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