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
57struct chan_info {
58	const char 	*base;
59	uint32		sample_offset;
60	float		gain;
61};
62
63
64MixerCore::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	fHasEvent(false),
88	fOutputGain(1.0)
89{
90}
91
92
93MixerCore::~MixerCore()
94{
95	delete fSettings;
96
97	delete fLocker;
98	delete fInputs;
99
100	ASSERT(fMixThreadWaitSem == -1);
101	ASSERT(fMixThread == -1);
102
103	if (fMixBuffer)
104		rtm_free(fMixBuffer);
105
106	if (fTimeSource)
107		fTimeSource->Release();
108
109	if (fResampler) {
110		for (int i = 0; i < fMixBufferChannelCount; i++)
111			delete fResampler[i];
112		delete[] fResampler;
113	}
114
115	delete[] fMixBufferChannelTypes;
116}
117
118
119MixerSettings *
120MixerCore::Settings()
121{
122	return fSettings;
123}
124
125
126void
127MixerCore::UpdateResamplingAlgorithm()
128{
129	ASSERT_LOCKED();
130
131	_UpdateResamplers(fOutput->MediaOutput().format.u.raw_audio);
132
133	for (int32 i = fInputs->CountItems() - 1; i >= 0; i--) {
134		MixerInput* input
135			= reinterpret_cast<MixerInput*>(fInputs->ItemAtFast(i));
136		input->UpdateResamplingAlgorithm();
137	}
138}
139
140
141void
142MixerCore::SetOutputAttenuation(float gain)
143{
144	ASSERT_LOCKED();
145	fOutputGain = gain;
146}
147
148
149MixerInput*
150MixerCore::AddInput(const media_input& input)
151{
152	ASSERT_LOCKED();
153	MixerInput* in = new MixerInput(this, input, fMixBufferFrameRate,
154		fMixBufferFrameCount);
155	fInputs->AddItem(in);
156	return in;
157}
158
159
160MixerOutput*
161MixerCore::AddOutput(const media_output& output)
162{
163	ASSERT_LOCKED();
164	if (fOutput) {
165		ERROR("MixerCore::AddOutput: already connected\n");
166		return fOutput;
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
180bool
181MixerCore::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
196bool
197MixerCore::RemoveOutput()
198{
199	ASSERT_LOCKED();
200	if (!fOutput)
201		return false;
202
203	if (fStarted)
204		StopMixThread();
205
206	delete fOutput;
207	fOutput = 0;
208	fOutputEnabled = true;
209	return true;
210}
211
212
213int32
214MixerCore::CreateInputID()
215{
216	ASSERT_LOCKED();
217	return fNextInputID++;
218}
219
220
221MixerInput *
222MixerCore::Input(int i)
223{
224	ASSERT_LOCKED();
225	return (MixerInput *)fInputs->ItemAt(i);
226}
227
228
229MixerOutput *
230MixerCore::Output()
231{
232	ASSERT_LOCKED();
233	return fOutput;
234}
235
236
237void
238MixerCore::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
254void
255MixerCore::InputFormatChanged(int32 inputID,
256	const media_multi_audio_format &format)
257{
258	ASSERT_LOCKED();
259	ERROR("MixerCore::InputFormatChanged not handled\n");
260}
261
262
263void
264MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
265{
266	ASSERT_LOCKED();
267	bool was_started = fStarted;
268
269	if (was_started)
270		Stop();
271
272	fOutput->ChangeFormat(format);
273	_ApplyOutputFormat();
274
275	if (was_started)
276		Start();
277}
278
279
280void
281MixerCore::SetOutputBufferGroup(BBufferGroup *group)
282{
283	ASSERT_LOCKED();
284	fBufferGroup = group;
285}
286
287
288void
289MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
290{
291	ASSERT_LOCKED();
292	if (fTimeSource)
293		fTimeSource->Release();
294
295	fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
296	fDownstreamLatency = downstream_latency;
297
298	TRACE("MixerCore::SetTimingInfo, now = %lld, downstream latency %lld\n",
299		fTimeSource->Now(), fDownstreamLatency);
300}
301
302
303void
304MixerCore::EnableOutput(bool enabled)
305{
306	ASSERT_LOCKED();
307	TRACE("MixerCore::EnableOutput %d\n", enabled);
308	fOutputEnabled = enabled;
309
310	if (fRunning && !fOutputEnabled)
311		StopMixThread();
312
313	if (!fRunning && fOutput && fStarted && fOutputEnabled)
314		StartMixThread();
315}
316
317
318uint32
319MixerCore::OutputChannelCount()
320{
321	return (fOutput) ? fOutput->GetOutputChannelCount() : 0;
322}
323
324
325bool
326MixerCore::Start()
327{
328	ASSERT_LOCKED();
329	TRACE("MixerCore::Start\n");
330	if (fStarted)
331		return false;
332
333	fStarted = true;
334
335	ASSERT(!fRunning);
336
337	// only start the mix thread if we have an output
338	if (fOutput && fOutputEnabled)
339		StartMixThread();
340
341	return true;
342}
343
344
345bool
346MixerCore::Stop()
347{
348	ASSERT_LOCKED();
349	TRACE("MixerCore::Stop\n");
350	if (!fStarted)
351		return false;
352
353	if (fRunning)
354		StopMixThread();
355
356	fStarted = false;
357	return true;
358}
359
360
361void
362MixerCore::StartMixThread()
363{
364	ASSERT(fOutputEnabled == true);
365	ASSERT(fRunning == false);
366	ASSERT(fOutput);
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
375void
376MixerCore::StopMixThread()
377{
378	ASSERT(fRunning == true);
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
395void
396MixerCore::_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
421void
422MixerCore::_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
468int32
469MixerCore::_MixThreadEntry(void* arg)
470{
471	static_cast<MixerCore*>(arg)->_MixThread();
472	return 0;
473}
474
475
476void
477MixerCore::_MixThread()
478{
479	// The broken BeOS R5 multiaudio node starts with time 0,
480	// then publishes negative times for about 50ms, publishes 0
481	// again until it finally reaches time values > 0
482	if (!Lock())
483		return;
484	bigtime_t start = fTimeSource->Now();
485	Unlock();
486	while (start <= 0) {
487		TRACE("MixerCore: delaying _MixThread start, timesource is at %lld\n",
488			start);
489		snooze(5000);
490		if (!Lock())
491			return;
492		start = fTimeSource->Now();
493		Unlock();
494	}
495
496	fEventLatency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration(
497		fOutput->MediaOutput().format.u.raw_audio)));
498
499	// TODO: when the format changes while running, everything is wrong!
500	bigtime_t bufferRequestTimeout = buffer_duration(
501		fOutput->MediaOutput().format.u.raw_audio) / 2;
502
503	TRACE("MixerCore: starting _MixThread at %lld with latency %lld and "
504		"downstream latency %lld, bufferRequestTimeout %lld\n", start,
505		fEventLatency, fDownstreamLatency, bufferRequestTimeout);
506
507	// We must read from the input buffer at a position (pos) that is always
508	// a multiple of fMixBufferFrameCount.
509	int64 temp = frames_for_duration(fMixBufferFrameRate, start);
510	int64 frameBase = ((temp / fMixBufferFrameCount) + 1)
511		* fMixBufferFrameCount;
512	bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase);
513
514	TRACE("MixerCore: starting _MixThread, start %lld, timeBase %lld, "
515		"frameBase %lld\n", start, timeBase, frameBase);
516
517	ASSERT(fMixBufferFrameCount > 0);
518
519#if DEBUG
520	uint64 bufferIndex = 0;
521#endif
522
523	typedef RtList<chan_info> chan_info_list;
524	chan_info_list inputChanInfos[MAX_CHANNEL_TYPES];
525	BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount);
526		// TODO: this does not support changing output channel count
527	if (!mixChanInfos.IsValid()) {
528		ERROR("MixerCore::_MixThread mixChanInfos allocation failed\n");
529		return;
530	}
531
532	fEventTime = timeBase;
533	int64 framePos = 0;
534	status_t ret = B_ERROR;
535
536	while(fRunning == true) {
537		if (fHasEvent == false)
538			goto schedule_next_event;
539
540		ret = acquire_sem(fMixThreadWaitSem);
541		if (ret == B_INTERRUPTED)
542			continue;
543		else if (ret != B_OK)
544			return;
545
546		fHasEvent = false;
547
548		if (!LockWithTimeout(10000)) {
549			ERROR("MixerCore: LockWithTimeout failed\n");
550			continue;
551		}
552
553		// no inputs or output muted, skip further processing and just send an
554		// empty buffer
555		if (fInputs->IsEmpty() || fOutput->IsMuted()) {
556			int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
557			BBuffer* buffer = fBufferGroup->RequestBuffer(size,
558				bufferRequestTimeout);
559			if (buffer != NULL) {
560				int middle = 0;
561				if (fOutput->MediaOutput().format.u.raw_audio.format
562						== media_raw_audio_format::B_AUDIO_UCHAR)
563					middle = 128;
564				memset(buffer->Data(), middle, size);
565				// fill in the buffer header
566				media_header* hdr = buffer->Header();
567				hdr->type = B_MEDIA_RAW_AUDIO;
568				hdr->size_used = size;
569				hdr->time_source = fTimeSource->ID();
570				hdr->start_time = fEventTime;
571				if (fNode->SendBuffer(buffer, fOutput) != B_OK) {
572#if DEBUG
573					ERROR("MixerCore: SendBuffer failed for buffer %lld\n",
574						bufferIndex);
575#else
576					ERROR("MixerCore: SendBuffer failed\n");
577#endif
578					buffer->Recycle();
579				}
580			} else {
581#if DEBUG
582				ERROR("MixerCore: RequestBuffer failed for buffer %lld\n",
583					bufferIndex);
584#else
585				ERROR("MixerCore: RequestBuffer failed\n");
586#endif
587			}
588			goto schedule_next_event;
589		}
590
591		int64 currentFramePos;
592		currentFramePos = frameBase + framePos;
593
594		// mix all data from all inputs into the mix buffer
595		ASSERT(currentFramePos % fMixBufferFrameCount == 0);
596
597		PRINT(4, "create new buffer event at %lld, reading input frames at "
598			"%lld\n", fEventTime, currentFramePos);
599
600		// Init the channel information for each MixerInput.
601		for (int i = 0; MixerInput* input = Input(i); i++) {
602			int count = input->GetMixerChannelCount();
603			for (int channel = 0; channel < count; channel++) {
604				int type;
605				const float* base;
606				uint32 sampleOffset;
607				float gain;
608				if (!input->GetMixerChannelInfo(channel, currentFramePos,
609						fEventTime, &base, &sampleOffset, &type, &gain)) {
610					continue;
611				}
612				if (type < 0 || type >= MAX_CHANNEL_TYPES)
613					continue;
614				chan_info* info = inputChanInfos[type].Create();
615				info->base = (const char*)base;
616				info->sample_offset = sampleOffset;
617				info->gain = gain;
618			}
619		}
620
621		for (int channel = 0; channel < fMixBufferChannelCount; channel++) {
622			int sourceCount = fOutput->GetOutputChannelSourceCount(channel);
623			for (int i = 0; i < sourceCount; i++) {
624				int type;
625				float gain;
626				fOutput->GetOutputChannelSourceInfoAt(channel, i, &type,
627					&gain);
628				if (type < 0 || type >= MAX_CHANNEL_TYPES)
629					continue;
630				int count = inputChanInfos[type].CountItems();
631				for (int j = 0; j < count; j++) {
632					chan_info* info = inputChanInfos[type].ItemAt(j);
633					chan_info* newInfo = mixChanInfos[channel].Create();
634					newInfo->base = info->base;
635					newInfo->sample_offset = info->sample_offset;
636					newInfo->gain = info->gain * gain;
637				}
638			}
639		}
640
641		memset(fMixBuffer, 0,
642			fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
643		for (int channel = 0; channel < fMixBufferChannelCount; channel++) {
644			PRINT(5, "_MixThread: channel %d has %d sources\n", channel,
645				mixChanInfos[channel].CountItems());
646
647			int count = mixChanInfos[channel].CountItems();
648			for (int i = 0; i < count; i++) {
649				chan_info* info = mixChanInfos[channel].ItemAt(i);
650				PRINT(5, "_MixThread:   base %p, sample-offset %2d, gain %.3f\n",
651					info->base, info->sample_offset, info->gain);
652				// This looks slightly ugly, but the current GCC will generate
653				// the fastest code this way.
654				// fMixBufferFrameCount is always > 0.
655				uint32 dstSampleOffset
656					= fMixBufferChannelCount * sizeof(float);
657				uint32 srcSampleOffset = info->sample_offset;
658				char* dst = (char*)&fMixBuffer[channel];
659				char* src = (char*)info->base;
660				float gain = info->gain;
661				int j = fMixBufferFrameCount;
662				do {
663					*(float*)dst += *(const float*)src * gain;
664					dst += dstSampleOffset;
665					src += srcSampleOffset;
666				 } while (--j);
667			}
668		}
669
670		// request a buffer
671		BBuffer* buffer;
672		buffer = fBufferGroup->RequestBuffer(
673			fOutput->MediaOutput().format.u.raw_audio.buffer_size,
674			bufferRequestTimeout);
675		if (buffer != NULL) {
676			// copy data from mix buffer into output buffer
677			for (int i = 0; i < fMixBufferChannelCount; i++) {
678				fResampler[i]->Resample(
679					reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float),
680					fMixBufferChannelCount * sizeof(float),
681					fMixBufferFrameCount,
682					reinterpret_cast<char*>(buffer->Data())
683						+ (i * bytes_per_sample(
684							fOutput->MediaOutput().format.u.raw_audio)),
685					bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio),
686					frames_per_buffer(
687						fOutput->MediaOutput().format.u.raw_audio),
688					fOutputGain * fOutput->GetOutputChannelGain(i));
689			}
690			PRINT(4, "send buffer, inframes %ld, outframes %ld\n",
691				fMixBufferFrameCount,
692				frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
693
694			// fill in the buffer header
695			media_header* hdr = buffer->Header();
696			hdr->type = B_MEDIA_RAW_AUDIO;
697			hdr->size_used
698				= fOutput->MediaOutput().format.u.raw_audio.buffer_size;
699			hdr->time_source = fTimeSource->ID();
700			hdr->start_time = fEventTime;
701
702			// swap byte order if necessary
703			fOutput->AdjustByteOrder(buffer);
704
705			// send the buffer
706			status_t res = fNode->SendBuffer(buffer, fOutput);
707			if (res != B_OK) {
708#if DEBUG
709				ERROR("MixerCore: SendBuffer failed for buffer %lld\n",
710					bufferIndex);
711#else
712				ERROR("MixerCore: SendBuffer failed\n");
713#endif
714				buffer->Recycle();
715			}
716		} else {
717#if DEBUG
718			ERROR("MixerCore: RequestBuffer failed for buffer %lld\n",
719				bufferIndex);
720#else
721			ERROR("MixerCore: RequestBuffer failed\n");
722#endif
723		}
724
725		// make all lists empty
726		for (int i = 0; i < MAX_CHANNEL_TYPES; i++)
727			inputChanInfos[i].MakeEmpty();
728		for (int i = 0; i < fOutput->GetOutputChannelCount(); i++)
729			mixChanInfos[i].MakeEmpty();
730
731schedule_next_event:
732		Unlock();
733
734		// schedule next event
735		framePos += fMixBufferFrameCount;
736		fEventTime = timeBase + bigtime_t((1000000LL * framePos)
737			/ fMixBufferFrameRate);
738
739		media_timed_event mixerEvent(PickEvent(),
740			MIXER_PROCESS_EVENT, 0, BTimedEventQueue::B_NO_CLEANUP);
741
742		ret = write_port(fNode->ControlPort(), MIXER_SCHEDULE_EVENT,
743			&mixerEvent, sizeof(mixerEvent));
744		if (ret != B_OK)
745			TRACE("MixerCore::_MixThread: can't write to owner port\n");
746
747		fHasEvent = true;
748
749#if DEBUG
750		bufferIndex++;
751#endif
752	}
753}
754