#include #include #include #include namespace psemek::audio { namespace { struct channel_impl final : mixer::channel { stream_ptr stream; void stop() override; bool is_stopped() const override; }; void channel_impl::stop() { std::atomic_store(&stream, stream_ptr()); } bool channel_impl::is_stopped() const { return std::atomic_load(&stream) != nullptr; } struct mixer_impl final : mixer , std::enable_shared_from_this { channel_ptr add(stream_ptr stream) override; std::size_t read(float * data, std::size_t sample_count) override; private: std::vector> channels_; std::vector> alive_channels_; std::vector buffer_; std::mutex new_channels_mutex_; std::vector> new_channels_; }; mixer::channel_ptr mixer_impl::add(stream_ptr stream) { auto result = std::make_shared(); result->stream = std::move(stream); { std::lock_guard lock{new_channels_mutex_}; new_channels_.push_back(result); } return result; } std::size_t mixer_impl::read(float * data, std::size_t sample_count) { { std::vector> new_channels; { std::lock_guard lock{new_channels_mutex_}; new_channels = std::move(new_channels_); } for (auto & ch : new_channels) channels_.push_back(std::move(ch)); } std::fill(data, data + sample_count, 0.f); buffer_.resize(sample_count); for (auto & ch : channels_) { auto stream = std::atomic_load(&(ch->stream)); if (!stream) continue; auto read = stream->read(buffer_.data(), sample_count); { auto begin = buffer_.data(); auto end = begin + read; auto dst = data; for (; begin < end; ) *dst++ += *begin++; } if (read < sample_count) { ch->stop(); continue; } alive_channels_.push_back(std::move(ch)); } std::swap(channels_, alive_channels_); alive_channels_.clear(); return sample_count; } } mixer_ptr make_mixer() { return std::make_shared(); } }