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