source-mirror: Fix out-of-order playback of audio

On highly parallel systems (> 4 Threads) audio had a chance of being played back out of order, causing it to jitter. This queue should help eliminate the issue entirely.

Fixes #111
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-03-20 23:59:42 +01:00
parent 8f4313d8e8
commit d6c903a3bd
2 changed files with 21 additions and 12 deletions

View file

@ -55,18 +55,18 @@ source::mirror::mirror_audio_data::mirror_audio_data(const audio_data* audio, sp
// Build a clone of a packet. // Build a clone of a packet.
audio_t* oad = obs_get_audio(); audio_t* oad = obs_get_audio();
const audio_output_info* aoi = audio_output_get_info(oad); const audio_output_info* aoi = audio_output_get_info(oad);
osa.frames = audio->frames; osa.frames = audio->frames;
osa.timestamp = audio->timestamp; osa.timestamp = audio->timestamp;
osa.speakers = layout; osa.speakers = layout;
osa.format = aoi->format; osa.format = aoi->format;
osa.samples_per_sec = aoi->samples_per_sec; osa.samples_per_sec = aoi->samples_per_sec;
data.resize(MAX_AV_PLANES); data.resize(MAX_AV_PLANES);
for (size_t idx = 0; idx < MAX_AV_PLANES; idx++) { for (size_t idx = 0; idx < MAX_AV_PLANES; idx++) {
if (!audio->data[idx]) { if (!audio->data[idx]) {
osa.data[idx] = nullptr; osa.data[idx] = nullptr;
continue; continue;
} }
data[idx].resize(audio->frames * get_audio_bytes_per_channel(osa.format)); data[idx].resize(audio->frames * get_audio_bytes_per_channel(osa.format));
memcpy(data[idx].data(), audio->data[idx], data[idx].size()); memcpy(data[idx].data(), audio->data[idx], data[idx].size());
osa.data[idx] = data[idx].data(); osa.data[idx] = data[idx].data();
@ -249,16 +249,23 @@ void source::mirror::mirror_instance::on_audio(std::shared_ptr<obs_source_t>, co
} }
} }
{
std::unique_lock<std::mutex> ul(_audio_queue_lock);
_audio_queue.emplace(audio, detected_layout);
}
// Create a clone of the audio data and push it to the thread pool. // Create a clone of the audio data and push it to the thread pool.
get_global_threadpool()->push( get_global_threadpool()->push(
std::bind(&source::mirror::mirror_instance::audio_output, this, std::placeholders::_1), std::bind(&source::mirror::mirror_instance::audio_output, this, std::placeholders::_1), nullptr);
std::make_shared<mirror_audio_data>(audio, detected_layout));
} }
void source::mirror::mirror_instance::audio_output(std::shared_ptr<void> data) void source::mirror::mirror_instance::audio_output(std::shared_ptr<void> data)
{ {
std::shared_ptr<mirror_audio_data> mad = std::static_pointer_cast<mirror_audio_data>(data); std::unique_lock<std::mutex> ul(_audio_queue_lock);
obs_source_output_audio(_self, &mad->osa); while (_audio_queue.size() > 0) {
obs_source_output_audio(_self, &((_audio_queue.front()).osa));
_audio_queue.pop();
}
} }
std::shared_ptr<mirror::mirror_factory> mirror::mirror_factory::factory_instance; std::shared_ptr<mirror::mirror_factory> mirror::mirror_factory::factory_instance;

View file

@ -59,8 +59,10 @@ namespace source::mirror {
std::shared_ptr<obs::audio_signal_handler> _signal_audio; std::shared_ptr<obs::audio_signal_handler> _signal_audio;
// Audio // Audio
bool _audio_enabled; bool _audio_enabled;
speaker_layout _audio_layout; speaker_layout _audio_layout;
std::mutex _audio_queue_lock;
std::queue<mirror_audio_data> _audio_queue;
public: public:
mirror_instance(obs_data_t* settings, obs_source_t* self); mirror_instance(obs_data_t* settings, obs_source_t* self);