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