Ring Daemon 16.0.0
Loading...
Searching...
No Matches
audio_receive_thread.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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 "media_recorder.h"
25#include "ringbuffer.h"
26#include "ringbufferpool.h"
27
28#include <memory>
29
30namespace jami {
31
32AudioReceiveThread::AudioReceiveThread(const std::string& streamId,
33 const AudioFormat& format,
34 const std::string& sdp,
35 const uint16_t mtu)
36 : streamId_(streamId)
37 , format_(format)
38 , stream_(sdp)
39 , sdpContext_(new MediaIOHandle(sdp.size(), false, &readFunction, 0, 0, this))
40 , mtu_(mtu)
41 , loop_(std::bind(&AudioReceiveThread::setup, this),
42 std::bind(&AudioReceiveThread::process, this),
43 std::bind(&AudioReceiveThread::cleanup, this))
44{}
45
50
51bool
52AudioReceiveThread::setup()
53{
54 std::lock_guard lk(mutex_);
55 audioDecoder_.reset(new MediaDecoder([this](std::shared_ptr<MediaFrame>&& frame) mutable {
57 ringbuffer_->put(std::static_pointer_cast<AudioFrame>(frame));
58 }));
59 audioDecoder_->setContextCallback([this]() {
60 if (recorderCallback_)
61 recorderCallback_(getInfo());
62 });
63 audioDecoder_->setInterruptCallback(interruptCb, this);
64
65 // custom_io so the SDP demuxer will not open any UDP connections
66 args_.input = SDP_FILENAME;
67 args_.format = "sdp";
68 args_.sdp_flags = "custom_io";
69
70 if (stream_.str().empty()) {
71 JAMI_ERR("No SDP loaded");
72 return false;
73 }
74
75 audioDecoder_->setIOContext(sdpContext_.get());
76 audioDecoder_->setFEC(true);
77 if (audioDecoder_->openInput(args_)) {
78 JAMI_ERR("Unable to open input \"%s\"", SDP_FILENAME);
79 return false;
80 }
81
82 // Now replace our custom AVIOContext with one that will read packets
83 audioDecoder_->setIOContext(demuxContext_.get());
84 if (audioDecoder_->setupAudio()) {
85 JAMI_ERR("decoder IO startup failed");
86 return false;
87 }
88
89 ringbuffer_ = Manager::instance().getRingBufferPool().createRingBuffer(streamId_);
90
91 if (onSuccessfulSetup_)
92 onSuccessfulSetup_(MEDIA_AUDIO, 1);
93
94 return true;
95}
96
97void
98AudioReceiveThread::process()
99{
100 audioDecoder_->decode();
101}
102
103void
104AudioReceiveThread::cleanup()
105{
106 std::lock_guard lk(mutex_);
107 audioDecoder_.reset();
108 demuxContext_.reset();
109}
110
111int
112AudioReceiveThread::readFunction(void* opaque, uint8_t* buf, int buf_size)
113{
114 std::istream& is = static_cast<AudioReceiveThread*>(opaque)->stream_;
115 is.read(reinterpret_cast<char*>(buf), buf_size);
116
117 auto count = is.gcount();
118 return count ? count : AVERROR_EOF;
119}
120
121// This callback is used by libav internally to break out of blocking calls
122int
123AudioReceiveThread::interruptCb(void* data)
124{
125 auto context = static_cast<AudioReceiveThread*>(data);
126 return not context->loop_.isRunning();
127}
128
129void
131{
132 demuxContext_.reset(socketPair.createIOContext(mtu_));
133}
134
135void
137 const std::function<void(const MediaStream& ms)>& cb)
138{
139 recorderCallback_ = cb;
140 if (audioDecoder_)
141 audioDecoder_->setContextCallback([this]() {
142 if (recorderCallback_)
143 recorderCallback_(getInfo());
144 });
145}
146
149{
150 if (!audioDecoder_)
151 return {};
152 return audioDecoder_->getStream("a:remote");
153}
154
155void
160
161void
163{
164 loop_.stop();
165}
166
167}; // 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:676
RingBufferPool & getRingBufferPool()
Return a pointer to the instance of the RingBufferPool.
Definition manager.cpp:3157
void notify(std::shared_ptr< MediaFrame > data)
Definition observer.h:118
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:218
void emitSignal(Args... args)
Definition ring_signal.h:64
@ MEDIA_AUDIO
Definition media_codec.h:47
Structure to hold sample rate and channel number associated with audio data.
std::string format
std::string input
std::string sdp_flags