Использование собственного планировщика для времени аудиопотока

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

Я думаю об использовании HistoricalScheduler для сроков такой деятельности. Насколько я понимаю, он выполняет все запланированные действия в том же потоке, который вызвал AdvanceBy/To, Кроме того, все приложение находится под нашим контролем, в том смысле, что нет сторонних компонентов - по крайней мере, таких, которые будут использовать RX.

Вопрос 1: Правильно ли это, хорошо или невероятно глупо? Я понимаю RX в уме, не имею опыта с ним, интуитивное чувство, если хотите.

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

IDisposable _sub;

// The historic scheduler that reflects the time of 
// the last sample in the endless buffer.
HistoricalScheduler _hisch = new HistoricalScheduler();

// This must be disposed of.
EventLoopScheduler _eventLoopSch = new EventLoopScheduler();

public IScheduler StreamTimeScheduler => _hisch;

// Subscribing to the stream.
void Initialize() {
  _sub = Observable.FromEventPattern<TEventHandler, TEventArgs>(
                     h => ReceivedAudio += h,
                     h => ReceivedAudio -= h)
                   .ObserveOn(_eventLoopSch)
                   .Subscribe(b => Append(b));
}

// The function that puts samples into the endless buffer. 
void Append(byte[] sample) {
  // ...put the sample into the array...
  _hisch.AdvanceBy(TimeSpan.FromSeconds(sample.Length / _avgBytesPerSecond));
}

Вопрос 2: Я чувствую странное продвижение планировщика из функции наблюдения, как в примере выше. Является ли это приемлемой практикой, или она сразу пахнет рыбой (или, может быть, это нечто среднее между двумя крайностями)?

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

Вопрос 3: Каковы, если таковые имеются, последствия остановки времени в планировщике, так что некоторые запланированные действия никогда не будут выполняться и останутся в очереди навсегда? Будет ли просто удаление ссылки на планировщик причиной утечки одноразового ресурса?

А также время потока отличается от времени настенных часов.

Вопрос 4: Что, если таковые имеются, последствия различных планировщиков, обеспечивающих непоследовательное понятие Now?

Мое лучшее предположение здесь "вообще нет", так как HistoricScheduler в других сценариях мирно сосуществуют с планировщиками реального времени, но я не уверен, что достаточно хорошо понимаю эту часть RX, чтобы не задавать этот вопрос.

0 ответов

Другие вопросы по тегам