Ring Daemon
Loading...
Searching...
No Matches
audio_receive_thread.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
19#include "libav_deps.h"
20#include "logger.h"
21#include "manager.h"
22#include "media_decoder.h"
23#include "media_io_handle.h"
24#include "ringbufferpool.h"
25
26#include <memory>
27
28namespace jami {
29
30AudioReceiveThread::AudioReceiveThread(const std::string& streamId,
31 const AudioFormat& format,
32 const std::string& sdp,
33 const uint16_t mtu)
34 : streamId_(streamId)
35 , format_(format)
36 , stream_(sdp)
37 , sdpContext_(new MediaIOHandle(sdp.size(), false, &readFunction, 0, 0, this))
38 , mtu_(mtu)
39 , loop_(std::bind(&AudioReceiveThread::setup, this),
40 std::bind(&AudioReceiveThread::process, this),
41 std::bind(&AudioReceiveThread::cleanup, this))
42{}
43
48
49bool
50AudioReceiveThread::setup()
51{
52 std::lock_guard lk(mutex_);
53 audioDecoder_.reset(new MediaDecoder([this](std::shared_ptr<MediaFrame>&& frame) mutable {
55 ringbuffer_->put(std::static_pointer_cast<AudioFrame>(frame));
56 }));
57 audioDecoder_->setContextCallback([this]() {
58 if (recorderCallback_)
59 recorderCallback_(getInfo());
60 });
61 audioDecoder_->setInterruptCallback(interruptCb, this);
62
63 // custom_io so the SDP demuxer will not open any UDP connections
64 args_.input = SDP_FILENAME;
65 args_.format = "sdp";
66 args_.sdp_flags = "custom_io";
67
68 if (stream_.str().empty()) {
69 JAMI_ERR("No SDP loaded");
70 return false;
71 }
72
73 audioDecoder_->setIOContext(sdpContext_.get());
74 audioDecoder_->setFEC(true);
75 if (audioDecoder_->openInput(args_)) {
76 JAMI_ERR("Unable to open input \"%s\"", SDP_FILENAME);
77 return false;
78 }
79
80 // Now replace our custom AVIOContext with one that will read packets
81 audioDecoder_->setIOContext(demuxContext_.get());
82 if (audioDecoder_->setupAudio()) {
83 JAMI_ERR("decoder IO startup failed");
84 return false;
85 }
86
87 ringbuffer_ = Manager::instance().getRingBufferPool().createRingBuffer(streamId_);
88
89 if (onSuccessfulSetup_)
90 onSuccessfulSetup_(MEDIA_AUDIO, 1);
91
92 return true;
93}
94
95void
96AudioReceiveThread::process()
97{
98 audioDecoder_->decode();
99}
100
101void
102AudioReceiveThread::cleanup()
103{
104 std::lock_guard lk(mutex_);
105 audioDecoder_.reset();
106 demuxContext_.reset();
107}
108
109int
110AudioReceiveThread::readFunction(void* opaque, uint8_t* buf, int buf_size)
111{
112 std::istream& is = static_cast<AudioReceiveThread*>(opaque)->stream_;
113 is.read(reinterpret_cast<char*>(buf), buf_size);
114
115 auto count = is.gcount();
116 return count ? static_cast<int>(count) : AVERROR_EOF;
117}
118
119// This callback is used by libav internally to break out of blocking calls
120int
121AudioReceiveThread::interruptCb(void* data)
122{
123 auto* context = static_cast<AudioReceiveThread*>(data);
124 return not context->loop_.isRunning();
125}
126
127void
129{
130 demuxContext_.reset(socketPair.createIOContext(mtu_));
131}
132
133void
134AudioReceiveThread::setRecorderCallback(const std::function<void(const MediaStream& ms)>& cb)
135{
136 recorderCallback_ = cb;
137 if (audioDecoder_)
138 audioDecoder_->setContextCallback([this]() {
139 if (recorderCallback_)
140 recorderCallback_(getInfo());
141 });
142}
143
146{
147 if (!audioDecoder_)
148 return {};
149 return audioDecoder_->getStream("a:remote");
150}
151
152void
157
158void
160{
161 loop_.stop();
162}
163
164}; // namespace jami
void addIOContext(SocketPair &socketPair)
AudioReceiveThread(const std::string &streamId, const AudioFormat &format, const std::string &sdp, const uint16_t mtu)
void setRecorderCallback(const std::function< void(const MediaStream &ms)> &cb)
static LIBJAMI_TEST_EXPORT Manager & instance()
Definition manager.cpp:694
RingBufferPool & getRingBufferPool()
Return a pointer to the instance of the RingBufferPool.
Definition manager.cpp:3197
void notify(std::shared_ptr< MediaFrame > data)
Definition observer.h:117
std::shared_ptr< RingBuffer > createRingBuffer(const std::string &id)
Create a new ringbuffer with a default readoffset.
virtual void stop()
#define JAMI_ERR(...)
Definition logger.h:230
void emitSignal(Args... args)
Definition jami_signal.h:64
@ MEDIA_AUDIO
Definition media_codec.h:46
Structure to hold sample rate and channel number associated with audio data.
std::string format
std::string input
std::string sdp_flags