UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
state_audio_mixer Struct Referencefinal
Collaboration diagram for state_audio_mixer:
Collaboration graph

Public Member Functions

 state_audio_mixer (const char *cfg)
 
 state_audio_mixer (state_audio_mixer const &)=delete
 
 ~state_audio_mixer ()
 
state_audio_mixer & operator= (state_audio_mixer const &)=delete
 
void worker ()
 

Public Attributes

string audio_codec {"PCM"}
 
map< sockaddr_storage, am_participant, sockaddr_storage_less > participants
 
mutex participants_lock
 
struct socket_udp_local * recv_socket {}
 
bool should_exit = false
 

Private Attributes

unique_ptr< generic_mix_algo< sample_type_source, sample_type_mixed > > mixing_algorithm {new linear_mix_algo<sample_type_source, sample_type_mixed>()}
 
thread thread_id
 

Detailed Description

Definition at line 227 of file mixer.cpp.

Constructor & Destructor Documentation

◆ state_audio_mixer() [1/2]

state_audio_mixer::state_audio_mixer ( const char * cfg)
inline

Definition at line 228 of file mixer.cpp.

228 {
229 if (cfg) {
230 shared_ptr<char> tmp(strdup(cfg), free);
231 char *item, *save_ptr;
232 char *copy = tmp.get();
233
234 while ((item = strtok_r(copy, ":", &save_ptr))) {
235 if (strncmp(item, "codec=", strlen("codec=")) == 0) {
236 audio_codec = item + strlen("codec=");
237 } else if (strncmp(item, "algo=", strlen("algo=")) == 0) {
238 string algo = item + strlen("algo=");
239 if (algo == "linear") {
241 } else if (algo == "logarithmic") {
243 } else {
244 LOG(LOG_LEVEL_ERROR) << "Unknown mixing algorithm: " << algo << "\n";
245 throw 1;
246 }
247 } else {
248 LOG(LOG_LEVEL_ERROR) << "Unknown option: " << item << "\n";
249 throw 1;
250 }
251 copy = nullptr;
252 }
253 }
254
255 struct audio_codec_state *audio_coder =
257 if (!audio_coder) {
258 LOG(LOG_LEVEL_ERROR) << "Audio coder init failed!\n";
259 throw 1;
260 } else {
261 audio_codec_done(audio_coder);
262 }
263
264 thread_id = thread(&state_audio_mixer::worker, this);
265 }
struct audio_codec_state * audio_codec_init_cfg(const char *audio_codec_cfg, audio_codec_direction_t direction)
Definition codec.cpp:165
void audio_codec_done(struct audio_codec_state *s)
Definition codec.cpp:372
@ AUDIO_CODER
Definition codec.h:46
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG(level)
Definition debug.h:313
Definition hd-rum.c:27
unique_ptr< generic_mix_algo< sample_type_source, sample_type_mixed > > mixing_algorithm
Definition mixer.cpp:281
string audio_codec
Definition mixer.cpp:278

References audio_codec, audio_codec_done(), audio_codec_init_cfg(), AUDIO_CODER, LOG, LOG_LEVEL_ERROR, mixing_algorithm, thread_id, and worker().

Here is the call graph for this function:

◆ ~state_audio_mixer()

state_audio_mixer::~state_audio_mixer ( )
inline

Definition at line 266 of file mixer.cpp.

266 {
267 thread_id.join();
268 }

References thread_id.

◆ state_audio_mixer() [2/2]

state_audio_mixer::state_audio_mixer ( state_audio_mixer const & )
delete

Member Function Documentation

◆ operator=()

state_audio_mixer & state_audio_mixer::operator= ( state_audio_mixer const & )
delete

◆ worker()

void state_audio_mixer::worker ( )

Definition at line 284 of file mixer.cpp.

