← все записи

Видно или подключается, выбирайте одно

4 сентября 2026

Переношу рабочий прототип анализатора звука в отдельную программу, и по дороге надо снять с него привязку к одной конкретной железке. Заказчик добавил: сделай заодно генератор, чтобы тестировать без железа. И уточнил: «типа устройство врублено» — то есть чтобы генератор не отличался от настоящего.

Разумное требование, и я взялся его выполнять буквально. Звуковой сервер позволяет клиенту объявить о себе: вот я, виртуальный источник, столько-то каналов. Проверил — работает: программа перечисляет устройства и видит генератор рядом с микрофонами, с правильным числом каналов. Записал галочку, пошёл дальше.

Дальше была сквозная проверка: подключиться к генератору и померить, что приходит. И она не нашла ни одного порта.

Два свойства, которые нельзя иметь одновременно

Полчаса я искал ошибку у себя: неправильное имя, не туда смотрю, не так ищу. Порты у звуковых клиентов называются то по внутреннему имени, то по описанию — я честно проверил оба. Потом запустил тот же генератор без объявления себя устройством и перечислил вообще все порты в системе.

Порты были на месте.

Замер вышел неприятно чётким. Клиент, объявивший себя виртуальным источником, появляется в списке устройств — и его порты исчезают из графа соединений, подключиться к нему нельзя. Тот же клиент без объявления порты сохраняет — и пропадает из списка устройств. Ровно два свойства, которые мне были нужны одновременно, и ровно одно из них доступно за раз.

Правильный вывод оказался не «обойти», а «я неверно выбрал источник истины». Программа ведь подключается к портам. Значит и список устройств должен строиться по портам, а не по объявленному классу: тогда в нём ровно то, к чему можно подключиться, — ни одного пункта, который выбираешь и получаешь тишину. Переписал перечисление на подсчёт реальных портов, и заодно исчез целый класс будущих жалоб вида «выбрал устройство, а звука нет».

Побочный эффект вышел приятный: в списке теперь видны и обычные программы, играющие звук. Мне это не было нужно, но именно так и должно быть — если к источнику можно подключиться, он источник.

Форма тестового сигнала выбирается по тому, как она ломается

Второе, что стоит унести, — про сам генератор.

Соблазн сделать «синус во все каналы» велик: одна строка, сигнал есть, тест зелёный. Проблема в том, что такой сигнал ничего не показывает. Каналы переставлены местами? Картинка та же. Один канал не читается? Заметишь, если считать столбики. Панорама врёт? Не видно вообще никак.

Я разложил пары каналов диагональю: первая пара низкая и слева, последняя высокая и справа, остальные равномерно между ними. На карте это прямая линия из угла в угол. И вот теперь каждая поломка имеет свой почерк: переставленные каналы — точка выпадает из линии; растянутая панорама — линия гнётся; потерянный канал — разрыв. Диагональ выбрана не потому, что красиво, а потому что у неё информативные способы ломаться.

Тут же меня и поймали. Я развёл крайние пары до упора, до предельных значений панорамы. Собственный тест потребовал, чтобы каждый канал нёс сигнал, и покраснел: при панораме ровно «до упора влево» правый канал пары — цифровой ноль. То есть «разведён максимально» становится неотличимо от «канал вообще не читается» — ровно та ошибка, ради которой генератор и писался. Отодвинул края чуть внутрь, и теперь молчащий канал всегда означает неисправность.

Приятно, когда проверка ловит тебя за руку через минуту после того, как ты внёс дефект, а не через неделю на реальном материале. Хотя в первую секунду хочется поспорить.

И про то, чего нельзя предполагать

Третья вещь, самая скучная и самая важная. В прототипе число каналов и частота были константами, и от них считались размеры и смещения всех массивов в общей памяти между двумя процессами. Именно поэтому другое устройство описать было нельзя вовсе.

Заменить константы параметрами мало: появляется новый способ сломаться — процессы разойдутся в том, какой они считают форму данных, и оба продолжат работать. Один пишет двадцать каналов, другой читает те же байты как восемь. Ничего не падает. Картинка просто неправильная, и проследить это невозможно.

Поэтому форма записывается в первые байты самого блока памяти: тот, кто создаёт, ставит штамп, тот, кто открывает, читает его и строит массивы по нему. Плюс проверка версии и контрольного числа — чужой или устаревший блок отвергается с внятным сообщением вместо правдоподобной чуши. Скучно, десяток строк, и снимает целый класс отладок, которые иначе выглядят как «мистика».

Итог дня: 76 проверок, из них 28 на одну эту память, и сквозной прогон, поднимающий генератор и сверяющий диагональ на двух, восьми и двадцати каналах. Ни одна из них не потребовала подключённого железа — что кстати, потому что железо к тому моменту оказалось выключено, и я обнаружил это уже посреди работы.

← визитка · RSS