Распределенная синхронизация времени и веб-приложения

Основная причина этого оказалась: вы использовали функцию decode() таким образом, для которого она не была специально разработана. Даже если кажется, что decode() позволит вам декодировать любую часть потока .mp3 способом произвольного доступа, на практике первые несколько мс возвращенного аудио всегда всегда молчат , независимо от того, начинаете ли вы в начале песни или в середине. Это молчание вызывало «пробелы». По-видимому, функция decode() была больше предназначена для повторного запуска воспроизведения в случайном месте, например, из-за пользовательского «поиска».

decode() ведет себя таким образом, потому что для декодирования N-го блока сжатых данных декодеру требуется как блок N-1 , так и блок N. Декомпрессированные данные, которые соответствуют блоку N, будут хорошо, но данные для блока N-1 будут иметь этот звук "постепенного появления". Это общая особенность декодеров .mp3, и я знаю, что это происходит и с AAC. Между тем, декодирование блоков N + 1, N + 2, N + 3 и т. Д. Не представляет проблем, поскольку в каждом случае декодер уже имеет предыдущий блок.

Одним из решений является изменение функции decode():

private Decoder decoder;
private float totalMs;
private Bitstream bitstream;
private InputStream inputStream;

//call this once, when it is time to start a new song:
private void startNewSong(String path) throws IOException
{
    decoder = new Decoder();
    totalMs = 0;
    File file = new File(path);
    inputStream = new BufferedInputStream(new FileInputStream(file), 8 * 1024);
    bitstream = new Bitstream(inputStream);
}

private byte[] decode(String path, int startMs, int maxMs)
        throws IOException {
    ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);


    try {
        boolean done = false;
        while (! done) {
            Header frameHeader = bitstream.readFrame();
            if (frameHeader == null) {
                done = true;
                inputStream.close();   //Note this change. Now, the song is done. You can also clean up the decoder here.
            } else {
                totalMs += frameHeader.ms_per_frame();

                SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);

                if (output.getSampleFrequency() != 44100
                        || output.getChannelCount() != 2) {
                    Log.w("ERROR", "mono or non-44100 MP3 not supported");
                }

                short[] pcm = output.getBuffer();
                for (short s : pcm) {
                    outStream.write(s & 0xff);
                    outStream.write((s >> 8) & 0xff);
                }

                if (totalMs >= (startMs + maxMs)) {
                    done = true;
                }
            }
            bitstream.closeFrame();
        }
    } catch (BitstreamException e) {
        throw new IOException("Bitstream error: " + e);
    } catch (DecoderException e) {
        Log.w("ERROR", "Decoder error", e);
    }
    return outStream.toByteArray();
}

Этот код немного грубоват. готов, и это может использовать некоторые улучшения. Но общий подход, вместо произвольного доступа, decode() использует FSM , чтобы каждый раз декодировать немного больше песни; прочитайте немного больше файла и отправьте еще несколько кусков в декодер. Поскольку состояние декодера (и bitstream) сохраняется между каждым вызовом decode(), нет необходимости искать блок N-1.

UDP и потоковая передача

Достоверность вашего подхода UDP зависит от многих вещей. Вы можете искать другие вопросы, которые касаются именно этого. UDP удобен для широковещательной рассылки на несколько устройств в данной подсети, но он не поможет вам гарантировать, что пакеты получены в порядке или вообще. Вы можете хотеть TCP вместо этого. Также подумайте, хотите ли вы передать закодированные блоки .mp3 (возвращенные bitstream.readFrame()) или блоки распакованного звука. Также подумайте о том, как вы будете справляться с задержкой в ​​сети, разрывом соединений и буферизацией. Здесь есть много сложных дизайнерских решений, и у каждого выбора есть свои плюсы и минусы. Удачи.

9
задан CMS 10 January 2009 в 20:29
поделиться

4 ответа

Это кажется мне как, необходимо слушать многоадресное событие с сервера во многих различных местах. Так как можно принять изменение 2-3 секунд, Вы могли просто поместить все свои клиенты в долговечные запросы стиля кометы и просто получить ответ от сервера? Звуки мне как клиенты не должны были бы иметь дело со временем во всем этом пути?

Вы могли использовать ajax, чтобы сделать это, таким образом, Вы ̈́'d избежать любых клиентских тупиков при ожидании новых данных.

Я могу пропускать что-то полностью здесь.

2
ответ дан 3 November 2019 в 05:39
поделиться

Позвольте мне подвести итог, удостовериться, что я понимаю вопрос.

У Вас есть приложение, которое имеет компонент клиента и сервера. Существует несколько серверов, которые могут каждый обслуживать много (сотни) клиентов. Серверы более или менее синхронизируются друг с другом; клиенты не. Вы хотите, чтобы большое количество клиентов выполнило то же событие приблизительно в то же время, независимо от которого сервер, оказывается, тот, с которым они соединились первоначально.

Предположение, что я описал ситуацию более или менее точно:

У Вас могли быть серверы, сохраняют определенное состояние для каждого клиента (такого как начальное время соединения - время сервера), и когда время события, которое должно будет произойти, будет известно, уведомьте клиент с сообщением, содержащим количество миллисекунд после начинающегося значения, которое должно протечь прежде, чем запустить событие?

Проиллюстрировать:

   client A connects to server S at time t0 = 0
   client B connects to server S at time t1 = 120
   server S decides an event needs to happen at time t3 = 500
   server S sends a message to A:
   S->A : {eventName, 500}
   server S sends a message to B:
   S->B : {eventName, 380}

Это не полагается на клиентское время вообще; только на способности клиента следить за ходом времени в течение некоторого довольно короткого периода (единственная сессия).

2
ответ дан 3 November 2019 в 05:39
поделиться

В синхронизации времени очень трудно разобраться и по-моему неправильный способ пойти об этом. Вам нужна система событий, которая может уведомить зарегистрированных наблюдателей каждый раз, когда событие диспетчеризируется (шаблон "наблюдатель"). Все наблюдатели будут уведомлены одновременно (или максимально близко к тому), устраняя необходимость синхронизации времени.

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

1
ответ дан 3 November 2019 в 05:39
поделиться

Если можно предположить, что часы являются разумной конюшней - который является, они установлены неправильно, но отсчитывающий на более или менее правильном уровне.

Имейте серверы, получают их смещение от единственного определенного источника (например, один из Ваших серверов, или сервера базы данных или чего-то).

Затем имейте каждый клиент, вычисляют, это смещается от, он - сервер (возможные сложности туда и обратно, если Вы хотите большую точность).

Хранилище, что, затем Вы объединенное смещение на каждом клиенте для инициирования события в нужное время.

(client-time-to-trigger-event) = (scheduled-time) + (client-to-server-difference) + (server-to-reference-difference)
1
ответ дан 3 November 2019 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: