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