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