xref: /haiku/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
1 /*
2  * Copyright 2002 David Shipman,
3  * Copyright 2003-2007 Marcus Overhagen
4  * Copyright 2007-2011 Haiku Inc. All rights reserved.
5  *
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include "AudioMixer.h"
11 
12 #include <math.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <Buffer.h>
18 #include <Catalog.h>
19 #include <FindDirectory.h>
20 #include <MediaDefs.h>
21 #include <MediaRoster.h>
22 #include <ParameterWeb.h>
23 #include <Path.h>
24 #include <RealtimeAlloc.h>
25 #include <TimeSource.h>
26 
27 #include "MixerCore.h"
28 #include "MixerInput.h"
29 #include "MixerOutput.h"
30 #include "MixerUtils.h"
31 
32 
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "AudioMixer"
35 
36 
37 // the range of the gain sliders (in dB)
38 #define DB_MAX	18.0
39 #define DB_MIN	-60.0
40 // when using non linear sliders, we use a power function with
41 #define DB_EXPONENT_POSITIVE 1.4	// for dB values > 0
42 #define DB_EXPONENT_NEGATIVE 1.8	// for dB values < 0
43 
44 #define USE_MEDIA_FORMAT_WORKAROUND 1
45 
46 #define DB_TO_GAIN(db)			dB_to_Gain((db))
47 #define GAIN_TO_DB(gain)		Gain_to_dB((gain))
48 #define PERCENT_TO_GAIN(pct)	((pct) / 100.0)
49 #define GAIN_TO_PERCENT(gain)	((gain)  * 100.0)
50 
51 // the id is encoded with 16 bits
52 // then chan and src (or dst) are encoded with 6 bits
53 // the unique number with 4 bits
54 // the PARAM_ETC etc is encoded with 26 bits
55 #define PARAM_SRC_ENABLE(id, chan, src)		(((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x1)
56 #define PARAM_SRC_GAIN(id, chan, src)		(((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x2)
57 #define PARAM_DST_ENABLE(id, chan, dst)		(((id) << 16) | ((chan) << 10) | ((dst) << 4) | 0x3)
58 #define PARAM_ETC(etc)						(((etc) << 16) | 0x4)
59 #define PARAM_SRC_STR(id, chan)				(((id) << 16) | ((chan) << 10) | 0x5)
60 #define PARAM_DST_STR(id, chan)				(((id) << 16) | ((chan) << 10) | 0x6)
61 #define PARAM_MUTE(id)						(((id) << 16) | 0x7)
62 #define PARAM_GAIN(id)						(((id) << 16) | 0x8)
63 #define PARAM_BALANCE(id)					(((id) << 16) | 0x9)
64 #define PARAM_STR1(id)						(((id) << 16) | ((1) << 10) | 0xa)
65 #define PARAM_STR2(id)						(((id) << 16) | ((2) << 10) | 0xa)
66 #define PARAM_STR3(id)						(((id) << 16) | ((3) << 10) | 0xa)
67 #define PARAM_STR4(id)						(((id) << 16) | ((4) << 10) | 0xa)
68 #define PARAM_STR5(id)						(((id) << 16) | ((5) << 10) | 0xa)
69 #define PARAM_STR6(id)						(((id) << 16) | ((6) << 10) | 0xa)
70 #define PARAM_STR7(id)						(((id) << 16) | ((7) << 10) | 0xa)
71 
72 #define PARAM(id)							((id) >> 16)
73 #define ETC(id)								((id) >> 16)
74 #define PARAM_CHAN(id)						(((id) >> 10) & 0x3f)
75 #define PARAM_SRC(id)						(((id) >> 4) & 0x3f)
76 #define PARAM_DST(id)						(((id) >> 4) & 0x3f)
77 #define PARAM_IS_SRC_ENABLE(id)				(((id) & 0xf) == 0x1)
78 #define PARAM_IS_SRC_GAIN(id)				(((id) & 0xf) == 0x2)
79 #define PARAM_IS_DST_ENABLE(id)				(((id) & 0xf) == 0x3)
80 #define PARAM_IS_ETC(id)					(((id) & 0xf) == 0x4)
81 #define PARAM_IS_MUTE(id)					(((id) & 0xf) == 0x7)
82 #define PARAM_IS_GAIN(id)					(((id) & 0xf) == 0x8)
83 #define PARAM_IS_BALANCE(id)				(((id) & 0xf) == 0x9)
84 
85 #if USE_MEDIA_FORMAT_WORKAROUND
86 static void
87 multi_audio_format_specialize(media_multi_audio_format *format,
88 	const media_multi_audio_format *other);
89 #endif
90 
91 #define FORMAT_USER_DATA_TYPE 		0x7294a8f3
92 #define FORMAT_USER_DATA_MAGIC_1	0xc84173bd
93 #define FORMAT_USER_DATA_MAGIC_2	0x4af62b7d
94 
95 
96 const static bigtime_t kMaxLatency = 150000;
97 	// 150 ms is the maximum latency we publish
98 
99 const bigtime_t kMinMixingTime = 3500;
100 const bigtime_t kMaxJitter = 1500;
101 
102 
103 AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
104 	:
105 	BMediaNode("Audio Mixer"),
106 	BBufferConsumer(B_MEDIA_RAW_AUDIO),
107 	BBufferProducer(B_MEDIA_RAW_AUDIO),
108 	BControllable(),
109 	BMediaEventLooper(),
110 	fAddOn(addOn),
111 	fCore(new MixerCore(this)),
112 	fWeb(NULL),
113 	fBufferGroup(NULL),
114 	fDownstreamLatency(1),
115 	fInternalLatency(1),
116 	fDisableStop(false),
117 	fLastLateNotification(0),
118 	fLastLateness(0)
119 {
120 	BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
121 
122 	// this is the default format used for all wildcard format SpecializeTo()s
123 	fDefaultFormat.type = B_MEDIA_RAW_AUDIO;
124 	fDefaultFormat.u.raw_audio.frame_rate = 96000;
125 	fDefaultFormat.u.raw_audio.channel_count = 2;
126 	fDefaultFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
127 	fDefaultFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
128 	fDefaultFormat.u.raw_audio.buffer_size = 4096;
129 	fDefaultFormat.u.raw_audio.channel_mask = 0;
130 	fDefaultFormat.u.raw_audio.valid_bits = 0;
131 	fDefaultFormat.u.raw_audio.matrix_mask = 0;
132 
133 	if (isSystemMixer) {
134 		// to get persistent settings, assign a settings file
135 		BPath path;
136 		if (B_OK != find_directory (B_USER_SETTINGS_DIRECTORY, &path))
137 			path.SetTo("/boot/home/config/settings/");
138 		path.Append("System Audio Mixer");
139 		fCore->Settings()->SetSettingsFile(path.Path());
140 
141 		// disable stop on the auto started (system) mixer
142 		DisableNodeStop();
143 	}
144 
145 	ApplySettings();
146 }
147 
148 
149 AudioMixer::~AudioMixer()
150 {
151 	BMediaEventLooper::Quit();
152 	SetParameterWeb(NULL);
153 
154 	// stop the mixer
155 	fCore->Lock();
156 	fCore->Stop();
157 	fCore->Unlock();
158 
159 	// disconnect all nodes from the mixer
160 	// XXX todo
161 
162 	delete fCore;
163 	delete fBufferGroup;
164 
165 	DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0);
166 }
167 
168 
169 void
170 AudioMixer::ApplySettings()
171 {
172 	fCore->Lock();
173 	fCore->SetOutputAttenuation(fCore->Settings()->AttenuateOutput() ? 0.708 : 1.0);
174 	fCore->Unlock();
175 }
176 
177 
178 void
179 AudioMixer::DisableNodeStop()
180 {
181 	fDisableStop = true;
182 }
183 
184 
185 //	#pragma mark - BMediaNode methods
186 
187 
188 void
189 AudioMixer::Stop(bigtime_t performance_time, bool immediate)
190 {
191 	if (fDisableStop) {
192 		TRACE("AudioMixer STOP is disabled\n");
193 		return;
194 	} else {
195 		BMediaEventLooper::Stop(performance_time, immediate);
196 	}
197 }
198 
199 
200 BMediaAddOn*
201 AudioMixer::AddOn(int32 *internal_id) const
202 {
203 	*internal_id = 0;
204 	return fAddOn;
205 }
206 
207 
208 //	#pragma mark - BBufferConsumer methods
209 
210 
211 status_t
212 AudioMixer::HandleMessage(int32 message, const void *data, size_t size)
213 {
214 	// since we're using a mediaeventlooper, there shouldn't be any messages
215 	// except the message we are using to schedule output events for the
216 	// process thread.
217 
218 	if (message == MIXER_SCHEDULE_EVENT) {
219 		RealTimeQueue()->AddEvent(*(const media_timed_event*)data);
220 		return B_OK;
221 	}
222 
223 	return B_ERROR;
224 }
225 
226 
227 status_t
228 AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat)
229 {
230 	PRINT_FORMAT("AudioMixer::AcceptFormat: ", *ioFormat);
231 
232 	// check that the specified format is reasonable for the specified destination, and
233 	// fill in any wildcard fields for which our BBufferConsumer has specific requirements.
234 
235 	// we have multiple inputs with different IDs, but
236 	// the port number must match our ControlPort()
237 	if (dest.port != ControlPort())
238 		return B_MEDIA_BAD_DESTINATION;
239 
240 	// specialize to raw audio format if necessary
241 	if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE)
242 		ioFormat->type = B_MEDIA_RAW_AUDIO;
243 
244 	// we require a raw audio format
245 	if (ioFormat->type != B_MEDIA_RAW_AUDIO)
246 		return B_MEDIA_BAD_FORMAT;
247 
248 	// We do not have special requirements, but just in case
249 	// another mixer is connecting to us and may need a hint
250 	// to create a connection at optimal frame rate and
251 	// channel count, we place this information in the user_data
252 	fCore->Lock();
253 	MixerOutput *output = fCore->Output();
254 	uint32 channel_count = output ? output->MediaOutput().format.u.raw_audio.channel_count : 0;
255 	float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 0.0;
256 	fCore->Unlock();
257 	ioFormat->user_data_type = FORMAT_USER_DATA_TYPE;
258 	*(uint32 *)&ioFormat->user_data[0] = FORMAT_USER_DATA_MAGIC_1;
259 	*(uint32 *)&ioFormat->user_data[4] = channel_count;
260 	*(float *)&ioFormat->user_data[20] = frame_rate;
261 	*(uint32 *)&ioFormat->user_data[44] = FORMAT_USER_DATA_MAGIC_2;
262 
263 	return B_OK;
264 }
265 
266 
267 status_t
268 AudioMixer::GetNextInput(int32 *cookie, media_input *out_input)
269 {
270 	TRACE("AudioMixer::GetNextInput\n");
271 
272 	// our 0th input is always a wildcard and free one
273 	if (*cookie == 0) {
274 		out_input->node = Node();
275 		out_input->source = media_source::null;
276 		out_input->destination.port = ControlPort();
277 		out_input->destination.id = 0;
278 		memset(&out_input->format, 0, sizeof(out_input->format));
279 		out_input->format.type = B_MEDIA_RAW_AUDIO;
280 		strcpy(out_input->name, "Free Input");
281 		*cookie += 1;
282 		return B_OK;
283 	}
284 
285 	// the other inputs are the currently connected ones
286 	fCore->Lock();
287 	MixerInput *input;
288 	input = fCore->Input(*cookie - 1);
289 	if (!input) {
290 		fCore->Unlock();
291 		return B_BAD_INDEX;
292 	}
293 	*out_input = input->MediaInput();
294 	*cookie += 1;
295 	fCore->Unlock();
296 	return B_OK;
297 }
298 
299 
300 void
301 AudioMixer::DisposeInputCookie(int32 cookie)
302 {
303 	// nothing to do
304 }
305 
306 
307 void
308 AudioMixer::BufferReceived(BBuffer *buffer)
309 {
310 
311 	if (buffer->Header()->type == B_MEDIA_PARAMETERS) {
312 		TRACE("Control Buffer Received\n");
313 		ApplyParameterData(buffer->Data(), buffer->SizeUsed());
314 		buffer->Recycle();
315 		return;
316 	}
317 
318 	//PRINT(4, "buffer received at %12Ld, should arrive at %12Ld, delta %12Ld\n", TimeSource()->Now(), buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time);
319 
320 	// to receive the buffer at the right time,
321 	// push it through the event looper
322 	media_timed_event event(buffer->Header()->start_time,
323 		BTimedEventQueue::B_HANDLE_BUFFER, buffer,
324 		BTimedEventQueue::B_RECYCLE_BUFFER);
325 	EventQueue()->AddEvent(event);
326 }
327 
328 
329 void
330 AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
331 {
332 	bigtime_t variation = 0;
333 	if (lateness > fLastLateness)
334 		variation = lateness-fLastLateness;
335 
336 	if (variation > kMaxJitter) {
337 		TRACE("AudioMixer: Dequeued input buffer %" B_PRIdBIGTIME
338 			" usec late\n", lateness);
339 		if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION
340 			|| RunMode() == B_INCREASE_LATENCY) {
341 			TRACE("AudioMixer: sending notify\n");
342 
343 			// Build a media_source out of the header data
344 			media_source source = media_source::null;
345 			source.port = buffer->Header()->source_port;
346 			source.id = buffer->Header()->source;
347 
348 			NotifyLateProducer(source, variation, TimeSource()->Now());
349 
350 			if (RunMode() == B_DROP_DATA) {
351 				TRACE("AudioMixer: dropping buffer\n");
352 				return;
353 			}
354 		}
355 	}
356 
357 	fLastLateness = lateness;
358 
359 	fCore->Lock();
360 	fCore->BufferReceived(buffer, lateness);
361 	fCore->Unlock();
362 }
363 
364 
365 void
366 AudioMixer::ProducerDataStatus(const media_destination& for_whom,
367 	int32 status, bigtime_t at_performance_time)
368 {
369 /*
370 	if (IsValidDest(for_whom))
371 	{
372 		media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
373 			(void *)(&for_whom), BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
374 		EventQueue()->AddEvent(event);
375 
376 		// FIX_THIS
377 		// the for_whom destination is not being sent correctly - verify in HandleEvent loop
378 
379 	}
380 */
381 }
382 
383 
384 status_t
385 AudioMixer::GetLatencyFor(const media_destination &for_whom,
386 	bigtime_t *out_latency, media_node_id *out_timesource)
387 {
388 	// we have multiple inputs with different IDs, but
389 	// the port number must match our ControlPort()
390 	if (for_whom.port != ControlPort())
391 		return B_MEDIA_BAD_DESTINATION;
392 
393 	// return our event latency - this includes our internal + downstream
394 	// latency, but _not_ the scheduling latency
395 	*out_latency = EventLatency();
396 	*out_timesource = TimeSource()->ID();
397 
398 	printf("AudioMixer::GetLatencyFor %" B_PRIdBIGTIME ", timesource is %"
399 		B_PRId32 "\n", *out_latency, *out_timesource);
400 
401 	return B_OK;
402 }
403 
404 
405 status_t
406 AudioMixer::Connected(const media_source &producer,
407 	const media_destination &where, const media_format &with_format,
408 	media_input *out_input)
409 {
410 	PRINT_FORMAT("AudioMixer::Connected: ", with_format);
411 
412 	// workaround for a crashing bug in RealPlayer.  to be proper, RealPlayer's
413 	// BBufferProducer::PrepareToConnect() should have removed all wildcards.
414 	if (out_input->format.u.raw_audio.frame_rate == 0) {
415 		fprintf(stderr, "Audio Mixer Warning: "
416 			"Producer (port %" B_PRId32 ", id %" B_PRId32 ") connected with "
417 			"frame_rate=0\n", producer.port, producer.id);
418 		MixerOutput *output = fCore->Output();
419 		float frame_rate = output
420 			? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f;
421 		out_input->format.u.raw_audio.frame_rate = frame_rate;
422 	}
423 
424 	// a BBufferProducer is connecting to our BBufferConsumer
425 
426 	// incoming connections should always have an incoming ID=0,
427 	// and the port number must match our ControlPort()
428 	if (where.id != 0 || where.port != ControlPort())
429 		return B_MEDIA_BAD_DESTINATION;
430 
431 	fCore->Lock();
432 
433 	// we assign a new id (!= 0) to the newly created input
434 	out_input->destination.id = fCore->CreateInputID();
435 
436 	// We need to make sure that the outInput's name field contains a valid
437 	// name, the name given the connection by the producer may still be an
438 	// empty string.
439 	// if the input has no name, assign one
440 	if (strlen(out_input->name) == 0) {
441 		sprintf(out_input->name, "Input %" B_PRId32,
442 			out_input->destination.id);
443 	}
444 
445 	// add a new input to the mixer engine
446 	MixerInput *input;
447 	input = fCore->AddInput(*out_input);
448 
449 	fCore->Settings()->LoadConnectionSettings(input);
450 
451 	fCore->Unlock();
452 
453 	// If we want the producer to use a specific BBufferGroup, we now need
454 	// to call BMediaRoster::SetOutputBuffersFor() here to set the producer's
455 	// buffer group.
456 	// But we have no special buffer requirements anyway...
457 
458 	UpdateParameterWeb();
459 
460 	return B_OK;
461 }
462 
463 
464 void
465 AudioMixer::Disconnected(const media_source &producer,
466 	const media_destination &where)
467 {
468 	// One of our inputs has been disconnected
469 
470 	// check if it is really belongs to us
471 	if (where.port != ControlPort()) {
472 		TRACE("AudioMixer::Disconnected wrong input port\n");
473 		return;
474 	}
475 
476 	fCore->Lock();
477 
478 	if (!fCore->RemoveInput(where.id)) {
479 		TRACE("AudioMixer::Disconnected can't remove input\n");
480 	}
481 
482 	fCore->Unlock();
483 	UpdateParameterWeb();
484 }
485 
486 
487 status_t
488 AudioMixer::FormatChanged(const media_source &producer,
489 	const media_destination &consumer, int32 change_tag,
490 	const media_format &format)
491 {
492 	// at some point in the future (indicated by change_tag and RequestCompleted()),
493 	// we will receive buffers in a different format
494 
495 	TRACE("AudioMixer::FormatChanged\n");
496 
497 	if (consumer.port != ControlPort() || consumer.id == 0)
498 		return B_MEDIA_BAD_DESTINATION;
499 
500 	if (fCore->Settings()->RefuseInputFormatChange()) {
501 		TRACE("AudioMixer::FormatChanged: input format change refused\n");
502 		return B_NOT_ALLOWED;
503 	}
504 
505 	// TODO: We should not apply the format change at this point
506 	// TODO: At the moment, this is not implemented at the moment and will just
507 	// crash the media_server.
508 	return B_NOT_SUPPORTED;
509 
510 	// tell core about format change
511 	fCore->Lock();
512 	fCore->InputFormatChanged(consumer.id, format.u.raw_audio);
513 	fCore->Unlock();
514 
515 	return B_OK;
516 }
517 
518 
519 //	#pragma mark - BBufferProducer methods
520 
521 
522 status_t
523 AudioMixer::FormatSuggestionRequested(media_type type, int32 quality,
524 	media_format *format)
525 {
526 	TRACE("AudioMixer::FormatSuggestionRequested\n");
527 
528 	// BBufferProducer function, a downstream consumer
529 	// is asking for our output format
530 
531 	if (type != B_MEDIA_RAW_AUDIO && type != B_MEDIA_UNKNOWN_TYPE)
532 		return B_MEDIA_BAD_FORMAT;
533 
534 	// we can produce any (wildcard) raw audio format
535 	memset(format, 0, sizeof(*format));
536 	format->type = B_MEDIA_RAW_AUDIO;
537 	return B_OK;
538 }
539 
540 
541 status_t
542 AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
543 {
544 	// BBufferProducer function, we implement this function to verify that the
545 	// proposed media_format is suitable for the specified output. If any fields
546 	// in the format are wildcards, and we have a specific requirement, adjust
547 	// those fields to match our requirements before returning.
548 
549 	TRACE("AudioMixer::FormatProposal\n");
550 
551 	// we only have one output (id=0, port=ControlPort())
552 	if (output.id != 0 || output.port != ControlPort())
553 		return B_MEDIA_BAD_SOURCE;
554 
555 	// specialize to raw audio format if necessary
556 	if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE)
557 		ioFormat->type = B_MEDIA_RAW_AUDIO;
558 
559 	// we require a raw audio format
560 	if (ioFormat->type != B_MEDIA_RAW_AUDIO)
561 		return B_MEDIA_BAD_FORMAT;
562 
563 	return B_OK;
564 }
565 
566 /*!	If the format isn't good, put a good format into *io_format and return error
567 	If format has wildcard, specialize to what you can do (and change).
568 	If you can change the format, return OK.
569 	The request comes from your destination sychronously, so you cannot ask it
570 	whether it likes it -- you should assume it will since it asked.
571 */
572 status_t
573 AudioMixer::FormatChangeRequested(const media_source &source,
574 	const media_destination &destination, media_format *io_format,
575 	int32 *_deprecated_)
576 {
577 	// the downstream consumer node (soundcard) requested that we produce
578 	// another format, we need to check if the format is acceptable and
579 	// remove any wildcards before returning OK.
580 
581 	TRACE("AudioMixer::FormatChangeRequested\n");
582 
583 	if (fCore->Settings()->RefuseOutputFormatChange()) {
584 		TRACE("AudioMixer::FormatChangeRequested: output format change refused\n");
585 		return B_ERROR;
586 	}
587 
588 	fCore->Lock();
589 
590 	status_t status = B_OK;
591 	BBufferGroup *group = NULL;
592 	MixerOutput *output = fCore->Output();
593 	if (!output) {
594 		ERROR("AudioMixer::FormatChangeRequested: no output\n");
595 		goto err;
596 	}
597 	if (source != output->MediaOutput().source) {
598 		ERROR("AudioMixer::FormatChangeRequested: wrong output source\n");
599 		goto err;
600 	}
601 	if (destination != output->MediaOutput().destination) {
602 		ERROR("AudioMixer::FormatChangeRequested: wrong output destination "
603 			"(port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port,
604 			destination.id, output->MediaOutput().destination.port,
605 			output->MediaOutput().destination.id);
606 		if (destination.port == output->MediaOutput().destination.port
607 			&& destination.id == output->MediaOutput().destination.id + 1) {
608 			ERROR("AudioMixer::FormatChangeRequested: this might be the broken "
609 				"R5 multi audio add-on\n");
610 		}
611 		goto err;
612 	}
613 	if (io_format->type != B_MEDIA_RAW_AUDIO
614 		&& io_format->type != B_MEDIA_UNKNOWN_TYPE) {
615 		ERROR("AudioMixer::FormatChangeRequested: wrong format type\n");
616 		goto err;
617 	}
618 
619 	/* remove wildcards */
620 #if USE_MEDIA_FORMAT_WORKAROUND
621 	multi_audio_format_specialize(&io_format->u.raw_audio,
622 		&fDefaultFormat.u.raw_audio);
623 #else
624 	io_format->SpecializeTo(&fDefaultFormat);
625 #endif
626 
627 	media_node_id id;
628 	FindLatencyFor(destination, &fDownstreamLatency, &id);
629 	TRACE("AudioMixer: Downstream Latency is %" B_PRIdBIGTIME " usecs\n",
630 		fDownstreamLatency);
631 
632 	// SetDuration of one buffer
633 	SetBufferDuration(buffer_duration(io_format->u.raw_audio));
634 	TRACE("AudioMixer: buffer duration is %" B_PRIdBIGTIME " usecs\n",
635 		BufferDuration());
636 
637 	// Our internal latency is at least the length of a full output buffer
638 	fInternalLatency = BufferDuration()
639 		+ max((bigtime_t)4500, bigtime_t(0.5 * BufferDuration()));
640 	TRACE("AudioMixer: Internal latency is %" B_PRIdBIGTIME " usecs\n",
641 		fInternalLatency);
642 
643 	SetEventLatency(fDownstreamLatency + fInternalLatency);
644 
645 	// we need to inform all connected *inputs* about *our* change in latency
646 	PublishEventLatencyChange();
647 
648 	// TODO: we might need to create more buffers, to span a larger downstream
649 	// latency
650 
651 	// apply latency change
652 	fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
653 
654 	// apply format change
655 	fCore->OutputFormatChanged(io_format->u.raw_audio);
656 
657 	status = CreateBufferGroup(&group);
658 	if (status != B_OK)
659 		return status;
660 	else {
661 		delete fBufferGroup;
662 		fBufferGroup = group;
663 		fCore->SetOutputBufferGroup(fBufferGroup);
664 	}
665 
666 err:
667 	fCore->Unlock();
668 	return status;
669 }
670 
671 
672 status_t
673 AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
674 {
675 	TRACE("AudioMixer::GetNextOutput\n");
676 
677 	if (*cookie != 0)
678 		return B_BAD_INDEX;
679 
680 	fCore->Lock();
681 	MixerOutput *output = fCore->Output();
682 	if (output) {
683 		*out_output = output->MediaOutput();
684 	} else {
685 		out_output->node = Node();
686 		out_output->source.port = ControlPort();
687 		out_output->source.id = 0;
688 		out_output->destination = media_destination::null;
689 		memset(&out_output->format, 0, sizeof(out_output->format));
690 		out_output->format.type = B_MEDIA_RAW_AUDIO;
691 		strcpy(out_output->name, "Mixer Output");
692 	}
693 	fCore->Unlock();
694 
695 	*cookie += 1;
696 	return B_OK;
697 }
698 
699 
700 status_t
701 AudioMixer::DisposeOutputCookie(int32 cookie)
702 {
703 	// nothing to do
704 	return B_OK;
705 }
706 
707 
708 status_t
709 AudioMixer::SetBufferGroup(const media_source &for_source,
710 	BBufferGroup *newGroup)
711 {
712 	TRACE("AudioMixer::SetBufferGroup\n");
713 	// the downstream consumer (soundcard) node asks us to use another
714 	// BBufferGroup (might be NULL). We only have one output (id 0)
715 	if (for_source.port != ControlPort() || for_source.id != 0)
716 		return B_MEDIA_BAD_SOURCE;
717 
718 	if (newGroup == fBufferGroup) {
719 		// we're already using this buffergroup
720 		return B_OK;
721 	}
722 
723 	fCore->Lock();
724 	if (!newGroup) {
725 		status_t status = CreateBufferGroup(&newGroup);
726 		if (status != B_OK)
727 			return status;
728 	}
729 	fCore->SetOutputBufferGroup(newGroup);
730 	delete fBufferGroup;
731 	fBufferGroup = newGroup;
732 	fCore->Unlock();
733 
734 	return B_OK;
735 }
736 
737 
738 status_t
739 AudioMixer::GetLatency(bigtime_t *out_latency)
740 {
741 	// report our *total* latency:  internal plus downstream plus scheduling
742 	*out_latency = EventLatency() + SchedulingLatency();
743 
744 	TRACE("AudioMixer::GetLatency %Ld\n", *out_latency);
745 
746 	return B_OK;
747 }
748 
749 
750 void
751 AudioMixer::LatencyChanged(const media_source& source,
752 	const media_destination& destination, bigtime_t new_latency, uint32 flags)
753 {
754 	if (source.port != ControlPort() || source.id != 0) {
755 		ERROR("AudioMixer::LatencyChanged: received but has wrong source "
756 			"%ld/%ld\n", source.port, source.id);
757 		return;
758 	}
759 
760 	TRACE("AudioMixer::LatencyChanged: downstream latency from %ld/%ld to "
761 		"%ld/%ld changed from %Ld to %Ld\n", source.port, source.id,
762 		destination.port, destination.id, fDownstreamLatency, new_latency);
763 
764 #if DEBUG
765 	{
766 		media_node_id id;
767 		bigtime_t l;
768 		FindLatencyFor(destination, &l, &id);
769 		TRACE("AudioMixer: Reported downstream Latency is %Ld usecs\n", l);
770 	}
771 #endif
772 
773 	fDownstreamLatency = new_latency;
774 	SetEventLatency(fDownstreamLatency + fInternalLatency);
775 
776 	// XXX we might need to create more buffers, to span a larger downstream
777 	// latency
778 
779 	fCore->Lock();
780 	fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
781 	PublishEventLatencyChange();
782 	fCore->Unlock();
783 }
784 
785 status_t
786 AudioMixer::PrepareToConnect(const media_source &what,
787 	const media_destination &where, media_format *format,
788 	media_source *out_source, char *out_name)
789 {
790 	TRACE("AudioMixer::PrepareToConnect\n");
791 	// PrepareToConnect() is the second stage of format negotiations that
792 	// happens inside BMediaRoster::Connect(). At this point, the consumer's
793 	// AcceptFormat() method has been called, and that node has potentially
794 	// changed the proposed format.
795 	// It may also have left wildcards in the format. PrepareToConnect()
796 	// *must* fully specialize the format before returning!
797 	// we also create the new output connection and return it in out_source.
798 
799 	PRINT_FORMAT("AudioMixer::PrepareToConnect: suggested format", *format);
800 
801 	// avoid loop connections
802 	if (where.port == ControlPort())
803 		return B_MEDIA_BAD_SOURCE;
804 
805 	// is the source valid?
806 	if (what.port != ControlPort() || what.id != 0)
807 		return B_MEDIA_BAD_SOURCE;
808 
809 	// is the format acceptable?
810 	if (format->type != B_MEDIA_RAW_AUDIO
811 		&& format->type != B_MEDIA_UNKNOWN_TYPE) {
812 		PRINT_FORMAT("AudioMixer::PrepareToConnect: bad format", *format);
813 		return B_MEDIA_BAD_FORMAT;
814 	}
815 
816 	fCore->Lock();
817 
818 	// are we already connected?
819 	if (fCore->Output() != 0) {
820 		fCore->Unlock();
821 		ERROR("AudioMixer::PrepareToConnect: already connected\n");
822 		return B_MEDIA_ALREADY_CONNECTED;
823 	}
824 
825 	// It is possible that another mixer is connecting.
826 	// To avoid using the default format, we use one of
827 	// a) the format that it indicated as hint in the user_data,
828 	// b) the output format of the system audio mixer
829 	// c) the input format of the system DAC device
830 	// d) if everything failes, keep the wildcard
831 	if (format->u.raw_audio.channel_count == 0
832 		&& format->u.raw_audio.frame_rate < 1
833 		&& format->user_data_type == FORMAT_USER_DATA_TYPE
834 		&& *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1
835 		&& *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) {
836 		// ok, a mixer is connecting
837 		uint32 channel_count = *(uint32 *)&format->user_data[4];
838 		float frame_rate = *(float *)&format->user_data[20];
839 		if (channel_count > 0 && frame_rate > 0) {
840 			// format is good, use it
841 			format->u.raw_audio.channel_count = channel_count;
842 			format->u.raw_audio.frame_rate = frame_rate;
843 		} else {
844 			// other mixer's output is probably not connected
845 			media_node node;
846 			BMediaRoster *roster = BMediaRoster::Roster();
847 			media_output out;
848 			media_input in;
849 			int32 count;
850 			if (roster->GetAudioMixer(&node) == B_OK
851 				&& roster->GetConnectedOutputsFor(node, &out, 1, &count)
852 						== B_OK
853 				&& count == 1) {
854 				// use mixer output format
855 				format->u.raw_audio.channel_count
856 					= out.format.u.raw_audio.channel_count;
857 				format->u.raw_audio.frame_rate
858 					= out.format.u.raw_audio.frame_rate;
859 			} else if (roster->GetAudioOutput(&node) == B_OK
860 				&& roster->GetAllInputsFor(node, &in, 1, &count) == B_OK
861 				&& count == 1) {
862 				// use DAC input format
863 				format->u.raw_audio.channel_count
864 					= in.format.u.raw_audio.channel_count;
865 				format->u.raw_audio.frame_rate
866 					= in.format.u.raw_audio.frame_rate;
867 			}
868 		}
869 	}
870 
871 	/* set source and suggest a name */
872 	*out_source = what;
873 	strcpy(out_name, "Mixer Output");
874 
875 	/* remove wildcards */
876 #if USE_MEDIA_FORMAT_WORKAROUND
877 	multi_audio_format_specialize(&format->u.raw_audio,
878 		&fDefaultFormat.u.raw_audio);
879 #else
880 	format->SpecializeTo(&fDefaultFormat);
881 #endif
882 
883 	PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format);
884 
885 	/* add output to core */
886 	media_output output;
887 	output.node = Node();
888 	output.source = *out_source;
889 	output.destination = where;
890 	output.format = *format;
891 	strcpy(output.name, out_name);
892 
893 	fCore->EnableOutput(false);
894 	fCore->AddOutput(output);
895 
896 	fCore->Unlock();
897 	return B_OK;
898 }
899 
900 
901 void
902 AudioMixer::Connect(status_t error, const media_source &source,
903 	const media_destination &dest, const media_format &format, char *io_name)
904 {
905 	TRACE("AudioMixer::Connect\n");
906 
907 	fCore->Lock();
908 	// are we still connected?
909 	if (fCore->Output() == 0) {
910 		fCore->Unlock();
911 		ERROR("AudioMixer::Connect: no longer connected\n");
912 		return;
913 	}
914 	fCore->Unlock();
915 
916 	if (error != B_OK) {
917 		// if an error occured, remove output from core
918 		ERROR("AudioMixer::Connect failed with error 0x%08lX, removing "
919 			"connection\n", error);
920 		fCore->Lock();
921 		fCore->RemoveOutput();
922 		fCore->Unlock();
923 		return;
924 	}
925 
926 	// Switch our prefered format to have the same
927 	// frame_rate and channel count as the output.
928 	fDefaultFormat.u.raw_audio.frame_rate = format.u.raw_audio.frame_rate;
929 	fDefaultFormat.u.raw_audio.channel_count = format.u.raw_audio.channel_count;
930 
931 	// if the connection has no name, we set it now
932 	if (strlen(io_name) == 0)
933 		strcpy(io_name, "Mixer Output");
934 
935 	// Now that we're connected, we can determine our downstream latency.
936 	media_node_id id;
937 	FindLatencyFor(dest, &fDownstreamLatency, &id);
938 	TRACE("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency);
939 
940 	// SetDuration of one buffer
941 	SetBufferDuration(buffer_duration(format.u.raw_audio));
942 	TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
943 
944 	// Our internal latency is at least the length of a full output buffer
945 	// plus mixing time, plus jitter
946 	fInternalLatency = BufferDuration()
947 		+ max(kMinMixingTime, bigtime_t(0.5 * BufferDuration())) + kMaxJitter;
948 	TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
949 
950 	SetEventLatency(fDownstreamLatency + fInternalLatency);
951 
952 	// we need to inform all connected *inputs* about *our* change in latency
953 	PublishEventLatencyChange();
954 
955 	fCore->Lock();
956 
957 	// Set up the buffer group for our connection, as long as nobody handed
958 	// us a buffer group (via SetBufferGroup()) prior to this.  That can
959 	// happen, for example, if the consumer calls SetOutputBuffersFor() on
960 	// us from within its Connected() method.
961 	if (!fBufferGroup) {
962 		BBufferGroup *group = NULL;
963 		if (CreateBufferGroup(&group) != B_OK)
964 			return;
965 		fBufferGroup = group;
966 	}
967 
968 	ASSERT(fCore->Output() != 0);
969 
970 	// our source should still be valid, too
971 	ASSERT(fCore->Output()->MediaOutput().source.id == 0);
972 	ASSERT(fCore->Output()->MediaOutput().source.port == ControlPort());
973 
974 	// BBufferConsumer::Connected() may return a different input for the
975 	// newly created connection. The destination can have changed since
976 	// AudioMixer::PrepareToConnect() and we need to update it.
977 	fCore->Output()->MediaOutput().destination = dest;
978 
979 	fCore->EnableOutput(true);
980 	fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
981 	fCore->SetOutputBufferGroup(fBufferGroup);
982 
983 	fCore->Settings()->LoadConnectionSettings(fCore->Output());
984 
985 	fCore->Unlock();
986 	UpdateParameterWeb();
987 }
988 
989 
990 void
991 AudioMixer::Disconnect(const media_source& what, const media_destination& where)
992 {
993 	TRACE("AudioMixer::Disconnect\n");
994 	fCore->Lock();
995 
996 	// Make sure that our connection is the one being disconnected
997 	MixerOutput* output = fCore->Output();
998 	if (!output
999 		|| output->MediaOutput().node != Node()
1000 		|| output->MediaOutput().source != what
1001 		|| output->MediaOutput().destination != where) {
1002 		ERROR("AudioMixer::Disconnect can't disconnect (wrong connection)\n");
1003 		fCore->Unlock();
1004 		return;
1005 	}
1006 
1007 	// Switch our prefered format back to default
1008 	// frame rate and channel count.
1009 	fDefaultFormat.u.raw_audio.frame_rate = 96000;
1010 	fDefaultFormat.u.raw_audio.channel_count = 2;
1011 
1012 	// force a stop
1013 	fCore->Stop();
1014 
1015 	fCore->RemoveOutput();
1016 
1017 	// destroy buffer group
1018 	delete fBufferGroup;
1019 	fBufferGroup = NULL;
1020 	fCore->SetOutputBufferGroup(0);
1021 
1022 	fCore->Unlock();
1023 	UpdateParameterWeb();
1024 }
1025 
1026 
1027 void
1028 AudioMixer::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
1029 	bigtime_t performanceTime)
1030 {
1031 	// We've produced some late buffers... Increase Latency
1032 	// is the only runmode in which we can do anything about this
1033 	// TODO: quality could be decreased, too
1034 
1035 	ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", howMuch,
1036 		performanceTime);
1037 
1038 	if (what == fCore->Output()->MediaOutput().source
1039 		&& RunMode() == B_INCREASE_LATENCY) {
1040 		// We need to ignore subsequent notices whose arrival time here
1041 		// lies within the last lateness, because queued-up buffers will all be 'late'
1042 		if (performanceTime < fLastLateNotification)
1043 			return;
1044 
1045 		fInternalLatency += howMuch;
1046 
1047 		// At some point a too large latency can get annoying
1048 		// (actually more than annoying, as there won't be enough buffers long before this!)
1049 		if (fInternalLatency > kMaxLatency)
1050 			fInternalLatency = kMaxLatency;
1051 
1052 		fLastLateNotification = TimeSource()->Now() + howMuch;
1053 
1054 		TRACE("AudioMixer: increasing internal latency to %"
1055 			B_PRIdBIGTIME " usec\n", fInternalLatency);
1056 		SetEventLatency(fDownstreamLatency + fInternalLatency);
1057 
1058 		PublishEventLatencyChange();
1059 	}
1060 }
1061 
1062 
1063 void
1064 AudioMixer::EnableOutput(const media_source& what, bool enabled,
1065 	int32 */*deprecated*/)
1066 {
1067 	// we only have one output
1068 	if (what.id != 0 || what.port != ControlPort())
1069 		return;
1070 
1071 	fCore->Lock();
1072 	fCore->EnableOutput(enabled);
1073 	fCore->Unlock();
1074 }
1075 
1076 
1077 //	#pragma mark - BMediaEventLooper methods
1078 
1079 
1080 void
1081 AudioMixer::NodeRegistered()
1082 {
1083 	UpdateParameterWeb();
1084 	SetPriority(B_REAL_TIME_PRIORITY);
1085 	Run();
1086 }
1087 
1088 
1089 void
1090 AudioMixer::SetTimeSource(BTimeSource* timeSource)
1091 {
1092 	TRACE("AudioMixer::SetTimeSource: timesource is now %ld\n",
1093 		timeSource->ID());
1094 	fCore->Lock();
1095 	fCore->SetTimingInfo(timeSource, fDownstreamLatency);
1096 	fCore->Unlock();
1097 }
1098 
1099 
1100 void
1101 AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness,
1102 	bool realTimeEvent)
1103 {
1104 	switch (event->type) {
1105 		case BTimedEventQueue::B_HANDLE_BUFFER:
1106 		{
1107 			HandleInputBuffer((BBuffer *)event->pointer, lateness);
1108 			((BBuffer *)event->pointer)->Recycle();
1109 			break;
1110 		}
1111 
1112 		case BTimedEventQueue::B_START:
1113 		{
1114 			TRACE("AudioMixer::HandleEvent: B_START\n");
1115 			if (RunState() != B_STARTED) {
1116 				fCore->Lock();
1117 				fCore->Start();
1118 				fCore->Unlock();
1119 			}
1120 			break;
1121 		}
1122 
1123 		case BTimedEventQueue::B_STOP:
1124 		{
1125 			TRACE("AudioMixer::HandleEvent: B_STOP\n");
1126 			// stopped - don't process any more buffers, flush all buffers
1127 			// from event queue
1128 			EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
1129 				BTimedEventQueue::B_HANDLE_BUFFER);
1130 			fCore->Lock();
1131 			fCore->Stop();
1132 			fCore->Unlock();
1133 			break;
1134 		}
1135 
1136 		case BTimedEventQueue::B_DATA_STATUS:
1137 		{
1138 			ERROR("DataStatus message\n");
1139 			break;
1140 		}
1141 
1142 		case MIXER_PROCESS_EVENT:
1143 			fCore->Process();
1144 		break;
1145 
1146 		default:
1147 			break;
1148 	}
1149 }
1150 
1151 
1152 //	#pragma mark - AudioMixer methods
1153 
1154 
1155 void
1156 AudioMixer::PublishEventLatencyChange()
1157 {
1158 	// our event (processing + downstream) latency has changed,
1159 	// and we need tell all inputs about this
1160 
1161 	TRACE("AudioMixer::PublishEventLatencyChange\n");
1162 
1163 	fCore->Lock();
1164 
1165 	MixerInput *input;
1166 	for (int i = 0; (input = fCore->Input(i)) != 0; i++) {
1167 		TRACE("AudioMixer::PublishEventLatencyChange: SendLatencyChange, "
1168 			"connection %ld/%ld to %ld/%ld event latency is now %Ld\n",
1169 			input->MediaInput().source.port, input->MediaInput().source.id,
1170 			input->MediaInput().destination.port,
1171 			input->MediaInput().destination.id, EventLatency());
1172 		SendLatencyChange(input->MediaInput().source,
1173 			input->MediaInput().destination, EventLatency());
1174 	}
1175 
1176 	fCore->Unlock();
1177 }
1178 
1179 
1180 status_t
1181 AudioMixer::CreateBufferGroup(BBufferGroup** buffer) const
1182 {
1183 	// allocate enough buffers to span our downstream latency
1184 	// (plus one for rounding up), plus one extra
1185 	int32 count = int32(fDownstreamLatency / BufferDuration()) + 2;
1186 
1187 	TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, "
1188 		"BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency,
1189 		BufferDuration(), count);
1190 
1191 	if (count < 3)
1192 		count = 3;
1193 
1194 	fCore->Lock();
1195 	uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size;
1196 	fCore->Unlock();
1197 
1198 	TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n",
1199 		count, size);
1200 
1201 	BBufferGroup* buf = new BBufferGroup(size, count);
1202 	if (buf == NULL)
1203 		return B_NO_MEMORY;
1204 
1205 	status_t status = buf->InitCheck();
1206 	if (status != B_OK)
1207 		delete buf;
1208 	else
1209 		*buffer = buf;
1210 
1211 	return status;
1212 }
1213 
1214 
1215 status_t
1216 AudioMixer::SendBuffer(BBuffer* buffer, MixerOutput* output)
1217 {
1218 	return BBufferProducer::SendBuffer(buffer, output->MediaOutput().source,
1219 		output->MediaOutput().destination);
1220 }
1221 
1222 
1223 float
1224 AudioMixer::dB_to_Gain(float db)
1225 {
1226 	TRACE("dB_to_Gain: dB in: %01.2f ", db);
1227 	if (fCore->Settings()->NonLinearGainSlider()) {
1228 		if (db > 0) {
1229 			db = db * (pow(abs(DB_MAX), (1.0 / DB_EXPONENT_POSITIVE))
1230 				/ abs(DB_MAX));
1231 			db = pow(db, DB_EXPONENT_POSITIVE);
1232 		} else {
1233 			db = -db;
1234 			db = db * (pow(abs(DB_MIN), (1.0 / DB_EXPONENT_NEGATIVE))
1235 				/ abs(DB_MIN));
1236 			db = pow(db, DB_EXPONENT_NEGATIVE);
1237 			db = -db;
1238 		}
1239 	}
1240 	TRACE("dB out: %01.2f\n", db);
1241 	return pow(10.0, db / 20.0);
1242 }
1243 
1244 
1245 float
1246 AudioMixer::Gain_to_dB(float gain)
1247 {
1248 	float db;
1249 	db = 20.0 * log10(gain);
1250 	if (fCore->Settings()->NonLinearGainSlider()) {
1251 		if (db > 0) {
1252 			db = pow(db, (1.0 / DB_EXPONENT_POSITIVE));
1253 			db = db * (abs(DB_MAX) / pow(abs(DB_MAX),
1254 				(1.0 / DB_EXPONENT_POSITIVE)));
1255 		} else {
1256 			db = -db;
1257 			db = pow(db, (1.0 / DB_EXPONENT_NEGATIVE));
1258 			db = db * (abs(DB_MIN) / pow(abs(DB_MIN),
1259 				(1.0 / DB_EXPONENT_NEGATIVE)));
1260 			db = -db;
1261 		}
1262 	}
1263 	return db;
1264 }
1265 
1266 
1267 // #pragma mark - BControllable methods
1268 
1269 
1270 status_t
1271 AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, void *value,
1272 	size_t *ioSize)
1273 {
1274 	TRACE("GetParameterValue: id 0x%08lx, ioSize %ld\n", id, *ioSize);
1275 	int param = PARAM(id);
1276 	fCore->Lock();
1277 	if (PARAM_IS_ETC(id)) {
1278 		switch (ETC(id)) {
1279 			case 10:	// Attenuate mixer output by 3dB
1280 				*ioSize = sizeof(int32);
1281 				static_cast<int32 *>(value)[0] = fCore->Settings()->AttenuateOutput();
1282 				break;
1283 			case 20:	// Use non linear gain sliders
1284 				*ioSize = sizeof(int32);
1285 				static_cast<int32 *>(value)[0] = fCore->Settings()->NonLinearGainSlider();
1286 				break;
1287 			case 30:	// Display balance control for stereo connections
1288 				*ioSize = sizeof(int32);
1289 				static_cast<int32 *>(value)[0] = fCore->Settings()->UseBalanceControl();
1290 				break;
1291 			case 40:	// Allow output channel remapping
1292 				*ioSize = sizeof(int32);
1293 				static_cast<int32 *>(value)[0] = fCore->Settings()->AllowOutputChannelRemapping();
1294 				break;
1295 			case 50:	// Allow input channel remapping
1296 				*ioSize = sizeof(int32);
1297 				static_cast<int32 *>(value)[0] = fCore->Settings()->AllowInputChannelRemapping();
1298 				break;
1299 			case 60:	// Input gain controls
1300 				*ioSize = sizeof(int32);
1301 				static_cast<int32 *>(value)[0] = fCore->Settings()->InputGainControls();
1302 				break;
1303 			case 70:	// Resampling algorithm
1304 				*ioSize = sizeof(int32);
1305 				static_cast<int32 *>(value)[0] = fCore->Settings()->ResamplingAlgorithm();
1306 				break;
1307 			case 80:	// Refuse output format changes
1308 				*ioSize = sizeof(int32);
1309 				static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseOutputFormatChange();
1310 				break;
1311 			case 90:	// Refuse input format changes
1312 				*ioSize = sizeof(int32);
1313 				static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseInputFormatChange();
1314 				break;
1315 			default:
1316 				ERROR("unhandled ETC 0x%08lx\n", id);
1317 				break;
1318 		}
1319 	} else if (param == 0) {
1320 		MixerOutput *output = fCore->Output();
1321 		if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id) && !PARAM_IS_BALANCE(id)))
1322 			goto err;
1323 		if (PARAM_IS_MUTE(id)) {
1324 			// output mute control
1325 			if (*ioSize < sizeof(int32))
1326 				goto err;
1327 			*ioSize = sizeof(int32);
1328 			static_cast<int32 *>(value)[0] = output->IsMuted();
1329 		}
1330 		if (PARAM_IS_GAIN(id)) {
1331 			// output gain control
1332 			if (fCore->Settings()->UseBalanceControl() && output->GetOutputChannelCount() == 2 && 1 /*channel mask is stereo */) {
1333 				// single channel control + balance
1334 				if (*ioSize < sizeof(float))
1335 					goto err;
1336 				*ioSize = sizeof(float);
1337 				static_cast<float *>(value)[0] = GAIN_TO_DB((output->GetOutputChannelGain(0) + output->GetOutputChannelGain(1)) / 2);
1338 			} else {
1339 				// multi channel control
1340 				if (*ioSize == sizeof(float)) {
1341 					// get combined gain for all controls
1342 					float gain = 0;
1343 					for (int channel = 0;
1344 							channel < output->GetOutputChannelCount();
1345 							channel++) {
1346 						gain += GAIN_TO_DB(
1347 							output->GetOutputChannelGain(channel));
1348 					}
1349 					static_cast<float *>(value)[0] = gain
1350 						/ output->GetOutputChannelCount();
1351 				} else {
1352 					if (*ioSize < output->GetOutputChannelCount()
1353 							* sizeof(float))
1354 						goto err;
1355 
1356 					*ioSize = output->GetOutputChannelCount() * sizeof(float);
1357 
1358 					for (int channel = 0;
1359 							channel < output->GetOutputChannelCount();
1360 							channel++) {
1361 						static_cast<float *>(value)[channel]
1362 							= GAIN_TO_DB(output->GetOutputChannelGain(channel));
1363 					}
1364 				}
1365 			}
1366 		}
1367 		if (PARAM_IS_BALANCE(id)) {
1368 			float l = output->GetOutputChannelGain(0);
1369 			float r = output->GetOutputChannelGain(1);
1370 			float v = r / (l+r);
1371 			TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v);
1372 			if (*ioSize < sizeof(float))
1373 				goto err;
1374 			*ioSize = sizeof(float);
1375 			static_cast<float *>(value)[0] = v * 100;
1376 		}
1377 		if (PARAM_IS_SRC_ENABLE(id)) {
1378 			if (*ioSize < sizeof(int32))
1379 				goto err;
1380 			*ioSize = sizeof(int32);
1381 			static_cast<int32 *>(value)[0] = output->HasOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id));
1382 		}
1383 		if (PARAM_IS_SRC_GAIN(id)) {
1384 			if (*ioSize < sizeof(float))
1385 				goto err;
1386 			*ioSize = sizeof(float);
1387 			static_cast<float *>(value)[0] = GAIN_TO_PERCENT(output->GetOutputChannelSourceGain(PARAM_CHAN(id), PARAM_SRC(id)));
1388 		}
1389 	} else {
1390 		MixerInput *input;
1391 		for (int i = 0; (input = fCore->Input(i)); i++)
1392 			if (input->ID() == param)
1393 				break;
1394 		if (!input || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_DST_ENABLE(id) && !PARAM_IS_BALANCE(id)))
1395 			goto err;
1396 		if (PARAM_IS_MUTE(id)) {
1397 			// input mute control
1398 			if (*ioSize < sizeof(int32))
1399 				goto err;
1400 			*ioSize = sizeof(int32);
1401 			static_cast<int32 *>(value)[0] = !input->IsEnabled();
1402 		}
1403 		if (PARAM_IS_GAIN(id)) {
1404 			// input gain control
1405 			if (fCore->Settings()->InputGainControls() == 0) {
1406 				// Physical input channels
1407 				if (fCore->Settings()->UseBalanceControl() && input->GetInputChannelCount() == 2 && 1 /*channel mask is stereo */) {
1408 					// single channel control + balance
1409 					if (*ioSize < sizeof(float))
1410 						goto err;
1411 					*ioSize = sizeof(float);
1412 					static_cast<float *>(value)[0] = GAIN_TO_DB((input->GetInputChannelGain(0) + input->GetInputChannelGain(1)) / 2);
1413 				} else {
1414 					// multi channel control
1415 					if (*ioSize < input->GetInputChannelCount() * sizeof(float))
1416 						goto err;
1417 					*ioSize = input->GetInputChannelCount() * sizeof(float);
1418 					for (int chan = 0; chan < input->GetInputChannelCount(); chan++)
1419 						static_cast<float *>(value)[chan] = GAIN_TO_DB(input->GetInputChannelGain(chan));
1420 				}
1421 			} else {
1422 				// Virtual output channels
1423 				if (fCore->Settings()->UseBalanceControl() && input->GetMixerChannelCount() == 2 && 1 /*channel mask is stereo */) {
1424 					// single channel control + balance
1425 					if (*ioSize < sizeof(float))
1426 						goto err;
1427 					*ioSize = sizeof(float);
1428 					static_cast<float *>(value)[0] = GAIN_TO_DB((input->GetMixerChannelGain(0) + input->GetMixerChannelGain(1)) / 2);
1429 				} else {
1430 					// multi channel control
1431 					if (*ioSize < input->GetMixerChannelCount() * sizeof(float))
1432 						goto err;
1433 					*ioSize = input->GetMixerChannelCount() * sizeof(float);
1434 					for (int chan = 0; chan < input->GetMixerChannelCount(); chan++)
1435 						static_cast<float *>(value)[chan] = GAIN_TO_DB(input->GetMixerChannelGain(chan));
1436 				}
1437 			}
1438 		}
1439 		if (PARAM_IS_BALANCE(id)) {
1440 			if (fCore->Settings()->InputGainControls() == 0) {
1441 				// Physical input channels
1442 				float l = input->GetInputChannelGain(0);
1443 				float r = input->GetInputChannelGain(1);
1444 				float v = r / (l+r);
1445 				TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v);
1446 				if (*ioSize < sizeof(float))
1447 					goto err;
1448 				*ioSize = sizeof(float);
1449 				static_cast<float *>(value)[0] = v * 100;
1450 			} else {
1451 				// Virtual output channels
1452 				float l = input->GetMixerChannelGain(0);
1453 				float r = input->GetMixerChannelGain(1);
1454 				float v = r / (l+r);
1455 				TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v);
1456 				if (*ioSize < sizeof(float))
1457 					goto err;
1458 				*ioSize = sizeof(float);
1459 				static_cast<float *>(value)[0] = v * 100;
1460 			}
1461 		}
1462 		if (PARAM_IS_DST_ENABLE(id)) {
1463 			if (*ioSize < sizeof(int32))
1464 				goto err;
1465 			*ioSize = sizeof(int32);
1466 			static_cast<int32 *>(value)[0] = input->HasInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id));
1467 		}
1468 	}
1469 	*last_change = TimeSource()->Now(); // XXX we could do better
1470 	fCore->Unlock();
1471 	return B_OK;
1472 err:
1473 	fCore->Unlock();
1474 	return B_ERROR;
1475 }
1476 
1477 
1478 void
1479 AudioMixer::SetParameterValue(int32 id, bigtime_t when, const void *value,
1480 	size_t size)
1481 {
1482 	TRACE("SetParameterValue: id 0x%08lx, size %ld\n", id, size);
1483 	bool update = false;
1484 	int param = PARAM(id);
1485 	fCore->Lock();
1486 	if (PARAM_IS_ETC(id)) {
1487 		switch (ETC(id)) {
1488 			case 10:	// Attenuate mixer output by 3dB
1489 				if (size != sizeof(int32))
1490 					goto err;
1491 				fCore->Settings()->SetAttenuateOutput(static_cast<const int32 *>(value)[0]);
1492 				// this value is special (see MixerCore.h) and we need to notify the core
1493 				fCore->SetOutputAttenuation((static_cast<const int32 *>(value)[0]) ? 0.708 : 1.0);
1494 				break;
1495 			case 20:	// Use non linear gain sliders
1496 				if (size != sizeof(int32))
1497 					goto err;
1498 				fCore->Settings()->SetNonLinearGainSlider(static_cast<const int32 *>(value)[0]);
1499 				update = true; // XXX should use BroadcastChangedParameter()
1500 				break;
1501 			case 30:	// Display balance control for stereo connections
1502 				if (size != sizeof(int32))
1503 					goto err;
1504 				fCore->Settings()->SetUseBalanceControl(static_cast<const int32 *>(value)[0]);
1505 				update = true;
1506 				break;
1507 			case 40:	// Allow output channel remapping
1508 				if (size != sizeof(int32))
1509 					goto err;
1510 				fCore->Settings()->SetAllowOutputChannelRemapping(static_cast<const int32 *>(value)[0]);
1511 				update = true;
1512 				break;
1513 			case 50:	// Allow input channel remapping
1514 				if (size != sizeof(int32))
1515 					goto err;
1516 				fCore->Settings()->SetAllowInputChannelRemapping(static_cast<const int32 *>(value)[0]);
1517 				update = true;
1518 				break;
1519 			case 60:	// Input gain controls represent
1520 						// (0, "Physical input channels")
1521 						// (1, "Virtual output channels")
1522 				if (size != sizeof(int32))
1523 					goto err;
1524 				fCore->Settings()->SetInputGainControls(static_cast<const int32 *>(value)[0]);
1525 				update = true; // XXX should use BroadcastChangedParameter()
1526 				break;
1527 			case 70:	// Resampling algorithm
1528 				if (size != sizeof(int32))
1529 					goto err;
1530 				fCore->Settings()->SetResamplingAlgorithm(static_cast<const int32 *>(value)[0]);
1531 				fCore->UpdateResamplingAlgorithm();
1532 				break;
1533 			case 80:	// Refuse output format changes
1534 				if (size != sizeof(int32))
1535 					goto err;
1536 				fCore->Settings()->SetRefuseOutputFormatChange(static_cast<const int32 *>(value)[0]);
1537 				break;
1538 			case 90:	// Refuse input format changes
1539 				if (size != sizeof(int32))
1540 					goto err;
1541 				fCore->Settings()->SetRefuseInputFormatChange(static_cast<const int32 *>(value)[0]);
1542 				break;
1543 			default:
1544 				ERROR("unhandled ETC 0x%08lx\n", id);
1545 				break;
1546 		}
1547 	} else if (param == 0) {
1548 		MixerOutput *output = fCore->Output();
1549 		if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id) && !PARAM_IS_BALANCE(id)))
1550 			goto err;
1551 		if (PARAM_IS_MUTE(id)) {
1552 			// output mute control
1553 			if (size != sizeof(int32))
1554 				goto err;
1555 			output->SetMuted(static_cast<const int32 *>(value)[0]);
1556 		}
1557 		if (PARAM_IS_GAIN(id)) {
1558 			// output gain control
1559 			if (fCore->Settings()->UseBalanceControl()
1560 				&& output->GetOutputChannelCount() == 2 && 1 /*channel mask is stereo */) {
1561 				// single channel control + balance
1562 				float l = output->GetOutputChannelGain(0);
1563 				float r = output->GetOutputChannelGain(1);
1564 				float m = (l + r) / 2;	// master volume
1565 				float v = DB_TO_GAIN(static_cast<const float *>(value)[0]);
1566 				float f = v / m;		// factor for both channels
1567 				TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f);
1568 				output->SetOutputChannelGain(0, output->GetOutputChannelGain(0) * f);
1569 				output->SetOutputChannelGain(1, output->GetOutputChannelGain(1) * f);
1570 			} else {
1571 				// multi channel control
1572 				if (size == sizeof(float)) {
1573 					// set same volume for all channels
1574 					float gain = static_cast<const float *>(value)[0];
1575 					for (int channel = 0;
1576 							channel < output->GetOutputChannelCount();
1577 							channel++) {
1578 						output->SetOutputChannelGain(channel,
1579 							DB_TO_GAIN(gain));
1580 					}
1581 				} else {
1582 					if (size < output->GetOutputChannelCount() * sizeof(float))
1583 						goto err;
1584 					for (int channel = 0;
1585 							channel < output->GetOutputChannelCount();
1586 							channel++) {
1587 						output->SetOutputChannelGain(channel,
1588 							DB_TO_GAIN(static_cast<const float *>(
1589 								value)[channel]));
1590 					}
1591 				}
1592 			}
1593 		}
1594 		if (PARAM_IS_BALANCE(id)) {
1595 			float l = output->GetOutputChannelGain(0);
1596 			float r = output->GetOutputChannelGain(1);
1597 			float m = (l + r) / 2;	// master volume
1598 			float v = static_cast<const float *>(value)[0] / 100; // current balance value
1599 			float fl = 2 * (1 - v);	// left channel factor of master volume
1600 			float fr = 2 * v;		// right channel factor of master volume
1601 			TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr);
1602 			output->SetOutputChannelGain(0, m * fl);
1603 			output->SetOutputChannelGain(1, m * fr);
1604 		}
1605 		if (PARAM_IS_SRC_ENABLE(id)) {
1606 			if (size != sizeof(int32))
1607 				goto err;
1608 			if (static_cast<const int32 *>(value)[0]) {
1609 				output->AddOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id));
1610 			} else {
1611 				output->RemoveOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id));
1612 			}
1613 		}
1614 		if (PARAM_IS_SRC_GAIN(id)) {
1615 			if (size != sizeof(float))
1616 				goto err;
1617 			output->SetOutputChannelSourceGain(PARAM_CHAN(id), PARAM_SRC(id), PERCENT_TO_GAIN(static_cast<const float *>(value)[0]));
1618 		}
1619 		fCore->Settings()->SaveConnectionSettings(output);
1620 	} else {
1621 		MixerInput *input;
1622 		for (int i = 0; (input = fCore->Input(i)); i++)
1623 			if (input->ID() == param)
1624 				break;
1625 		if (!input || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_DST_ENABLE(id) && !PARAM_IS_BALANCE(id)))
1626 			goto err;
1627 		if (PARAM_IS_MUTE(id)) {
1628 			// input mute control
1629 			if (size != sizeof(int32))
1630 				goto err;
1631 			input->SetEnabled(!static_cast<const int32 *>(value)[0]);
1632 		}
1633 		if (PARAM_IS_GAIN(id)) {
1634 			// input gain control
1635 			if (fCore->Settings()->InputGainControls() == 0) {
1636 				// Physical input channels
1637 				if (fCore->Settings()->UseBalanceControl() && input->GetInputChannelCount() == 2 && 1 /*channel mask is stereo */) {
1638 					// single channel control + balance
1639 					float l = input->GetInputChannelGain(0);
1640 					float r = input->GetInputChannelGain(1);
1641 					float m = (l + r) / 2;	// master volume
1642 					float v = DB_TO_GAIN(static_cast<const float *>(value)[0]);
1643 					float f = v / m;		// factor for both channels
1644 					TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f);
1645 					input->SetInputChannelGain(0, input->GetInputChannelGain(0) * f);
1646 					input->SetInputChannelGain(1, input->GetInputChannelGain(1) * f);
1647 				} else {
1648 					// multi channel control
1649 					if (size < input->GetInputChannelCount() * sizeof(float))
1650 						goto err;
1651 					for (int chan = 0; chan < input->GetInputChannelCount(); chan++)
1652 						input->SetInputChannelGain(chan, DB_TO_GAIN(static_cast<const float *>(value)[chan]));
1653 				}
1654 			} else {
1655 				// Virtual output channels
1656 				if (fCore->Settings()->UseBalanceControl() && input->GetMixerChannelCount() == 2 && 1 /*channel mask is stereo */) {
1657 					// single channel control + balance
1658 					float l = input->GetMixerChannelGain(0);
1659 					float r = input->GetMixerChannelGain(1);
1660 					float m = (l + r) / 2;	// master volume
1661 					float v = DB_TO_GAIN(static_cast<const float *>(value)[0]);
1662 					float f = v / m;		// factor for both channels
1663 					TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f);
1664 					input->SetMixerChannelGain(0, input->GetMixerChannelGain(0) * f);
1665 					input->SetMixerChannelGain(1, input->GetMixerChannelGain(1) * f);
1666 				} else {
1667 					// multi channel control
1668 					if (size < input->GetMixerChannelCount() * sizeof(float))
1669 						goto err;
1670 					for (int chan = 0; chan < input->GetMixerChannelCount(); chan++)
1671 						input->SetMixerChannelGain(chan, DB_TO_GAIN(static_cast<const float *>(value)[chan]));
1672 				}
1673 			}
1674 		}
1675 		if (PARAM_IS_BALANCE(id)) {
1676 			if (fCore->Settings()->InputGainControls() == 0) {
1677 				// Physical input channels
1678 				float l = input->GetInputChannelGain(0);
1679 				float r = input->GetInputChannelGain(1);
1680 				float m = (l + r) / 2;	// master volume
1681 				float v = static_cast<const float *>(value)[0] / 100; // current balance value
1682 				float fl = 2 * (1 - v);	// left channel factor of master volume
1683 				float fr = 2 * v;		// right channel factor of master volume
1684 				TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr);
1685 				input->SetInputChannelGain(0, m * fl);
1686 				input->SetInputChannelGain(1, m * fr);
1687 			} else {
1688 				// Virtual output channels
1689 				float l = input->GetMixerChannelGain(0);
1690 				float r = input->GetMixerChannelGain(1);
1691 				float m = (l + r) / 2;	// master volume
1692 				float v = static_cast<const float *>(value)[0] / 100; // current balance value
1693 				float fl = 2 * (1 - v);	// left channel factor of master volume
1694 				float fr = 2 * v;		// right channel factor of master volume
1695 				TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr);
1696 				input->SetMixerChannelGain(0, m * fl);
1697 				input->SetMixerChannelGain(1, m * fr);
1698 			}
1699 		}
1700 		if (PARAM_IS_DST_ENABLE(id)) {
1701 			if (size != sizeof(int32))
1702 				goto err;
1703 			if (static_cast<const int32 *>(value)[0]) {
1704 				int oldchan = input->GetInputChannelForDestination(PARAM_DST(id));
1705 				if (oldchan != -1) {
1706 					input->RemoveInputChannelDestination(oldchan, PARAM_DST(id));
1707 					int32 null = 0;
1708 					BroadcastNewParameterValue(when, PARAM_DST_ENABLE(PARAM(id), oldchan, PARAM_DST(id)), &null, sizeof(null));
1709 				}
1710 				input->AddInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id));
1711 			} else {
1712 				input->RemoveInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id));
1713 			}
1714 			// TODO: this is really annoying
1715 			// The slider count of the gain control needs to be changed,
1716 			// but calling SetChannelCount(input->GetMixerChannelCount())
1717 			// on it has no effect on remote BParameterWebs in other apps.
1718 			// BroadcastChangedParameter() should be correct, but doesn't work
1719 			BroadcastChangedParameter(PARAM_GAIN(PARAM(id)));
1720 			// We trigger a complete ParameterWeb update as workaround
1721 			// but it will change the focus from tab 3 to tab 1
1722 			update = true;
1723 		}
1724 		fCore->Settings()->SaveConnectionSettings(input);
1725 	}
1726 
1727 	BroadcastNewParameterValue(when, id, const_cast<void *>(value), size);
1728 
1729 err:
1730 	fCore->Unlock();
1731 	if (update)
1732 		UpdateParameterWeb();
1733 }
1734 
1735 
1736 void
1737 AudioMixer::UpdateParameterWeb()
1738 {
1739 	fCore->Lock();
1740 	BParameterWeb *web = new BParameterWeb();
1741 	BParameterGroup *top;
1742 	BParameterGroup *outputchannels;
1743 	BParameterGroup *inputchannels;
1744 	BParameterGroup *group;
1745 	BParameterGroup *subgroup;
1746 	BParameterGroup *subsubgroup;
1747 	BDiscreteParameter *dp;
1748 	MixerInput *in;
1749 	MixerOutput *out;
1750 	char buf[50];
1751 
1752 	top = web->MakeGroup(B_TRANSLATE("Gain controls"));
1753 
1754 	out = fCore->Output();
1755 	group = top->MakeGroup("");
1756 	group->MakeNullParameter(PARAM_STR1(0), B_MEDIA_RAW_AUDIO,
1757 		B_TRANSLATE("Master output"), B_WEB_BUFFER_INPUT);
1758 	if (!out) {
1759 		group->MakeNullParameter(PARAM_STR2(0), B_MEDIA_RAW_AUDIO,
1760 			B_TRANSLATE("not connected"), B_GENERIC);
1761 	} else {
1762 		group->MakeNullParameter(PARAM_STR2(0), B_MEDIA_RAW_AUDIO,
1763 			StringForFormat(buf, out), B_GENERIC);
1764 		group->MakeDiscreteParameter(PARAM_MUTE(0), B_MEDIA_RAW_AUDIO,
1765 			B_TRANSLATE("Mute"), B_MUTE);
1766 		if (fCore->Settings()->UseBalanceControl()
1767 			&& out->GetOutputChannelCount() == 2 && 1
1768 			/*channel mask is stereo */) {
1769 			// single channel control + balance
1770 			group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO,
1771 				B_TRANSLATE("Gain"), B_MASTER_GAIN, B_TRANSLATE("dB"),
1772 				DB_MIN, DB_MAX, 0.1);
1773 			group->MakeContinuousParameter(PARAM_BALANCE(0), B_MEDIA_RAW_AUDIO,
1774 				"", B_BALANCE, "", 0, 100, 1);
1775 		} else {
1776 			// multi channel control
1777 			group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO,
1778 				B_TRANSLATE("Gain"), B_MASTER_GAIN, B_TRANSLATE("dB"),
1779 				DB_MIN, DB_MAX, 0.1)
1780 				   ->SetChannelCount(out->GetOutputChannelCount());
1781 		}
1782 		group->MakeNullParameter(PARAM_STR3(0), B_MEDIA_RAW_AUDIO,
1783 			B_TRANSLATE("To output"), B_WEB_BUFFER_OUTPUT);
1784 	}
1785 
1786 	for (int i = 0; (in = fCore->Input(i)); i++) {
1787 		group = top->MakeGroup("");
1788 		group->MakeNullParameter(PARAM_STR1(in->ID()), B_MEDIA_RAW_AUDIO,
1789 			in->MediaInput().name, B_WEB_BUFFER_INPUT);
1790 		group->MakeNullParameter(PARAM_STR2(in->ID()), B_MEDIA_RAW_AUDIO,
1791 			StringForFormat(buf, in), B_GENERIC);
1792 		group->MakeDiscreteParameter(PARAM_MUTE(in->ID()), B_MEDIA_RAW_AUDIO,
1793 			B_TRANSLATE("Mute"), B_MUTE);
1794 		// XXX the gain control is ugly once you have more than two channels,
1795 		//     as you don't know what channel each slider controls. Tooltips might help...
1796 		if (fCore->Settings()->InputGainControls() == 0) {
1797 			// Physical input channels
1798 			if (fCore->Settings()->UseBalanceControl()
1799 				&& in->GetInputChannelCount() == 2 && 1
1800 				/*channel mask is stereo */) {
1801 				// single channel control + balance
1802 				group->MakeContinuousParameter(PARAM_GAIN(in->ID()),
1803 					B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN,
1804 					B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1);
1805 				group->MakeContinuousParameter(PARAM_BALANCE(in->ID()),
1806 					B_MEDIA_RAW_AUDIO, "", B_BALANCE, "", 0, 100, 1);
1807 			} else {
1808 				// multi channel control
1809 				group->MakeContinuousParameter(PARAM_GAIN(in->ID()),
1810 					B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN,
1811 					B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1)
1812 						->SetChannelCount(in->GetInputChannelCount());
1813 			}
1814 		} else {
1815 			// Virtual output channels
1816 			if (fCore->Settings()->UseBalanceControl()
1817 				&& in->GetMixerChannelCount() == 2 && 1
1818 				/*channel mask is stereo */) {
1819 				// single channel control + balance
1820 				group->MakeContinuousParameter(PARAM_GAIN(in->ID()),
1821 					B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN,
1822 					B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1);
1823 				group->MakeContinuousParameter(PARAM_BALANCE(in->ID()),
1824 					B_MEDIA_RAW_AUDIO, "", B_BALANCE, "", 0, 100, 1);
1825 			} else {
1826 				// multi channel control
1827 				group->MakeContinuousParameter(PARAM_GAIN(in->ID()),
1828 					B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN,
1829 					B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1)
1830 						->SetChannelCount(in->GetMixerChannelCount());
1831 			}
1832 		}
1833 		group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO,
1834 			B_TRANSLATE("To master"), B_WEB_BUFFER_OUTPUT);
1835 	}
1836 
1837 	if (fCore->Settings()->AllowOutputChannelRemapping()) {
1838 		top = web->MakeGroup(B_TRANSLATE("Output mapping")); // top level group
1839 		outputchannels = top->MakeGroup("");
1840 		outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO,
1841 			B_TRANSLATE("Output channel sources"), B_GENERIC);
1842 
1843 		group = outputchannels->MakeGroup("");
1844 		group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO,
1845 			B_TRANSLATE("Master output"), B_GENERIC);
1846 		group = group->MakeGroup("");
1847 		if (!out) {
1848 			group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO,
1849 				B_TRANSLATE("not connected"), B_GENERIC);
1850 		} else {
1851 			for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) {
1852 				subgroup = group->MakeGroup("");
1853 				subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan),
1854 					B_MEDIA_RAW_AUDIO, StringForChannelType(buf,
1855 						out->GetOutputChannelType(chan)), B_GENERIC);
1856 				for (int src = 0; src < MAX_CHANNEL_TYPES; src++) {
1857 					subsubgroup = subgroup->MakeGroup("");
1858 					subsubgroup->MakeDiscreteParameter(
1859 						PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "",
1860 						B_ENABLE);
1861 					subsubgroup->MakeContinuousParameter(
1862 						PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
1863 						StringForChannelType(buf, src), B_GAIN, "%", 0.0,
1864 						100.0, 0.1);
1865 				}
1866 			}
1867 		}
1868 	}
1869 
1870 	if (fCore->Settings()->AllowInputChannelRemapping()) {
1871 		top = web->MakeGroup(B_TRANSLATE("Input mapping")); // top level group
1872 		inputchannels = top->MakeGroup("");
1873 		inputchannels->MakeNullParameter(PARAM_STR7(0), B_MEDIA_RAW_AUDIO,
1874 			B_TRANSLATE("Input channel destinations"), B_GENERIC);
1875 
1876 		for (int i = 0; (in = fCore->Input(i)); i++) {
1877 			group = inputchannels->MakeGroup("");
1878 			group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO,
1879 				in->MediaInput().name, B_GENERIC);
1880 			group = group->MakeGroup("");
1881 
1882 			for (int chan = 0; chan < in->GetInputChannelCount(); chan++) {
1883 				subgroup = group->MakeGroup("");
1884 				subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan),
1885 					B_MEDIA_RAW_AUDIO, StringForChannelType(buf,
1886 					in->GetInputChannelType(chan)), B_GENERIC);
1887 				for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) {
1888 					subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(),
1889 					chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst),
1890 					B_ENABLE);
1891 				}
1892 			}
1893 		}
1894 	}
1895 
1896 	top = web->MakeGroup(B_TRANSLATE("Setup")); // top level group
1897 	group = top->MakeGroup("");
1898 
1899 	group->MakeDiscreteParameter(PARAM_ETC(10), B_MEDIA_RAW_AUDIO,
1900 		B_TRANSLATE("Attenuate mixer output by 3dB (like BeOS R5)"), B_ENABLE);
1901 	group->MakeDiscreteParameter(PARAM_ETC(20), B_MEDIA_RAW_AUDIO,
1902 		B_TRANSLATE("Use non linear gain sliders (like BeOS R5)"), B_ENABLE);
1903 	group->MakeDiscreteParameter(PARAM_ETC(30), B_MEDIA_RAW_AUDIO,
1904 		B_TRANSLATE("Display balance control for stereo connections"),
1905 		B_ENABLE);
1906 
1907 	group->MakeDiscreteParameter(PARAM_ETC(40), B_MEDIA_RAW_AUDIO,
1908 		B_TRANSLATE("Allow output channel remapping"), B_ENABLE);
1909 	group->MakeDiscreteParameter(PARAM_ETC(50), B_MEDIA_RAW_AUDIO,
1910 		B_TRANSLATE("Allow input channel remapping"), B_ENABLE);
1911 
1912 	dp = group->MakeDiscreteParameter(PARAM_ETC(60), B_MEDIA_RAW_AUDIO,
1913 		B_TRANSLATE("Input gain controls represent"), B_INPUT_MUX);
1914 	dp->AddItem(0, B_TRANSLATE("Physical input channels"));
1915 	dp->AddItem(1, B_TRANSLATE("Virtual output channels"));
1916 
1917 	dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO,
1918 		B_TRANSLATE("Resampling algorithm"), B_INPUT_MUX);
1919 	dp->AddItem(0, B_TRANSLATE("Drop/repeat samples"));
1920 	dp->AddItem(2, B_TRANSLATE("Linear interpolation"));
1921 
1922 	// Note: The following code is outcommented on purpose
1923 	// and is about to be modified at a later point
1924 	/*
1925 	dp->AddItem(1, B_TRANSLATE("Drop/repeat samples (template based)"));
1926 	dp->AddItem(3, B_TRANSLATE("17th order filtering"));
1927 	*/
1928 	group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO,
1929 		B_TRANSLATE("Refuse output format changes"), B_ENABLE);
1930 	group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO,
1931 		B_TRANSLATE("Refuse input format changes"), B_ENABLE);
1932 
1933 	fCore->Unlock();
1934 	SetParameterWeb(web);
1935 }
1936 
1937 
1938 #if USE_MEDIA_FORMAT_WORKAROUND
1939 static void
1940 raw_audio_format_specialize(media_raw_audio_format *format,
1941 	const media_raw_audio_format *other)
1942 {
1943 	if (format->frame_rate == 0)
1944 		format->frame_rate = other->frame_rate;
1945 	if (format->channel_count == 0)
1946 		format->channel_count = other->channel_count;
1947 	if (format->format == 0)
1948 		format->format = other->format;
1949 	if (format->byte_order == 0)
1950 		format->byte_order = other->byte_order;
1951 	if (format->buffer_size == 0)
1952 		format->buffer_size = other->buffer_size;
1953 	if (format->frame_rate == 0)
1954 		format->frame_rate = other->frame_rate;
1955 }
1956 
1957 
1958 static void
1959 multi_audio_info_specialize(media_multi_audio_info *format,
1960 	const media_multi_audio_info *other)
1961 {
1962 	if (format->channel_mask == 0)
1963 		format->channel_mask = other->channel_mask;
1964 	if (format->valid_bits == 0)
1965 		format->valid_bits = other->valid_bits;
1966 	if (format->matrix_mask == 0)
1967 		format->matrix_mask = other->matrix_mask;
1968 }
1969 
1970 
1971 static void
1972 multi_audio_format_specialize(media_multi_audio_format *format,
1973 	const media_multi_audio_format *other)
1974 {
1975 	raw_audio_format_specialize(format, other);
1976 	multi_audio_info_specialize(format, other);
1977 }
1978 #endif
1979