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