From 2081459f5f680777cd99c51cb8d4e84224fbb74a Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Thu, 15 Aug 2013 17:40:57 +0200 Subject: [PATCH] #155 Fixed problem where SFML stops calling SoundStream::OnGetData when too few samples are returned. This problem seems to have started after the change to static linking against SFML. The current solution is to collect the samples of more frames (3) before returning sample data. This unfortunately adds a 2 frame delay on system audio, but solves the choppyness. --- modules/oal/consumer/oal_consumer.cpp | 88 +++++++++++++++++++-------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/modules/oal/consumer/oal_consumer.cpp b/modules/oal/consumer/oal_consumer.cpp index e91dd68a3..528176055 100644 --- a/modules/oal/consumer/oal_consumer.cpp +++ b/modules/oal/consumer/oal_consumer.cpp @@ -21,6 +21,8 @@ #include "oal_consumer.h" +#include + #include #include #include @@ -37,7 +39,6 @@ #include -#include #include #include #include @@ -52,20 +53,20 @@ typedef std::vector> audio_buffer struct oal_consumer : public core::frame_consumer, public sf::SoundStream { safe_ptr graph_; - boost::timer perf_timer_; + boost::timer tick_timer_; int channel_index_; - tbb::concurrent_bounded_queue> input_; - boost::circular_buffer container_; + tbb::concurrent_bounded_queue>> input_; + std::shared_ptr> chunk_builder_; + audio_buffer_16 container_; tbb::atomic is_running_; - core::audio_buffer temp; core::video_format_desc format_desc_; core::channel_layout channel_layout_; + size_t frames_to_buffer_; public: oal_consumer() - : container_(16) - , channel_index_(-1) + : channel_index_(-1) , channel_layout_( core::default_channel_layout_repository().get_by_name( L"STEREO")) @@ -82,11 +83,11 @@ public: ~oal_consumer() { is_running_ = false; - input_.try_push(std::make_shared()); - input_.try_push(std::make_shared()); + input_.try_push(std::make_shared>()); + input_.try_push(std::make_shared>()); Stop(); - input_.try_push(std::make_shared()); - input_.try_push(std::make_shared()); + input_.try_push(std::make_shared>()); + input_.try_push(std::make_shared>()); CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; } @@ -101,8 +102,19 @@ public: if(Status() != Playing) { - sf::SoundStream::Initialize(2, 48000); - Play(); + sf::SoundStream::Initialize(2, format_desc.audio_sample_rate); + + // Each time OnGetData is called it seems to no longer be enough + // with the samples of one frame (since the change to statically + // linked SFML 1.6), so the samples of a few frames is needed to be + // collected. + static const double SAMPLES_NEEDED_BY_SFML_MULTIPLE = 0.1; + int min_num_samples_in_chunk = static_cast(format_desc.audio_sample_rate * SAMPLES_NEEDED_BY_SFML_MULTIPLE); + int min_num_samples_in_frame = *std::min_element(format_desc.audio_cadence.begin(), format_desc.audio_cadence.end()); + int min_frames_to_buffer = min_num_samples_in_chunk / min_num_samples_in_frame + (min_num_samples_in_chunk % min_num_samples_in_frame ? 1 : 0); + frames_to_buffer_ = min_frames_to_buffer; + + Play(); } CASPAR_LOG(info) << print() << " Sucessfully Initialized."; } @@ -114,7 +126,7 @@ public: virtual boost::unique_future send(const safe_ptr& frame) override { - std::shared_ptr buffer; + audio_buffer_16 buffer; if (core::needs_rearranging( frame->multichannel_view(), @@ -135,18 +147,35 @@ public: dest_view, core::default_mix_config_repository()); - buffer = std::make_shared( - core::audio_32_to_16(downmixed)); + buffer = core::audio_32_to_16(downmixed); } else { - buffer = std::make_shared( - core::audio_32_to_16(frame->audio_data())); + buffer = core::audio_32_to_16(frame->audio_data()); } - if (!input_.try_push(buffer)) - graph_->set_tag("dropped-frame"); + if (!chunk_builder_) + { + chunk_builder_.reset(new std::vector); + chunk_builder_->push_back(std::move(buffer)); + } + else + { + chunk_builder_->push_back(std::move(buffer)); + } + if (chunk_builder_->size() == frames_to_buffer_) + { + if (!input_.try_push(chunk_builder_)) + { + graph_->set_tag("dropped-frame"); + chunk_builder_->pop_back(); + } + else + { + chunk_builder_.reset(); + } + } return wrap_as_future(is_running_.load()); } @@ -177,7 +206,7 @@ public: virtual bool OnGetData(sf::SoundStream::Chunk& data) override { - std::shared_ptr audio_data; + std::shared_ptr> audio_data; if (!input_.try_pop(audio_data)) { @@ -185,12 +214,19 @@ public: input_.pop(audio_data); // Block until available } - container_.push_back(std::move(*audio_data)); - data.Samples = container_.back().data(); - data.NbSamples = container_.back().size(); + container_.clear(); + + // Concatenate to one large buffer. + BOOST_FOREACH(auto& buffer, *audio_data) + { + std::copy(buffer.begin(), buffer.end(), std::back_inserter(container_)); + } + + data.Samples = container_.data(); + data.NbSamples = container_.size(); - graph_->set_value("tick-time", perf_timer_.elapsed()*format_desc_.fps*0.5); - perf_timer_.restart(); + graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5 / frames_to_buffer_); + tick_timer_.restart(); return is_running_; } -- 2.39.2