Skip to content
Snippets Groups Projects
Commit c0766a6e authored by Philippe Gorley's avatar Philippe Gorley Committed by Adrien Béraud
Browse files

audio: mix file with mic when streaming

Audio devices drives the file decoder. Frames are read when needed.

Change-Id: I965e8cac98f7be9a926910b063a0f182d8d71698
parent cbf74f49
No related branches found
No related tags found
No related merge requests found
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "manager.h" #include "manager.h"
#include "media_decoder.h" #include "media_decoder.h"
#include "resampler.h" #include "resampler.h"
#include "ringbuffer.h"
#include "ringbufferpool.h" #include "ringbufferpool.h"
#include "smartools.h" #include "smartools.h"
...@@ -44,6 +45,7 @@ AudioInput::AudioInput(const std::string& id) : ...@@ -44,6 +45,7 @@ AudioInput::AudioInput(const std::string& id) :
resampler_(new Resampler), resampler_(new Resampler),
resizer_(new AudioFrameResizer(format_, frameSize_, resizer_(new AudioFrameResizer(format_, frameSize_,
[this](std::shared_ptr<AudioFrame>&& f){ frameResized(std::move(f)); })), [this](std::shared_ptr<AudioFrame>&& f){ frameResized(std::move(f)); })),
fileId_(id + "_file"),
loop_([] { return true; }, loop_([] { return true; },
[this] { process(); }, [this] { process(); },
[] {}) [] {})
...@@ -60,7 +62,9 @@ AudioInput::~AudioInput() ...@@ -60,7 +62,9 @@ AudioInput::~AudioInput()
void void
AudioInput::process() AudioInput::process()
{ {
foundDevOpts(devOpts_); // NOTE This is only useful if the device params weren't yet found in switchInput
// For both files and audio devices, this is already done
//foundDevOpts(devOpts_);
if (switchPending_.exchange(false)) { if (switchPending_.exchange(false)) {
if (devOpts_.input.empty()) if (devOpts_.input.empty())
RING_DBG() << "Switching to default audio input"; RING_DBG() << "Switching to default audio input";
...@@ -68,18 +72,13 @@ AudioInput::process() ...@@ -68,18 +72,13 @@ AudioInput::process()
RING_DBG() << "Switching audio input to '" << devOpts_.input << "'"; RING_DBG() << "Switching audio input to '" << devOpts_.input << "'";
} }
// send frame to resizer, frameResized will be called when it can be output readFromDevice();
if (decodingFile_)
nextFromFile();
else
nextFromDevice();
} }
void void
AudioInput::frameResized(std::shared_ptr<AudioFrame>&& ptr) AudioInput::frameResized(std::shared_ptr<AudioFrame>&& ptr)
{ {
std::shared_ptr<AudioFrame> frame = std::move(ptr); std::shared_ptr<AudioFrame> frame = std::move(ptr);
auto ms = MediaStream("a:local", format_, sent_samples);
frame->pointer()->pts = sent_samples; frame->pointer()->pts = sent_samples;
sent_samples += frame->pointer()->nb_samples; sent_samples += frame->pointer()->nb_samples;
...@@ -87,14 +86,17 @@ AudioInput::frameResized(std::shared_ptr<AudioFrame>&& ptr) ...@@ -87,14 +86,17 @@ AudioInput::frameResized(std::shared_ptr<AudioFrame>&& ptr)
} }
void void
AudioInput::nextFromDevice() AudioInput::readFromDevice()
{ {
auto& mainBuffer = Manager::instance().getRingBufferPool(); auto& mainBuffer = Manager::instance().getRingBufferPool();
auto bufferFormat = mainBuffer.getInternalAudioFormat(); auto bufferFormat = mainBuffer.getInternalAudioFormat();
if (not mainBuffer.waitForDataAvailable(id_, MS_PER_PACKET)) { if (decodingFile_ )
while (fileBuf_->isEmpty())
readFromFile();
if (not mainBuffer.waitForDataAvailable(id_, MS_PER_PACKET))
return; return;
}
auto samples = mainBuffer.getData(id_); auto samples = mainBuffer.getData(id_);
if (not samples) if (not samples)
...@@ -104,14 +106,14 @@ AudioInput::nextFromDevice() ...@@ -104,14 +106,14 @@ AudioInput::nextFromDevice()
// micData_.reset(); // micData_.reset();
// TODO handle mute // TODO handle mute
{ std::lock_guard<std::mutex> lk(fmtMutex_);
std::lock_guard<std::mutex> lk(fmtMutex_); if (bufferFormat != format_)
resizer_->enqueue(resampler_->resample(std::move(samples), format_)); samples = resampler_->resample(std::move(samples), format_);
} resizer_->enqueue(std::move(samples));
} }
void void
AudioInput::nextFromFile() AudioInput::readFromFile()
{ {
if (!decoder_) if (!decoder_)
return; return;
...@@ -120,7 +122,6 @@ AudioInput::nextFromFile() ...@@ -120,7 +122,6 @@ AudioInput::nextFromFile()
const auto ret = decoder_->decode(*frame); const auto ret = decoder_->decode(*frame);
const auto inFmt = AudioFormat((unsigned)frame->pointer()->sample_rate, (unsigned)frame->pointer()->channels, (AVSampleFormat)frame->pointer()->format); const auto inFmt = AudioFormat((unsigned)frame->pointer()->sample_rate, (unsigned)frame->pointer()->channels, (AVSampleFormat)frame->pointer()->format);
std::lock_guard<std::mutex> lk(fmtMutex_);
switch(ret) { switch(ret) {
case MediaDecoder::Status::ReadError: case MediaDecoder::Status::ReadError:
case MediaDecoder::Status::DecodeError: case MediaDecoder::Status::DecodeError:
...@@ -131,7 +132,7 @@ AudioInput::nextFromFile() ...@@ -131,7 +132,7 @@ AudioInput::nextFromFile()
createDecoder(); createDecoder();
break; break;
case MediaDecoder::Status::FrameFinished: case MediaDecoder::Status::FrameFinished:
resizer_->enqueue(resampler_->resample(std::move(frame), format_)); fileBuf_->put(std::move(frame));
break; break;
case MediaDecoder::Status::Success: case MediaDecoder::Status::Success:
default: default:
...@@ -165,6 +166,8 @@ AudioInput::initFile(const std::string& path) ...@@ -165,6 +166,8 @@ AudioInput::initFile(const std::string& path)
RING_WARN() << "Cannot decode audio from file, switching back to default device"; RING_WARN() << "Cannot decode audio from file, switching back to default device";
return initDevice(""); return initDevice("");
} }
fileBuf_ = Manager::instance().getRingBufferPool().createRingBuffer(fileId_);
Manager::instance().getRingBufferPool().bindHalfDuplexOut(id_, fileId_);
decodingFile_ = true; decodingFile_ = true;
return true; return true;
} }
...@@ -172,8 +175,7 @@ AudioInput::initFile(const std::string& path) ...@@ -172,8 +175,7 @@ AudioInput::initFile(const std::string& path)
std::shared_future<DeviceParams> std::shared_future<DeviceParams>
AudioInput::switchInput(const std::string& resource) AudioInput::switchInput(const std::string& resource)
{ {
if (resource == currentResource_) // Always switch inputs, even if it's the same resource, so audio will be in sync with video
return futureDevOpts_;
if (switchPending_) { if (switchPending_) {
RING_ERR() << "Audio switch already requested"; RING_ERR() << "Audio switch already requested";
...@@ -184,6 +186,8 @@ AudioInput::switchInput(const std::string& resource) ...@@ -184,6 +186,8 @@ AudioInput::switchInput(const std::string& resource)
decoder_.reset(); decoder_.reset();
decodingFile_ = false; decodingFile_ = false;
Manager::instance().getRingBufferPool().unBindHalfDuplexOut(id_, fileId_);
fileBuf_.reset();
currentResource_ = resource; currentResource_ = resource;
devOptsFound_ = false; devOptsFound_ = false;
...@@ -241,9 +245,8 @@ AudioInput::createDecoder() ...@@ -241,9 +245,8 @@ AudioInput::createDecoder()
return false; return false;
} }
// NOTE createDecoder is currently only used for files, which require rate emulation // NOTE don't emulate rate, file is read as frames are needed
auto decoder = std::make_unique<MediaDecoder>(); auto decoder = std::make_unique<MediaDecoder>();
decoder->emulateRate();
decoder->setInterruptCallback( decoder->setInterruptCallback(
[](void* data) -> int { return not static_cast<AudioInput*>(data)->isCapturing(); }, [](void* data) -> int { return not static_cast<AudioInput*>(data)->isCapturing(); },
this); this);
......
...@@ -38,6 +38,7 @@ class MediaDecoder; ...@@ -38,6 +38,7 @@ class MediaDecoder;
class MediaRecorder; class MediaRecorder;
struct MediaStream; struct MediaStream;
class Resampler; class Resampler;
class RingBuffer;
class AudioInput : public Observable<std::shared_ptr<MediaFrame>> class AudioInput : public Observable<std::shared_ptr<MediaFrame>>
{ {
...@@ -53,8 +54,8 @@ public: ...@@ -53,8 +54,8 @@ public:
MediaStream getInfo() const; MediaStream getInfo() const;
private: private:
void nextFromDevice(); void readFromDevice();
void nextFromFile(); void readFromFile();
bool initDevice(const std::string& device); bool initDevice(const std::string& device);
bool initFile(const std::string& path); bool initFile(const std::string& path);
bool createDecoder(); bool createDecoder();
...@@ -70,9 +71,11 @@ private: ...@@ -70,9 +71,11 @@ private:
std::unique_ptr<Resampler> resampler_; std::unique_ptr<Resampler> resampler_;
std::unique_ptr<AudioFrameResizer> resizer_; std::unique_ptr<AudioFrameResizer> resizer_;
std::weak_ptr<MediaRecorder> recorder_;
std::unique_ptr<MediaDecoder> decoder_; std::unique_ptr<MediaDecoder> decoder_;
std::string fileId_;
std::shared_ptr<RingBuffer> fileBuf_;
std::string currentResource_; std::string currentResource_;
std::atomic_bool switchPending_ {false}; std::atomic_bool switchPending_ {false};
DeviceParams devOpts_; DeviceParams devOpts_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment