From acbc1552ebc46ac884d19320cf5fa523eece5fc4 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Tue, 1 Oct 2024 11:39:26 +0200 Subject: [PATCH] refactor pop reframer --- .../audio_stream_pop_reframer.hpp | 95 +++++++++++++++++++ src/tox_av_voip_model.cpp | 82 +--------------- 2 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 src/frame_streams/audio_stream_pop_reframer.hpp diff --git a/src/frame_streams/audio_stream_pop_reframer.hpp b/src/frame_streams/audio_stream_pop_reframer.hpp new file mode 100644 index 00000000..a1734f78 --- /dev/null +++ b/src/frame_streams/audio_stream_pop_reframer.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "./audio_stream2.hpp" + +// reframes audio frames to a specified size in ms +// TODO: use absolute sample count instead?? +template +struct AudioStreamPopReFramer : public FrameStream2I { + uint32_t _frame_length_ms {20}; + + // gotta be careful of the multithreaded nature + // and false(true) sharing + uint64_t _pad0{}; + RealAudioStream _stream; + uint64_t _pad1{}; + + // dequeue? + std::vector _buffer; + + uint32_t _sample_rate {48'000}; + size_t _channels {0}; + + AudioStreamPopReFramer(uint32_t frame_length_ms = 20) + : _frame_length_ms(frame_length_ms) { + } + + AudioStreamPopReFramer(uint32_t frame_length_ms, FrameStream2I&& stream) + : _frame_length_ms(frame_length_ms), _stream(std::move(stream)) { + } + + ~AudioStreamPopReFramer(void) {} + + int32_t size(void) override { return -1; } + + std::optional pop(void) override { + auto new_in = _stream.pop(); + if (new_in.has_value()) { + auto& new_value = new_in.value(); + + // changed + if (_sample_rate != new_value.sample_rate || _channels != new_value.channels) { + if (_channels != 0) { + //std::cerr << "ReFramer warning: reconfiguring, dropping buffer\n"; + } + _sample_rate = new_value.sample_rate; + _channels = new_value.channels; + + // buffer does not exist or config changed and we discard + _buffer = {}; + } + + + //std::cout << "new incoming frame is " << new_value.getSpan().size/new_value.channels*1000/new_value.sample_rate << "ms\n"; + + auto new_span = new_value.getSpan(); + + if (_buffer.empty()) { + _buffer = {new_span.cbegin(), new_span.cend()}; + } else { + _buffer.insert(_buffer.cend(), new_span.cbegin(), new_span.cend()); + } + } else if (_buffer.empty()) { + // first pop might result in invalid state + return std::nullopt; + } + + const size_t desired_size {_frame_length_ms * _sample_rate * _channels / 1000}; + + // > threshold? + if (_buffer.size() < desired_size) { + return std::nullopt; + } + + // copy data + std::vector return_buffer(_buffer.cbegin(), _buffer.cbegin()+desired_size); + + // now crop buffer (meh) + // move data from back to front + _buffer.erase(_buffer.cbegin(), _buffer.cbegin() + desired_size); + + return AudioFrame2{ + _sample_rate, + _channels, + std::move(return_buffer), + }; + } + + bool push(const AudioFrame2& value) override { + // might be worth it to instead do the work on push + //assert(false && "push reframing not implemented"); + // passthrough + return _stream.push(value); + } +}; + diff --git a/src/tox_av_voip_model.cpp b/src/tox_av_voip_model.cpp index f25f4ec3..2a65e904 100644 --- a/src/tox_av_voip_model.cpp +++ b/src/tox_av_voip_model.cpp @@ -7,6 +7,7 @@ #include "./frame_streams/audio_stream2.hpp" #include "./frame_streams/locked_frame_stream.hpp" #include "./frame_streams/multi_source.hpp" +#include "./frame_streams/audio_stream_pop_reframer.hpp" #include @@ -28,73 +29,6 @@ namespace Components { // vid } // Components -// TODO: make proper adapter -struct AudioStreamReFramer { - FrameStream2I* _stream {nullptr}; - uint32_t frame_length_ms {20}; - - // dequeue? - std::vector buffer; - - uint32_t sample_rate {48'000}; - size_t channels {0}; - - std::optional pop(void) { - assert(_stream != nullptr); - - auto new_in = _stream->pop(); - if (new_in.has_value()) { - auto& new_value = new_in.value(); - - // changed - if (sample_rate != new_value.sample_rate || channels != new_value.channels) { - if (channels != 0) { - std::cerr << "ReFramer warning: reconfiguring, dropping buffer\n"; - } - sample_rate = new_value.sample_rate; - channels = new_value.channels; - - // buffer does not exist or config changed and we discard - buffer = {}; - } - - - //std::cout << "new incoming frame is " << new_value.getSpan().size/new_value.channels*1000/new_value.sample_rate << "ms\n"; - - auto new_span = new_value.getSpan(); - - if (buffer.empty()) { - buffer = {new_span.cbegin(), new_span.cend()}; - } else { - buffer.insert(buffer.cend(), new_span.cbegin(), new_span.cend()); - } - } else if (buffer.empty()) { - // first pop might result in invalid state - return std::nullopt; - } - - const size_t desired_size {frame_length_ms * sample_rate * channels / 1000}; - - // > threshold? - if (buffer.size() < desired_size) { - return std::nullopt; - } - - // copy data - std::vector return_buffer(buffer.cbegin(), buffer.cbegin()+desired_size); - - // now crop buffer (meh) - // move data from back to front - buffer.erase(buffer.cbegin(), buffer.cbegin() + desired_size); - - return AudioFrame2{ - sample_rate, - channels, - std::move(return_buffer), - }; - } -}; - struct ToxAVCallAudioSink : public FrameStream2SinkI { ToxAVI& _toxav; @@ -102,7 +36,7 @@ struct ToxAVCallAudioSink : public FrameStream2SinkI { uint32_t _audio_bitrate {32}; uint32_t _fid; - std::shared_ptr> _writer; + std::shared_ptr>> _writer; ToxAVCallAudioSink(ToxAVI& toxav, uint32_t fid) : _toxav(toxav), _fid(fid) {} ~ToxAVCallAudioSink(void) { @@ -124,7 +58,7 @@ struct ToxAVCallAudioSink : public FrameStream2SinkI { return nullptr; } - _writer = std::make_shared>(); + _writer = std::make_shared>>(); return _writer; } @@ -183,7 +117,6 @@ void ToxAVVoIPModel::addAudioSink(ObjectHandle session, uint32_t friend_number) auto new_asink = std::make_unique(_av, friend_number); outgoing_audio.emplace(new_asink.get()); - outgoing_audio.emplace(); outgoing_audio.emplace>(std::move(new_asink)); outgoing_audio.emplace(Components::StreamSink::create("ToxAV Friend Call Outgoing Audio")); @@ -270,17 +203,13 @@ ToxAVVoIPModel::~ToxAVVoIPModel(void) { } void ToxAVVoIPModel::tick(void) { - for (const auto& [oc, asink, asrf] : _os.registry().view().each()) { - //for (const auto& [oc, asink] : _os.registry().view().each()) { + for (const auto& [oc, asink] : _os.registry().view().each()) { if (!asink->_writer) { continue; } - asrf._stream = asink->_writer.get(); - for (size_t i = 0; i < 100; i++) { - //auto new_frame_opt = asink->_writer->pop(); - auto new_frame_opt = asrf.pop(); + auto new_frame_opt = asink->_writer->pop(); if (!new_frame_opt.has_value()) { break; } @@ -316,7 +245,6 @@ ObjectHandle ToxAVVoIPModel::enter(const Contact3 c, const Components::VoIP::Def const auto friend_number = _cr.get(c).friend_number; - std::cerr << "TAVVOIP: lol\n"; const auto err = _av.toxavCall(friend_number, 0, 0); if (err != TOXAV_ERR_CALL_OK) { std::cerr << "TAVVOIP error: failed to start call: " << err << "\n";