Zvukovik & Nullpath
Привет, я тут немного поколдовала с адаптивным кодеком квантования – он сохраняет чёткость среднего диапазона, при этом снижая полосу пропускания. Интересно, как бы ты спроектировал распределённую систему для потоковой передачи этого звука в реальном времени, чтобы задержки были минимальными?
Чтобы задержка была минимальной, разбей поток на микрофрагменты, скажем, кадры по 10 миллисекунд. Запусти кодек на легковесном процессе, который берёт кадр, квантует его и отправляет в брокер ZeroMQ. На принимающей стороне один поток снимает данные из очереди, декодирует их и подгружает в аудио-буфер с низкой задержкой. Используй UDP для передачи, добавь номера последовательности и отбрасывай устаревшие пакеты. Держи сеть как можно ближе к границе; если нужна избыточность, пусть второй брокер дублирует поток, но активируй его только если потеря пакетов превышает 1%. Так ты получишь адаптивное качество и мгновенную доставку.
Звучит неплохо, но 10 миллисекундные кадры всё равно немного громоздки для аудио высокого разрешения; будет слышно артефакты, если кодек даст сбой. Подумай о 2–3 миллисекундных окнах и более надёжном буфере джиттера. UDP + zeroMQ тоже подойдет, но сам брокер может стать узким местом — попробуй использовать разделяемую память с кольцевым буфером, если узлы на одном хосте. И просто отбрасывать пакеты без уведомления испортит восприятие качества; лучше добавить простую коррекцию ошибок, чем просто отбрасывать кадр. Идея с дополнительным брокером умная, но убедись, что при переключении не будет сдвига по синхронизации.
Получил параметры. Переходим на кадры по 3 мс, оставляем буфер джиттера в 30 мс и используем общий буфер памяти, если узлы находятся на одном хосте. Применяем FEC Reed-Solomon для каждого блока, чтобы восстанавливать потерянные кадры, а не отбрасывать их. Для брокера переключения при выходе из строя, фиксируем последовательность и ставим монотонную метку времени для потока; когда резервный брокер берет на себя, синхронизируемся по этой метке, чтобы избежать расхождения. Это должно сделать артефакты незаметными и поддерживать низкую задержку.
Замечательная доработка – 3 миллисекунды уже лучше, но не забудь про look-ahead кодека. Если ты всё ещё используешь буфер в 30 миллисекунд, у тебя будет 9 миллисекунд времени на предварительную декодировку. Для большинства сетей этого достаточно, но любой скачок джиттера больше 5 миллисекунд запустит цепную реакцию. Да, и Reed–Solomon на каждом блоке в 3 миллисекунды добавляет накладные расходы; они ощутимы, если размер твоих пакетов всего несколько сотен байт. Подумай о группировке нескольких кадров в один блок FEC, чтобы сбалансировать задержку и надёжность. Захват метки времени при переключении работает хорошо, просто убедись, что счётчик монотонности – 64-битный, чтобы избежать переполнения при длительных сеансах. В целом, ты двигаешься в правильном направлении – просто следи за накладными расходами.
Понял. Объединяем кадры третьей группы в один FEC-пакет, используем 64-битный монотонный счетчик для синхронизации при переключении, и подтягиваем буфер джиттера до 5 миллисекунд. Так мы находим баланс между накладными расходами и задержкой.