xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
23 MixerInput::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 
87 MixerInput::~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 
106 int32
107 MixerInput::ID()
108 {
109 	return fInput.destination.id;
110 }
111 
112 
113 media_input&
114 MixerInput::MediaInput()
115 {
116 	return fInput;
117 }
118 
119 
120 void
121 MixerInput::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 
311 void
312 MixerInput::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 
337 int
338 MixerInput::GetInputChannelCount()
339 {
340 	return fInputChannelCount;
341 }
342 
343 
344 void
345 MixerInput::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 
372 void
373 MixerInput::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 
392 bool
393 MixerInput::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 
404 int
405 MixerInput::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 
418 int
419 MixerInput::GetInputChannelType(int channel)
420 {
421 	if (channel < 0 || channel >= fInputChannelCount)
422 		return 0;
423 	return GetChannelType(channel, fInputChannelMask);
424 }
425 
426 
427 void
428 MixerInput::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 
439 float
440 MixerInput::GetInputChannelGain(int channel)
441 {
442 	if (channel < 0 || channel >= fInputChannelCount)
443 		return 0.0f;
444 	return fInputChannelInfo[channel].gain;
445 }
446 
447 
448 void
449 MixerInput::_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 
510 void
511 MixerInput::_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 /*
585 void
586 MixerInput::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 
610 float
611 MixerInput::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 
625 void
626 MixerInput::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 
638 float
639 MixerInput::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 
647 int
648 MixerInput::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 
656 void
657 MixerInput::SetEnabled(bool yesno)
658 {
659 	fEnabled = yesno;
660 }
661 
662 
663 bool
664 MixerInput::IsEnabled()
665 {
666 	return fEnabled;
667 }
668 
669 
670 void
671 MixerInput::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