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 <Buffer.h>
13#include <string.h>
14#include <TimeSource.h> // TODO: debug only
15
16#include "ByteSwap.h"
17#include "Interpolate.h"
18#include "MixerInput.h"
19#include "MixerUtils.h"
20#include "Resampler.h"
21
22
23MixerInput::MixerInput(MixerCore* core, const media_input& input,
24	float mixFrameRate, int32 mixFrameCount)
25	:
26	fCore(core),
27 	fInput(input),
28	fInputByteSwap(NULL),
29	fEnabled(true),
30	fInputChannelInfo(NULL),
31	fInputChannelCount(0),
32	fInputChannelMask(0),
33	fMixerChannelInfo(0),
34	fMixerChannelCount(0),
35	fMixBuffer(NULL),
36	fMixBufferFrameRate(0),
37	fMixBufferFrameCount(0),
38	fLastDataFrameWritten(-1),
39	fLastDataAvailableTime(-1),
40	fFractionalFrames(0.0),
41	fResampler(NULL),
42	fRtmPool(NULL),
43	fUserOverridesChannelDestinations(false)
44{
45	fix_multiaudio_format(&fInput.format.u.raw_audio);
46	PRINT_INPUT("MixerInput::MixerInput", fInput);
47	PRINT_CHANNEL_MASK(fInput.format);
48
49	ASSERT(fInput.format.u.raw_audio.channel_count > 0);
50
51	for (int i = 0; i <	MAX_CHANNEL_TYPES; i++)
52		fChannelTypeGain[i] = 1.0f;
53
54	fInputChannelCount = fInput.format.u.raw_audio.channel_count;
55	fInputChannelMask = fInput.format.u.raw_audio.channel_mask;
56	fInputChannelInfo = new input_chan_info[fInputChannelCount];
57
58	// perhaps we need byte swapping
59	if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
60		if (fInput.format.u.raw_audio.format
61				== media_raw_audio_format::B_AUDIO_FLOAT
62			|| fInput.format.u.raw_audio.format
63				== media_raw_audio_format::B_AUDIO_INT
64			|| fInput.format.u.raw_audio.format
65				== media_raw_audio_format::B_AUDIO_SHORT) {
66			fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format);
67		}
68	}
69
70	// initialize fInputChannelInfo
71	for (int i = 0; i < fInputChannelCount; i++) {
72		fInputChannelInfo[i].buffer_base = 0;
73			// will be set by SetMixBufferFormat()
74		fInputChannelInfo[i].destination_mask = 0;
75			// will be set by _UpdateInputChannelDestinationMask()
76		fInputChannelInfo[i].gain = 1.0;
77	}
78
79	UpdateResamplingAlgorithm();
80
81	// fMixerChannelInfo and fMixerChannelCount will be initialized by
82	// _UpdateInputChannelDestinations()
83	SetMixBufferFormat((int32)mixFrameRate, mixFrameCount);
84}
85
86
87MixerInput::~MixerInput()
88{
89	if (fMixBuffer)
90		rtm_free(fMixBuffer);
91	if (fRtmPool)
92		rtm_delete_pool(fRtmPool);
93	delete[] fInputChannelInfo;
94	delete[] fMixerChannelInfo;
95
96	// delete resamplers
97	if (fResampler != NULL) {
98		for (int i = 0; i < fInputChannelCount; i++)
99			delete fResampler[i];
100		delete[] fResampler;
101	}
102	delete fInputByteSwap;
103}
104
105
106int32
107MixerInput::ID()
108{
109	return fInput.destination.id;
110}
111
112
113media_input&
114MixerInput::MediaInput()
115{
116	return fInput;
117}
118
119
120void
121MixerInput::BufferReceived(BBuffer* buffer)
122{
123	void* data;
124	size_t size;
125	bigtime_t start;
126	bigtime_t buffer_duration;
127
128	if (!fMixBuffer) {
129		ERROR("MixerInput::BufferReceived: dropped incoming buffer as we "
130			"don't have a mix buffer\n");
131		return;
132	}
133
134	data = buffer->Data();
135	size = buffer->SizeUsed();
136	start = buffer->Header()->start_time;
137	buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate,
138		size / bytes_per_frame(fInput.format.u.raw_audio));
139	if (start < 0) {
140		ERROR("MixerInput::BufferReceived: buffer with negative start time of "
141			"%lld dropped\n", start);
142		return;
143	}
144
145	// swap the byte order of this buffer, if necessary
146	if (fInputByteSwap)
147		fInputByteSwap->Swap(data, size);
148
149	int offset = frames_for_duration(fMixBufferFrameRate, start)
150		% fMixBufferFrameCount;
151
152	PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n",
153		start, offset);
154
155	int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio);
156	double frames = ((double)in_frames * fMixBufferFrameRate)
157		/ fInput.format.u.raw_audio.frame_rate;
158	int out_frames = int(frames);
159	fFractionalFrames += frames - double(out_frames);
160	if (fFractionalFrames >= 1.0) {
161		fFractionalFrames -= 1.0;
162		out_frames++;
163	}
164
165	// if fLastDataFrameWritten != -1, then we have a valid last position
166	// and can do glitch compensation
167	if (fLastDataFrameWritten >= 0) {
168		int expected_frame = (fLastDataFrameWritten + 1)
169			% fMixBufferFrameCount;
170		if (offset != expected_frame) {
171			// due to rounding and other errors, offset might be off by +/- 1
172			// this is not really a bad glitch, we just adjust the position
173			if (offset == fLastDataFrameWritten) {
174//				printf("MixerInput::BufferReceived: -1 frame GLITCH! last "
175//					"frame was %ld, expected frame was %d, new frame is %d\n",
176//					fLastDataFrameWritten, expected_frame, offset);
177				offset = expected_frame;
178			} else if (offset == ((fLastDataFrameWritten + 2)
179				% fMixBufferFrameCount)) {
180//				printf("MixerInput::BufferReceived: +1 frame GLITCH! last "
181//					"frame was %ld, expected frame was %d, new frame is %d\n",
182//					fLastDataFrameWritten, expected_frame, offset);
183				offset = expected_frame;
184			} else {
185				printf("MixerInput::BufferReceived: GLITCH! last frame was "
186					"%4" B_PRId32 ", expected frame was %4d, new frame is %4d"
187					"\n", fLastDataFrameWritten, expected_frame, offset);
188
189				if (start > fLastDataAvailableTime) {
190					if ((start - fLastDataAvailableTime)
191						< (buffer_duration / 10)) {
192						// buffer is less than 10% of buffer duration too late
193						printf("short glitch, buffer too late, time delta "
194							"%" B_PRIdBIGTIME "\n", start
195							- fLastDataAvailableTime);
196						offset = expected_frame;
197						out_frames++;
198					} else {
199						// buffer more than 10% of buffer duration too late
200						// TODO: zerofill buffer
201						printf("MAJOR glitch, buffer too late, time delta "
202							"%" B_PRIdBIGTIME "\n", start
203							- fLastDataAvailableTime);
204					}
205				} else { // start <= fLastDataAvailableTime
206					// the new buffer is too early
207					if ((fLastDataAvailableTime - start)
208						< (buffer_duration / 10)) {
209						// buffer is less than 10% of buffer duration too early
210						printf("short glitch, buffer too early, time delta "
211							"%" B_PRIdBIGTIME "\n", fLastDataAvailableTime
212							- start);
213						offset = expected_frame;
214						out_frames--;
215						if (out_frames < 1)
216							out_frames = 1;
217					} else {
218						// buffer more than 10% of buffer duration too early
219						// TODO: zerofill buffer
220						printf("MAJOR glitch, buffer too early, time delta "
221							"%" B_PRIdBIGTIME "\n", fLastDataAvailableTime
222							- start);
223					}
224				}
225			}
226		}
227	}
228
229//	printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n",
230//		start,
231//		start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
232//		frames_per_buffer(fInput.format.u.raw_audio)), offset,
233//		offset + out_frames);
234	if (offset + out_frames > fMixBufferFrameCount) {
235		int out_frames1 = fMixBufferFrameCount - offset;
236		int out_frames2 = out_frames - out_frames1;
237		int in_frames1 = (out_frames1 * in_frames) / out_frames;
238		int in_frames2 = in_frames - in_frames1;
239
240//		printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at "
241//			"frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(),
242//			start,
243//			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
244//			frames_per_buffer(fInput.format.u.raw_audio)), offset,
245//			offset + out_frames1 - 1, 0, out_frames2 - 1);
246		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at "
247			"frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(),
248			start,
249			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
250			frames_per_buffer(fInput.format.u.raw_audio)), offset,
251			offset + out_frames1 - 1, 0, out_frames2 - 1);
252		PRINT(5, "  in_frames %5d, out_frames %5d, in_frames1 %5d, "
253			"out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
254			in_frames, out_frames, in_frames1, out_frames1, in_frames2,
255			out_frames2);
256
257		fLastDataFrameWritten = out_frames2 - 1;
258
259		// convert offset from frames into bytes
260		offset *= sizeof(float) * fInputChannelCount;
261
262		for (int i = 0; i < fInputChannelCount; i++) {
263			fResampler[i]->Resample(
264				reinterpret_cast<char*>(data)
265					+ i * bytes_per_sample(fInput.format.u.raw_audio),
266				bytes_per_frame(fInput.format.u.raw_audio), in_frames1,
267				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
268					+ offset, fInputChannelCount * sizeof(float), out_frames1,
269				fInputChannelInfo[i].gain);
270
271			fResampler[i]->Resample(
272				reinterpret_cast<char*>(data)
273					+ i * bytes_per_sample(fInput.format.u.raw_audio)
274					+ in_frames1 * bytes_per_frame(fInput.format.u.raw_audio),
275				bytes_per_frame(fInput.format.u.raw_audio), in_frames2,
276				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base),
277				fInputChannelCount * sizeof(float), out_frames2,
278				fInputChannelInfo[i].gain);
279
280		}
281	} else {
282//		printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at "
283//			"frames %ld to %ld\n", fCore->fTimeSource->Now(), start,
284//			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
285//			frames_per_buffer(fInput.format.u.raw_audio)), offset,
286//			offset + out_frames - 1);
287		PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at "
288			"frames %ld to %ld\n", fCore->fTimeSource->Now(), start,
289			start + duration_for_frames(fInput.format.u.raw_audio.frame_rate,
290			frames_per_buffer(fInput.format.u.raw_audio)), offset,
291			offset + out_frames - 1);
292		PRINT(5, "  in_frames %5d, out_frames %5d\n", in_frames, out_frames);
293
294		fLastDataFrameWritten = offset + out_frames - 1;
295		// convert offset from frames into bytes
296		offset *= sizeof(float) * fInputChannelCount;
297		for (int i = 0; i < fInputChannelCount; i++) {
298			fResampler[i]->Resample(
299				reinterpret_cast<char*>(data)
300					+ i * bytes_per_sample(fInput.format.u.raw_audio),
301				bytes_per_frame(fInput.format.u.raw_audio), in_frames,
302				reinterpret_cast<char*>(fInputChannelInfo[i].buffer_base)
303					+ offset, fInputChannelCount * sizeof(float),
304				out_frames, fInputChannelInfo[i].gain);
305		}
306	}
307	fLastDataAvailableTime = start + buffer_duration;
308}
309
310
311void
312MixerInput::UpdateResamplingAlgorithm()
313{
314	if (fResampler != NULL) {
315		for (int i = 0; i < fInputChannelCount; i++)
316			delete fResampler[i];
317		delete[] fResampler;
318	}
319	// create resamplers
320	fResampler = new Resampler*[fInputChannelCount];
321	for (int i = 0; i < fInputChannelCount; i++) {
322		switch (fCore->Settings()->ResamplingAlgorithm()) {
323			case 2:
324				fResampler[i] = new Interpolate(
325					fInput.format.u.raw_audio.format,
326					media_raw_audio_format::B_AUDIO_FLOAT);
327				break;
328			default:
329				fResampler[i] = new Resampler(
330					fInput.format.u.raw_audio.format,
331					media_raw_audio_format::B_AUDIO_FLOAT);
332		}
333	}
334}
335
336
337int
338MixerInput::GetInputChannelCount()
339{
340	return fInputChannelCount;
341}
342
343
344void
345MixerInput::AddInputChannelDestination(int channel, int destination_type)
346{
347	uint32 mask = ChannelTypeToChannelMask(destination_type);
348
349	if (channel < 0 || channel >= fInputChannelCount)
350		return;
351
352	// test if it is already set
353	if (fInputChannelInfo[channel].destination_mask & mask)
354		return;
355
356	// verify that no other channel has id
357	if (-1 != GetInputChannelForDestination(destination_type)) {
358		ERROR("MixerInput::AddInputChannelDestination: destination_type %d "
359			"already assigned to channel %d\n", destination_type,
360			GetInputChannelForDestination(destination_type));
361		return;
362	}
363
364	// add it to specified channel
365	fInputChannelInfo[channel].destination_mask |= mask;
366
367	fUserOverridesChannelDestinations = true;
368	_UpdateInputChannelDestinations();
369}
370
371
372void
373MixerInput::RemoveInputChannelDestination(int channel, int destination_type)
374{
375	uint32 mask = ChannelTypeToChannelMask(destination_type);
376
377	if (channel < 0 || channel >= fInputChannelCount)
378		return;
379
380	// test if it is really set
381	if ((fInputChannelInfo[channel].destination_mask & mask) == 0)
382		return;
383
384	// remove it from specified channel
385	fInputChannelInfo[channel].destination_mask &= ~mask;
386
387	fUserOverridesChannelDestinations = true;
388	_UpdateInputChannelDestinations();
389}
390
391
392bool
393MixerInput::HasInputChannelDestination(int channel, int destination_type)
394{
395	if (channel < 0 || channel >= fInputChannelCount)
396		return false;
397	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
398		return false;
399	return fInputChannelInfo[channel].destination_mask
400		& ChannelTypeToChannelMask(destination_type);
401}
402
403
404int
405MixerInput::GetInputChannelForDestination(int destination_type)
406{
407	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
408		return -1;
409	uint32 mask = ChannelTypeToChannelMask(destination_type);
410	for (int chan = 0; chan < fInputChannelCount; chan++) {
411		if (fInputChannelInfo[chan].destination_mask & mask)
412			return chan;
413	}
414	return -1;
415}
416
417
418int
419MixerInput::GetInputChannelType(int channel)
420{
421	if (channel < 0 || channel >= fInputChannelCount)
422		return 0;
423	return GetChannelType(channel, fInputChannelMask);
424}
425
426
427void
428MixerInput::SetInputChannelGain(int channel, float gain)
429{
430	if (channel < 0 || channel >= fInputChannelCount)
431		return;
432	if (gain < 0.0f)
433		gain = 0.0f;
434
435	fInputChannelInfo[channel].gain = gain;
436}
437
438
439float
440MixerInput::GetInputChannelGain(int channel)
441{
442	if (channel < 0 || channel >= fInputChannelCount)
443		return 0.0f;
444	return fInputChannelInfo[channel].gain;
445}
446
447
448void
449MixerInput::_UpdateInputChannelDestinationMask()
450{
451	// is the user already messed with the assignmens, don't do anything.
452	if (fUserOverridesChannelDestinations)
453		return;
454
455	TRACE("_UpdateInputChannelDestinationMask: enter\n");
456
457	// first apply a 1:1 mapping
458	for (int i = 0; i < fInputChannelCount; i++) {
459		fInputChannelInfo[i].destination_mask = GetChannelMask(i,
460			fInputChannelMask);
461	}
462
463	// specialize this, depending on the available physical output channels
464	if (fCore->OutputChannelCount() <= 2) {
465		// less or equal two channels
466		if (fInputChannelCount == 1
467			&& (GetChannelMask(0, fInputChannelMask)
468				& (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
469			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
470		}
471	} else {
472		// more than two channel output card
473		if (fInputChannelCount == 1
474			&& (GetChannelMask(0, fInputChannelMask)
475				& (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) {
476			fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO;
477		}
478		if (fInputChannelCount == 2
479			&& (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) {
480			fInputChannelInfo[0].destination_mask
481				= B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
482		}
483		if (fInputChannelCount == 2
484			&& (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) {
485			fInputChannelInfo[0].destination_mask
486				= B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
487		}
488		if (fInputChannelCount == 2
489			&& (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) {
490			fInputChannelInfo[1].destination_mask
491				= B_CHANNEL_LEFT | B_CHANNEL_REARLEFT;
492		}
493		if (fInputChannelCount == 2
494			&& (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) {
495			fInputChannelInfo[1].destination_mask
496				= B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT;
497		}
498	}
499
500	for (int i = 0; i < fInputChannelCount; i++) {
501		TRACE("_UpdateInputChannelDestinationMask: input channel %d, "
502			"destination_mask 0x%08lX, base %p, gain %.3f\n", i,
503			fInputChannelInfo[i].destination_mask,
504			fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
505	}
506	TRACE("_UpdateInputChannelDestinationMask: leave\n");
507}
508
509
510void
511MixerInput::_UpdateInputChannelDestinations()
512{
513	int channel_count;
514	uint32 all_bits;
515	uint32 mask;
516
517	TRACE("_UpdateInputChannelDestinations: enter\n");
518	for (int i = 0; i < fInputChannelCount; i++) {
519		TRACE("_UpdateInputChannelDestinations: input channel %d, "
520			"destination_mask 0x%08lX, base %p, gain %.3f\n", i,
521			fInputChannelInfo[i].destination_mask,
522			fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain);
523	}
524
525	all_bits = 0;
526	for (int i = 0; i < fInputChannelCount; i++)
527		all_bits |= fInputChannelInfo[i].destination_mask;
528
529	TRACE("_UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits);
530
531	channel_count = count_nonzero_bits(all_bits);
532	TRACE("_UpdateInputChannelDestinations: %d input channels, %d mixer "
533		"channels (%d old)\n", fInputChannelCount, channel_count,
534		fMixerChannelCount);
535	if (channel_count != fMixerChannelCount) {
536		delete [] fMixerChannelInfo;
537		fMixerChannelInfo = new mixer_chan_info[channel_count];
538		fMixerChannelCount = channel_count;
539	}
540
541	// assign each mixer channel one type
542	// and the gain from the fChannelTypeGain[]
543	mask = 1;
544	for (int i = 0; i < fMixerChannelCount; i++) {
545		while (mask != 0 && (all_bits & mask) == 0)
546			mask <<= 1;
547		fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask);
548		fMixerChannelInfo[i].destination_gain
549			= fChannelTypeGain[fMixerChannelInfo[i].destination_type];
550		mask <<= 1;
551	}
552
553	// assign buffer_base pointer for each mixer channel
554	for (int i = 0; i < fMixerChannelCount; i++) {
555		int j;
556		for (j = 0; j < fInputChannelCount; j++) {
557			if (fInputChannelInfo[j].destination_mask
558					& ChannelTypeToChannelMask(
559						fMixerChannelInfo[i].destination_type)) {
560				fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j]
561					: 0;
562				break;
563			}
564		}
565		if (j == fInputChannelCount) {
566			ERROR("buffer assignment failed for mixer chan %d\n", i);
567			fMixerChannelInfo[i].buffer_base = fMixBuffer;
568		}
569	}
570
571	for (int i = 0; i < fMixerChannelCount; i++) {
572		TRACE("_UpdateInputChannelDestinations: mixer channel %d, type %2d, "
573			"base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type,
574			fMixerChannelInfo[i].buffer_base,
575			fMixerChannelInfo[i].destination_gain);
576	}
577
578	TRACE("_UpdateInputChannelDestinations: leave\n");
579}
580
581
582// Note: The following code is outcommented on purpose
583// and is about to be modified at a later point
584/*
585void
586MixerInput::SetInputChannelDestinationGain(int channel, int destination_type,
587	float gain)
588{
589	TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d,
590		gain %.4f\n", channel, destination_type, gain);
591	// we don't need the channel, as each destination_type can only exist
592	// once for each MixerInput, but we use it for parameter validation
593	// and to have a interface similar to MixerOutput
594	if (channel < 0 || channel >= fMixerChannelCount)
595		return;
596	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
597		return;
598	if (gain < 0.0f)
599		gain = 0.0f;
600	fChannelTypeGain[destination_type] = gain;
601	for (int i = 0; i < fMixerChannelCount; i++) {
602		if (fMixerChannelInfo[i].destination_type == destination_type) {
603			fMixerChannelInfo[i].destination_gain = gain;
604			return;
605		}
606	}
607}
608
609
610float
611MixerInput::GetInputChannelDestinationGain(int channel, int destination_type)
612{
613	// we don't need the channel, as each destination_type can only exist
614	// once for each MixerInput, but we use it for parameter validation
615	// and to have a interface similar to MixerOutput
616	if (channel < 0 || channel >= fMixerChannelCount)
617		return 0.0f;
618	if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES)
619		return 0.0f;
620	return fChannelTypeGain[destination_type];
621}
622*/
623
624
625void
626MixerInput::SetMixerChannelGain(int mixer_channel, float gain)
627{
628	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
629		return;
630	if (gain < 0.0f)
631		gain = 0.0f;
632
633	fMixerChannelInfo[mixer_channel].destination_gain = gain;
634	fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain;
635}
636
637
638float
639MixerInput::GetMixerChannelGain(int mixer_channel)
640{
641	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
642		return 0.0;
643	return fMixerChannelInfo[mixer_channel].destination_gain;
644}
645
646
647int
648MixerInput::GetMixerChannelType(int mixer_channel)
649{
650	if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount)
651		return -1;
652	return fMixerChannelInfo[mixer_channel].destination_type;
653}
654
655
656void
657MixerInput::SetEnabled(bool yesno)
658{
659	fEnabled = yesno;
660}
661
662
663bool
664MixerInput::IsEnabled()
665{
666	return fEnabled;
667}
668
669
670void
671MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
672{
673	TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n",
674		framerate, frames);
675
676	fMixBufferFrameRate = framerate;
677	fDebugMixBufferFrames = frames;
678
679	// frames and/or framerate can be 0 (if no output is connected)
680	if (framerate == 0 || frames == 0) {
681		if (fMixBuffer != NULL) {
682			rtm_free(fMixBuffer);
683			fMixBuffer = NULL;
684		}
685		for (int i = 0; i < fInputChannelCount; i++)
686			fInputChannelInfo[i].buffer_base = 0;
687		fMixBufferFrameCount = 0;
688
689		_UpdateInputChannelDestinationMask();
690		_UpdateInputChannelDestinations();
691		return;
692	}
693
694	// make fMixBufferFrameCount an integral multiple of frames,
695	// but at least 3 times duration of our input buffer
696	// and at least 2 times duration of the output buffer
697	bigtime_t inputBufferLength  = duration_for_frames(
698		fInput.format.u.raw_audio.frame_rate,
699		frames_per_buffer(fInput.format.u.raw_audio));
700	bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
701	bigtime_t mixerBufferLength
702		= max_c(3 * inputBufferLength, 2 * outputBufferLength);
703	int temp = frames_for_duration(framerate, mixerBufferLength);
704	fMixBufferFrameCount = ((temp / frames) + 1) * frames;
705
706	TRACE("  inputBufferLength    %10Ld\n", inputBufferLength);
707	TRACE("  outputBufferLength   %10Ld\n", outputBufferLength);
708	TRACE("  mixerBufferLength    %10Ld\n", mixerBufferLength);
709	TRACE("  fMixBufferFrameCount %10d\n", fMixBufferFrameCount);
710
711	ASSERT((fMixBufferFrameCount % frames) == 0);
712
713	fLastDataFrameWritten = -1;
714	fFractionalFrames = 0.0;
715
716	rtm_free(fMixBuffer);
717	rtm_delete_pool(fRtmPool);
718
719	int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
720	if (rtm_create_pool(&fRtmPool, size) != B_OK)
721		fRtmPool = NULL;
722
723	fMixBuffer = (float*)rtm_alloc(fRtmPool, size);
724	if (fMixBuffer == NULL)
725		return;
726
727	memset(fMixBuffer, 0, size);
728
729	for (int i = 0; i < fInputChannelCount; i++)
730		fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
731
732	_UpdateInputChannelDestinationMask();
733	_UpdateInputChannelDestinations();
734}
735