285{
286 set_thread_name(__func__);
287 chrono::steady_clock::time_point next_frame_time = chrono::steady_clock::now();
288
289 static_assert(SAMPLES_PER_FRAME * 1000ll % SAMPLE_RATE == 0, "Sample rate is not evenly divisible by number of samples in frame");
290 const chrono::milliseconds interval(SAMPLES_PER_FRAME*1000ll/SAMPLE_RATE);
291
292 while (!should_exit) {
293 this_thread::sleep_until(next_frame_time);
294 next_frame_time += interval;
295 auto now = chrono::steady_clock::now();
296
297 // check if we didn't overslept much
298 if (next_frame_time < now) {
299 LOG(LOG_LEVEL_WARNING) << "[Audio mixer] Next frame time in past! Setting to now.\n";
300 next_frame_time = now;
301 }
302
303 unique_lock<mutex> plk(participants_lock);
304 // check timeouts
305 for (auto it = participants.cbegin(); it != participants.cend(); )
306 {
307 if (duration_cast<seconds>(now - it->second.last_seen).count() > PARTICIPANT_TIMEOUT_S) {
308 it = participants.erase(it);
309 } else {
310 ++it;
311 }
312 }
313
314 size_t data_len_source = SAMPLES_PER_FRAME * sizeof(sample_type_source) * CHANNELS;
315 vector<sample_type_mixed> mixed(SAMPLES_PER_FRAME * CHANNELS);
316 vector<audio_frame2> participant_frames(participants.size());
317 int participant_index = 0;
318
319 // mix all together
320 for (auto & p : participants) {
321 participant_frames[participant_index].init(CHANNELS, AC_PCM, BPS, SAMPLE_RATE);
322 static_assert(CHANNELS == 1, "Currently only one channel is implemented here.");
323 participant_frames[participant_index].resize(0, data_len_source);
324 char *particip_data = participant_frames[participant_index].get_data(0);
325 int ret = audio_buffer_read(p.second.m_buffer, particip_data, data_len_source);
326 memset(particip_data, 0, data_len_source - ret);
327
328 sample_type_source *src = (sample_type_source *)(void *) particip_data;
329 auto dst = mixed.begin();
330 for (int i = 0; i < SAMPLES_PER_FRAME * CHANNELS; ++i) {
331 *dst = mixing_algorithm->add_to_mix(*dst, *src);
332 ++dst;
333 ++src;
334 }
335 participant_index++;
336 }
337
338 // substract each source signal from the mix coming to that participant
339 for (auto & pb : participant_frames) {
340 auto mix = mixed.begin();
341 sample_type_source *part = (sample_type_source *)(void *) pb.get_data(0);
342 for (int i = 0; i < SAMPLES_PER_FRAME * CHANNELS; ++i) {
343 *part = mixing_algorithm->normalize(mixing_algorithm->get_mixed_without_source_sample(*mix, *part));
344 ++mix;
345 ++part;
346 }
347 }
348
349 // send
350 participant_index = 0;
351 for (auto & p : participants) {
352 audio_frame2 *uncompressed = &participant_frames[participant_index];
353 while (audio_frame2 compressed = audio_codec_compress(p.second.m_audio_coder, uncompressed)) {
354 audio_tx_send(p.second.m_tx_session, p.second.m_network_device, &compressed);
355 uncompressed = nullptr;
356 }
357
358 participant_index++;
359 }
360 plk.unlock();
361 }
362}
@ AC_PCM
Definition types.h:53
int audio_buffer_read(struct audio_buffer *buf, char *out, int max_len)
audio_frame2 audio_codec_compress(struct audio_codec_state *s, const audio_frame2 *frame)
Definition codec.cpp:245
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
#define CHANNELS
Definition mixer.cpp:65
#define PARTICIPANT_TIMEOUT_S
Definition mixer.cpp:70
#define SAMPLE_RATE
Definition mixer.cpp:63
#define SAMPLES_PER_FRAME
Definition mixer.cpp:68
#define BPS
Definition mixer.cpp:64
int16_t sample_type_source
Definition mixer.cpp:71
mutex participants_lock
Definition mixer.cpp:275
map< sockaddr_storage, am_participant, sockaddr_storage_less > participants
Definition mixer.cpp:274
void set_thread_name(const char *name)
Definition thread.c:72
void audio_tx_send(struct tx *tx, struct rtp *rtp_session, const audio_frame2 *buffer)
Definition transmit.cpp:799

References AC_PCM, audio_buffer_read(), audio_codec_compress(), audio_tx_send(), BPS, CHANNELS, LOG, LOG_LEVEL_WARNING, mixing_algorithm, PARTICIPANT_TIMEOUT_S, participants, participants_lock, SAMPLE_RATE, SAMPLES_PER_FRAME, set_thread_name(), and should_exit.

Referenced by state_audio_mixer().

Here is the call graph for this function:

Member Data Documentation

◆ audio_codec

string state_audio_mixer::audio_codec {"PCM"}

Definition at line 278 of file mixer.cpp.

278{"PCM"};

Referenced by state_audio_mixer(), and audio_play_mixer_put_frame().

◆ mixing_algorithm

unique_ptr<generic_mix_algo<sample_type_source, sample_type_mixed> > state_audio_mixer::mixing_algorithm {new linear_mix_algo<sample_type_source, sample_type_mixed>()}
private

Definition at line 281 of file mixer.cpp.

Referenced by state_audio_mixer(), and worker().

◆ participants

map<sockaddr_storage, am_participant, sockaddr_storage_less> state_audio_mixer::participants

Definition at line 274 of file mixer.cpp.

Referenced by audio_play_mixer_put_frame(), and worker().

◆ participants_lock

mutex state_audio_mixer::participants_lock

Definition at line 275 of file mixer.cpp.

Referenced by audio_play_mixer_put_frame(), and worker().

◆ recv_socket

struct socket_udp_local* state_audio_mixer::recv_socket {}

Definition at line 277 of file mixer.cpp.

277{};

Referenced by audio_play_mixer_ctl(), and audio_play_mixer_put_frame().

◆ should_exit

bool state_audio_mixer::should_exit = false

Definition at line 269 of file mixer.cpp.

Referenced by audio_play_mixer_done(), and worker().

◆ thread_id

thread state_audio_mixer::thread_id
private

Definition at line 280 of file mixer.cpp.

Referenced by state_audio_mixer(), and ~state_audio_mixer().


The documentation for this struct was generated from the following file: