1 /*
2 * Copyright 2003-2016 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Marcus Overhagen
7 * Dario Casalinuovo
8 */
9
10
11 #include "MixerCore.h"
12
13 #include <string.h>
14
15 #include <Buffer.h>
16 #include <BufferGroup.h>
17 #include <BufferProducer.h>
18 #include <MediaNode.h>
19 #include <RealtimeAlloc.h>
20 #include <StackOrHeapArray.h>
21 #include <StopWatch.h>
22 #include <TimeSource.h>
23
24 #include "AudioMixer.h"
25 #include "Interpolate.h"
26 #include "MixerInput.h"
27 #include "MixerOutput.h"
28 #include "MixerUtils.h"
29 #include "Resampler.h"
30 #include "RtList.h"
31
32
33 #define DOUBLE_RATE_MIXING 0
34
35 #if DEBUG > 1
36 # define ASSERT_LOCKED() if (fLocker->IsLocked()) {} \
37 else debugger("core not locked, meltdown occurred")
38 #else
39 # define ASSERT_LOCKED() ((void)0)
40 #endif
41
42 /*! Mixer channels are identified by a type number, each type number corresponds
43 to the one of the channel masks of enum media_multi_channels.
44
45 The mixer buffer uses either the same frame rate and same count of frames as
46 the output buffer, or the double frame rate and frame count.
47
48 All mixer input ring buffers must be an exact multiple of the mixer buffer
49 size, so that we do not get any buffer wrap around during reading from the
50 input buffers.
51 The mixer input is told by constructor (or after a format change by
52 SetMixBufferFormat() of the current mixer buffer propertys, and must
53 allocate a buffer that is an exact multiple,
54 */
55
56
57 struct chan_info {
58 const char *base;
59 uint32 sample_offset;
60 float gain;
61 };
62
63
MixerCore(AudioMixer * node)64 MixerCore::MixerCore(AudioMixer *node)
65 :
66 fLocker(new BLocker("mixer core lock")),
67 fInputs(new BList),
68 fOutput(0),
69 fNextInputID(1),
70 fRunning(false),
71 fStarted(false),
72 fOutputEnabled(true),
73 fResampler(0),
74 fMixBuffer(0),
75 fMixBufferFrameRate(0),
76 fMixBufferFrameCount(0),
77 fMixBufferChannelCount(0),
78 fMixBufferChannelTypes(0),
79 fDoubleRateMixing(DOUBLE_RATE_MIXING),
80 fDownstreamLatency(1),
81 fSettings(new MixerSettings),
82 fNode(node),
83 fBufferGroup(0),
84 fTimeSource(0),
85 fMixThread(-1),
86 fMixThreadWaitSem(-1),
87 fOutputGain(1.0)
88 {
89 }
90
91
~MixerCore()92 MixerCore::~MixerCore()
93 {
94 delete fSettings;
95
96 delete fLocker;
97 delete fInputs;
98
99 ASSERT(fMixThreadWaitSem == -1);
100 ASSERT(fMixThread == -1);
101
102 if (fMixBuffer)
103 rtm_free(fMixBuffer);
104
105 if (fTimeSource)
106 fTimeSource->Release();
107
108 if (fResampler) {
109 for (int i = 0; i < fMixBufferChannelCount; i++)
110 delete fResampler[i];
111 delete[] fResampler;
112 }
113
114 delete[] fMixBufferChannelTypes;
115 }
116
117
118 MixerSettings *
Settings()119 MixerCore::Settings()
120 {
121 return fSettings;
122 }
123
124
125 void
UpdateResamplingAlgorithm()126 MixerCore::UpdateResamplingAlgorithm()
127 {
128 ASSERT_LOCKED();
129
130 _UpdateResamplers(fOutput->MediaOutput().format.u.raw_audio);
131
132 for (int32 i = fInputs->CountItems() - 1; i >= 0; i--) {
133 MixerInput* input
134 = reinterpret_cast<MixerInput*>(fInputs->ItemAtFast(i));
135 input->UpdateResamplingAlgorithm();
136 }
137 }
138
139
140 void
SetOutputAttenuation(float gain)141 MixerCore::SetOutputAttenuation(float gain)
142 {
143 ASSERT_LOCKED();
144 fOutputGain = gain;
145 }
146
147
148 MixerInput*
AddInput(const media_input & input)149 MixerCore::AddInput(const media_input& input)
150 {
151 ASSERT_LOCKED();
152 MixerInput* in = new MixerInput(this, input, fMixBufferFrameRate,
153 fMixBufferFrameCount);
154 fInputs->AddItem(in);
155 return in;
156 }
157
158
159 MixerOutput*
AddOutput(const media_output & output)160 MixerCore::AddOutput(const media_output& output)
161 {
162 ASSERT_LOCKED();
163 if (fOutput != NULL) {
164 ERROR("MixerCore::AddOutput: already connected\n");
165 return fOutput;
166 }
167
168 fOutput = new MixerOutput(this, output);
169 // the output format might have been adjusted inside MixerOutput
170 _ApplyOutputFormat();
171
172 ASSERT(!fRunning);
173 if (fStarted && fOutputEnabled)
174 _StartMixThread();
175
176 return fOutput;
177 }
178
179
180 bool
RemoveInput(int32 inputID)181 MixerCore::RemoveInput(int32 inputID)
182 {
183 ASSERT_LOCKED();
184 MixerInput *input;
185 for (int i = 0; (input = Input(i)) != 0; i++) {
186 if (input->ID() == inputID) {
187 fInputs->RemoveItem(i);
188 delete input;
189 return true;
190 }
191 }
192 return false;
193 }
194
195
196 bool
RemoveOutput()197 MixerCore::RemoveOutput()
198 {
199 ASSERT_LOCKED();
200 if (fOutput == NULL)
201 return false;
202
203 if (fRunning)
204 _StopMixThread();
205
206 delete fOutput;
207 fOutput = NULL;
208 fOutputEnabled = true;
209 return true;
210 }
211
212
213 int32
CreateInputID()214 MixerCore::CreateInputID()
215 {
216 ASSERT_LOCKED();
217 return fNextInputID++;
218 }
219
220
221 MixerInput *
Input(int i)222 MixerCore::Input(int i)
223 {
224 ASSERT_LOCKED();
225 return (MixerInput *)fInputs->ItemAt(i);
226 }
227
228
229 MixerOutput *
Output()230 MixerCore::Output()
231 {
232 ASSERT_LOCKED();
233 return fOutput;
234 }
235
236
237 void
BufferReceived(BBuffer * buffer,bigtime_t lateness)238 MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness)
239 {
240 ASSERT_LOCKED();
241 MixerInput *input;
242 int32 id = buffer->Header()->destination;
243 for (int i = 0; (input = Input(i)) != 0; i++) {
244 if (input->ID() == id) {
245 input->BufferReceived(buffer);
246 return;
247 }
248 }
249 ERROR("MixerCore::BufferReceived: received buffer for unknown id %ld\n",
250 id);
251 }
252
253
254 void
InputFormatChanged(int32 inputID,const media_multi_audio_format & format)255 MixerCore::InputFormatChanged(int32 inputID,
256 const media_multi_audio_format &format)
257 {
258 ASSERT_LOCKED();
259 ERROR("MixerCore::InputFormatChanged not handled\n");
260 }
261
262
263 void
OutputFormatChanged(const media_multi_audio_format & format)264 MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
265 {
266 ASSERT_LOCKED();
267
268 if (fRunning)
269 _StopMixThread();
270
271 fOutput->ChangeFormat(format);
272 _ApplyOutputFormat();
273
274 if (fStarted)
275 _StartMixThread();
276 }
277
278
279 void
SetOutputBufferGroup(BBufferGroup * group)280 MixerCore::SetOutputBufferGroup(BBufferGroup *group)
281 {
282 ASSERT_LOCKED();
283 fBufferGroup = group;
284 }
285
286
287 void
SetTimingInfo(BTimeSource * ts,bigtime_t downstream_latency)288 MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
289 {
290 ASSERT_LOCKED();
291 if (fTimeSource)
292 fTimeSource->Release();
293
294 fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
295 fDownstreamLatency = downstream_latency;
296
297 TRACE("MixerCore::SetTimingInfo, now = %lld, downstream latency %lld\n",
298 fTimeSource->Now(), fDownstreamLatency);
299 }
300
301
302 void
EnableOutput(bool enabled)303 MixerCore::EnableOutput(bool enabled)
304 {
305 ASSERT_LOCKED();
306 TRACE("MixerCore::EnableOutput %d\n", enabled);
307 fOutputEnabled = enabled;
308
309 if (fRunning && !fOutputEnabled)
310 _StopMixThread();
311
312 if (!fRunning && fOutput != NULL && fStarted && fOutputEnabled)
313 _StartMixThread();
314 }
315
316
317 uint32
OutputChannelCount()318 MixerCore::OutputChannelCount()
319 {
320 return (fOutput) ? fOutput->GetOutputChannelCount() : 0;
321 }
322
323
324 bool
Start()325 MixerCore::Start()
326 {
327 ASSERT_LOCKED();
328 TRACE("MixerCore::Start\n");
329 if (fStarted)
330 return false;
331
332 fStarted = true;
333
334 ASSERT(!fRunning);
335
336 // only start the mix thread if we have an output
337 if (fOutput != NULL && fOutputEnabled)
338 _StartMixThread();
339
340 return true;
341 }
342
343
344 bool
Stop()345 MixerCore::Stop()
346 {
347 ASSERT_LOCKED();
348 TRACE("MixerCore::Stop\n");
349 if (!fStarted)
350 return false;
351
352 if (fRunning)
353 _StopMixThread();
354
355 fStarted = false;
356 return true;
357 }
358
359
360 void
_StartMixThread()361 MixerCore::_StartMixThread()
362 {
363 ASSERT(fOutputEnabled);
364 ASSERT(!fRunning);
365 ASSERT(fOutput != NULL);
366
367 fRunning = true;
368 fMixThreadWaitSem = create_sem(0, "mix thread wait");
369 fMixThread = spawn_thread(_MixThreadEntry, "Yeah baby, very shagadelic",
370 120, this);
371 resume_thread(fMixThread);
372 }
373
374
375 void
_StopMixThread()376 MixerCore::_StopMixThread()
377 {
378 ASSERT(fRunning);
379 ASSERT(fMixThread > 0);
380 ASSERT(fMixThreadWaitSem > 0);
381
382 fRunning = false;
383 status_t unused;
384 delete_sem(fMixThreadWaitSem);
385 wait_for_thread(fMixThread, &unused);
386
387 fMixThread = -1;
388 fMixThreadWaitSem = -1;
389 }
390
391
392 // #pragma mark - private
393
394
395 void
_UpdateResamplers(const media_multi_audio_format & format)396 MixerCore::_UpdateResamplers(const media_multi_audio_format& format)
397 {
398 ASSERT_LOCKED();
399
400 if (fResampler != NULL) {
401 for (int i = 0; i < fMixBufferChannelCount; i++)
402 delete fResampler[i];
403 delete[] fResampler;
404 }
405
406 fResampler = new Resampler*[fMixBufferChannelCount];
407 for (int i = 0; i < fMixBufferChannelCount; i++) {
408 switch (Settings()->ResamplingAlgorithm()) {
409 case 2:
410 fResampler[i] = new Interpolate(
411 media_raw_audio_format::B_AUDIO_FLOAT, format.format);
412 break;
413 default:
414 fResampler[i] = new Resampler(
415 media_raw_audio_format::B_AUDIO_FLOAT, format.format);
416 }
417 }
418 }
419
420
421 void
_ApplyOutputFormat()422 MixerCore::_ApplyOutputFormat()
423 {
424 ASSERT_LOCKED();
425
426 const media_multi_audio_format& format
427 = fOutput->MediaOutput().format.u.raw_audio;
428
429 if (fMixBuffer != NULL)
430 rtm_free(fMixBuffer);
431
432 delete[] fMixBufferChannelTypes;
433
434 fMixBufferFrameRate = (int32)(0.5 + format.frame_rate);
435 fMixBufferFrameCount = frames_per_buffer(format);
436 if (fDoubleRateMixing) {
437 fMixBufferFrameRate *= 2;
438 fMixBufferFrameCount *= 2;
439 }
440 fMixBufferChannelCount = format.channel_count;
441 ASSERT(fMixBufferChannelCount == fOutput->GetOutputChannelCount());
442 fMixBufferChannelTypes = new int32 [format.channel_count];
443
444 for (int i = 0; i < fMixBufferChannelCount; i++) {
445 fMixBufferChannelTypes[i]
446 = ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask));
447 }
448
449 fMixBuffer = (float*)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount
450 * fMixBufferChannelCount);
451 ASSERT(fMixBuffer != NULL);
452
453 _UpdateResamplers(format);
454
455 TRACE("MixerCore::OutputFormatChanged:\n");
456 TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
457 TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount);
458 TRACE(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount);
459 for (int i = 0; i < fMixBufferChannelCount; i++)
460 TRACE(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]);
461
462 MixerInput *input;
463 for (int i = 0; (input = Input(i)); i++)
464 input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount);
465 }
466
467
468 int32
_MixThreadEntry(void * arg)469 MixerCore::_MixThreadEntry(void* arg)
470 {
471 static_cast<MixerCore*>(arg)->_MixThread();
472 return 0;
473 }
474
475
476 void
_MixThread()477 MixerCore::_MixThread()
478 {
479 if (!Lock())
480 return;
481 {
482 // Delay starting the mixer until we have a valid time source.
483 bigtime_t performanceTime, realTime;
484 float drift;
485 while (fTimeSource->GetTime(&performanceTime, &realTime, &drift) != B_OK
486 || performanceTime <= 0 || realTime <= 0
487 || (realTime + 1 * 1000 * 1000) <= system_time()) {
488 TRACE("MixerCore: delaying _MixThread start, timesource is at %" B_PRIdBIGTIME "\n",
489 performanceTime);
490 Unlock();
491 snooze(5000);
492 while (!LockWithTimeout(10000)) {
493 if (!fRunning)
494 return;
495 }
496 }
497 }
498 Unlock();
499
500 const bigtime_t start = fTimeSource->Now();
501
502 bigtime_t eventLatency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration(
503 fOutput->MediaOutput().format.u.raw_audio)));
504
505 // TODO: when the format changes while running, everything is wrong!
506 bigtime_t bufferRequestTimeout = buffer_duration(
507 fOutput->MediaOutput().format.u.raw_audio) / 2;
508
509 TRACE("MixerCore: starting _MixThread at %lld with latency %lld and "
510 "downstream latency %lld, bufferRequestTimeout %lld\n", start,
511 eventLatency, fDownstreamLatency, bufferRequestTimeout);
512
513 // We must read from the input buffer at a position (pos) that is always
514 // a multiple of fMixBufferFrameCount.
515 int64 temp = frames_for_duration(fMixBufferFrameRate, start);
516 const int64 frameBase = ((temp / fMixBufferFrameCount) + 1)
517 * fMixBufferFrameCount;
518 const bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase);
519
520 TRACE("MixerCore: starting _MixThread, start %lld, timeBase %lld, "
521 "frameBase %lld\n", start, timeBase, frameBase);
522
523 ASSERT(fMixBufferFrameCount > 0);
524
525 typedef RtList<chan_info> chan_info_list;
526 chan_info_list inputChanInfos[MAX_CHANNEL_TYPES];
527 BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount);
528 // TODO: this does not support changing output channel count
529 if (!mixChanInfos.IsValid()) {
530 ERROR("MixerCore::_MixThread mixChanInfos allocation failed\n");
531 return;
532 }
533
534 int64 framePos = 0;
535 uint64 bufferIndex = 0;
536 bigtime_t eventTime = 0, nextRun = B_INFINITE_TIMEOUT;
537 while (fRunning) {
538 if (nextRun == B_INFINITE_TIMEOUT) {
539 eventTime = timeBase + bigtime_t((1000000LL * framePos)
540 / fMixBufferFrameRate);
541 nextRun = fTimeSource->RealTimeFor(eventTime, 0)
542 - eventLatency - fDownstreamLatency;
543 }
544
545 status_t status = acquire_sem_etc(fMixThreadWaitSem, 1,
546 B_ABSOLUTE_TIMEOUT, nextRun);
547 if (status != B_TIMED_OUT) {
548 if (status == B_OK || status == B_INTERRUPTED)
549 continue;
550 return;
551 }
552 nextRun = B_INFINITE_TIMEOUT;
553
554 if (!LockWithTimeout(10000)) {
555 ERROR("MixerCore: LockWithTimeout failed\n");
556 continue;
557 }
558
559 // no inputs or output muted, skip further processing and just send an
560 // empty buffer
561 if (fInputs->IsEmpty() || fOutput->IsMuted()) {
562 int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
563 BBuffer* buffer = fBufferGroup->RequestBuffer(size,
564 bufferRequestTimeout);
565 if (buffer != NULL) {
566 int middle = 0;
567 if (fOutput->MediaOutput().format.u.raw_audio.format
568 == media_raw_audio_format::B_AUDIO_UCHAR)
569 middle = 128;
570 memset(buffer->Data(), middle, size);
571 // fill in the buffer header
572 media_header* hdr = buffer->Header();
573 hdr->type = B_MEDIA_RAW_AUDIO;
574 hdr->size_used = size;
575 hdr->time_source = fTimeSource->ID();
576 hdr->start_time = eventTime;
577 if (fNode->SendBuffer(buffer, fOutput) != B_OK) {
578 ERROR("MixerCore: SendBuffer failed for buffer %lld\n",
579 bufferIndex);
580 buffer->Recycle();
581 }
582 } else {
583 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n",
584 bufferIndex);
585 }
586
587 bufferIndex++;
588 framePos += fMixBufferFrameCount;
589
590 Unlock();
591 continue;
592 }
593
594 int64 currentFramePos;
595 currentFramePos = frameBase + framePos;
596
597 // mix all data from all inputs into the mix buffer
598 ASSERT(currentFramePos % fMixBufferFrameCount == 0);
599
600 PRINT(4, "create new buffer event at %lld, reading input frames at "
601 "%lld\n", eventTime, currentFramePos);
602
603 // Init the channel information for each MixerInput.
604 for (int i = 0; MixerInput* input = Input(i); i++) {
605 int count = input->GetMixerChannelCount();
606 for (int channel = 0; channel < count; channel++) {
607 int type;
608 const float* base;
609 uint32 sampleOffset;
610 float gain;
611 if (!input->GetMixerChannelInfo(channel, currentFramePos,
612 eventTime, &base, &sampleOffset, &type, &gain)) {
613 continue;
614 }
615 if (type < 0 || type >= MAX_CHANNEL_TYPES)
616 continue;
617 chan_info* info = inputChanInfos[type].Create();
618 info->base = (const char*)base;
619 info->sample_offset = sampleOffset;
620 info->gain = gain;
621 }
622 }
623
624 for (int channel = 0; channel < fMixBufferChannelCount; channel++) {
625 int sourceCount = fOutput->GetOutputChannelSourceCount(channel);
626 for (int i = 0; i < sourceCount; i++) {
627 int type;
628 float gain;
629 fOutput->GetOutputChannelSourceInfoAt(channel, i, &type,
630 &gain);
631 if (type < 0 || type >= MAX_CHANNEL_TYPES)
632 continue;
633 int count = inputChanInfos[type].CountItems();
634 for (int j = 0; j < count; j++) {
635 chan_info* info = inputChanInfos[type].ItemAt(j);
636 chan_info* newInfo = mixChanInfos[channel].Create();
637 newInfo->base = info->base;
638 newInfo->sample_offset = info->sample_offset;
639 newInfo->gain = info->gain * gain;
640 }
641 }
642 }
643
644 memset(fMixBuffer, 0,
645 fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
646 for (int channel = 0; channel < fMixBufferChannelCount; channel++) {
647 PRINT(5, "_MixThread: channel %d has %d sources\n", channel,
648 mixChanInfos[channel].CountItems());
649
650 int count = mixChanInfos[channel].CountItems();
651 for (int i = 0; i < count; i++) {
652 chan_info* info = mixChanInfos[channel].ItemAt(i);
653 PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n",
654 info->base, info->sample_offset, info->gain);
655 // This looks slightly ugly, but the current GCC will generate
656 // the fastest code this way.
657 // fMixBufferFrameCount is always > 0.
658 uint32 dstSampleOffset
659 = fMixBufferChannelCount * sizeof(float);
660 uint32 srcSampleOffset = info->sample_offset;
661 char* dst = (char*)&fMixBuffer[channel];
662 char* src = (char*)info->base;
663 float gain = info->gain;
664 int j = fMixBufferFrameCount;
665 do {
666 *(float*)dst += *(const float*)src * gain;
667 dst += dstSampleOffset;
668 src += srcSampleOffset;
669 } while (--j);
670 }
671 }
672
673 // request a buffer
674 BBuffer* buffer;
675 buffer = fBufferGroup->RequestBuffer(
676 fOutput->MediaOutput().format.u.raw_audio.buffer_size,
677 bufferRequestTimeout);
678 if (buffer != NULL) {
679 // copy data from mix buffer into output buffer
680 for (int i = 0; i < fMixBufferChannelCount; i++) {
681 fResampler[i]->Resample(
682 reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float),
683 fMixBufferChannelCount * sizeof(float),
684 fMixBufferFrameCount,
685 reinterpret_cast<char*>(buffer->Data())
686 + (i * bytes_per_sample(
687 fOutput->MediaOutput().format.u.raw_audio)),
688 bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
689 frames_per_buffer(
690 fOutput->MediaOutput().format.u.raw_audio),
691 fOutputGain * fOutput->GetOutputChannelGain(i));
692 }
693 PRINT(4, "send buffer, inframes %ld, outframes %ld\n",
694 fMixBufferFrameCount,
695 frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
696
697 // fill in the buffer header
698 media_header* hdr = buffer->Header();
699 hdr->type = B_MEDIA_RAW_AUDIO;
700 hdr->size_used
701 = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
702 hdr->time_source = fTimeSource->ID();
703 hdr->start_time = eventTime;
704
705 // swap byte order if necessary
706 fOutput->AdjustByteOrder(buffer);
707
708 // send the buffer
709 status_t res = fNode->SendBuffer(buffer, fOutput);
710 if (res != B_OK) {
711 ERROR("MixerCore: SendBuffer failed for buffer %lld\n",
712 bufferIndex);
713 buffer->Recycle();
714 }
715 } else {
716 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n",
717 bufferIndex);
718 }
719
720 // make all lists empty
721 for (int i = 0; i < MAX_CHANNEL_TYPES; i++)
722 inputChanInfos[i].MakeEmpty();
723 for (int i = 0; i < fOutput->GetOutputChannelCount(); i++)
724 mixChanInfos[i].MakeEmpty();
725
726 bufferIndex++;
727 framePos += fMixBufferFrameCount;
728
729 Unlock();
730 }
731 }
732