2 * Copyright 2002 David Shipman,
3 * Copyright 2003-2007 Marcus Overhagen
4 * Copyright 2007-2011 Haiku Inc. All rights reserved.
6 * Distributed under the terms of the MIT License.
10 #include "AudioMixer.h"
19 #include <FindDirectory.h>
20 #include <MediaDefs.h>
21 #include <MediaRoster.h>
22 #include <ParameterWeb.h>
24 #include <RealtimeAlloc.h>
25 #include <TimeSource.h>
27 #include "MixerCore.h"
28 #include "MixerInput.h"
29 #include "MixerOutput.h"
30 #include "MixerUtils.h"
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "AudioMixer"
37 // the range of the gain sliders (in dB)
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
44 #define USE_MEDIA_FORMAT_WORKAROUND 1
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)
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)
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)
85 #if USE_MEDIA_FORMAT_WORKAROUND
87 multi_audio_format_specialize(media_multi_audio_format
*format
,
88 const media_multi_audio_format
*other
);
91 #define FORMAT_USER_DATA_TYPE 0x7294a8f3
92 #define FORMAT_USER_DATA_MAGIC_1 0xc84173bd
93 #define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d
96 const static bigtime_t kMaxLatency
= 150000;
97 // 150 ms is the maximum latency we publish
99 const bigtime_t kMinMixingTime
= 3500;
100 const bigtime_t kMaxJitter
= 1500;
103 AudioMixer::AudioMixer(BMediaAddOn
*addOn
, bool isSystemMixer
)
105 BMediaNode("Audio Mixer"),
106 BBufferConsumer(B_MEDIA_RAW_AUDIO
),
107 BBufferProducer(B_MEDIA_RAW_AUDIO
),
111 fCore(new MixerCore(this)),
114 fDownstreamLatency(1),
117 fLastLateNotification(0),
120 BMediaNode::AddNodeKind(B_SYSTEM_MIXER
);
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;
134 // to get persistent settings, assign a settings file
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());
141 // disable stop on the auto started (system) mixer
149 AudioMixer::~AudioMixer()
151 BMediaEventLooper::Quit();
152 SetParameterWeb(NULL
);
159 // disconnect all nodes from the mixer
165 DEBUG_ONLY(fCore
= 0; fBufferGroup
= 0; fWeb
= 0);
170 AudioMixer::ApplySettings()
173 fCore
->SetOutputAttenuation(fCore
->Settings()->AttenuateOutput() ? 0.708 : 1.0);
179 AudioMixer::DisableNodeStop()
185 // #pragma mark - BMediaNode methods
189 AudioMixer::Stop(bigtime_t performance_time
, bool immediate
)
192 TRACE("AudioMixer STOP is disabled\n");
195 BMediaEventLooper::Stop(performance_time
, immediate
);
201 AudioMixer::AddOn(int32
*internal_id
) const
208 // #pragma mark - BBufferConsumer methods
212 AudioMixer::HandleMessage(int32 message
, const void *data
, size_t size
)
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
218 if (message
== MIXER_SCHEDULE_EVENT
) {
219 RealTimeQueue()->AddEvent(*(const media_timed_event
*)data
);
228 AudioMixer::AcceptFormat(const media_destination
&dest
, media_format
*ioFormat
)
230 PRINT_FORMAT("AudioMixer::AcceptFormat: ", *ioFormat
);
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.
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
;
240 // specialize to raw audio format if necessary
241 if (ioFormat
->type
== B_MEDIA_UNKNOWN_TYPE
)
242 ioFormat
->type
= B_MEDIA_RAW_AUDIO
;
244 // we require a raw audio format
245 if (ioFormat
->type
!= B_MEDIA_RAW_AUDIO
)
246 return B_MEDIA_BAD_FORMAT
;
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
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;
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
;
268 AudioMixer::GetNextInput(int32
*cookie
, media_input
*out_input
)
270 TRACE("AudioMixer::GetNextInput\n");
272 // our 0th input is always a wildcard and free one
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");
285 // the other inputs are the currently connected ones
288 input
= fCore
->Input(*cookie
- 1);
293 *out_input
= input
->MediaInput();
301 AudioMixer::DisposeInputCookie(int32 cookie
)
308 AudioMixer::BufferReceived(BBuffer
*buffer
)
311 if (buffer
->Header()->type
== B_MEDIA_PARAMETERS
) {
312 TRACE("Control Buffer Received\n");
313 ApplyParameterData(buffer
->Data(), buffer
->SizeUsed());
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);
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
);
330 AudioMixer::HandleInputBuffer(BBuffer
* buffer
, bigtime_t lateness
)
332 bigtime_t variation
= 0;
333 if (lateness
> fLastLateness
)
334 variation
= lateness
-fLastLateness
;
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");
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
;
348 NotifyLateProducer(source
, variation
, TimeSource()->Now());
350 if (RunMode() == B_DROP_DATA
) {
351 TRACE("AudioMixer: dropping buffer\n");
357 fLastLateness
= lateness
;
360 fCore
->BufferReceived(buffer
, lateness
);
366 AudioMixer::ProducerDataStatus(const media_destination
& for_whom
,
367 int32 status
, bigtime_t at_performance_time
)
370 if (IsValidDest(for_whom))
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);
377 // the for_whom destination is not being sent correctly - verify in HandleEvent loop
385 AudioMixer::GetLatencyFor(const media_destination
&for_whom
,
386 bigtime_t
*out_latency
, media_node_id
*out_timesource
)
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
;
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();
398 printf("AudioMixer::GetLatencyFor %" B_PRIdBIGTIME
", timesource is %"
399 B_PRId32
"\n", *out_latency
, *out_timesource
);
406 AudioMixer::Connected(const media_source
&producer
,
407 const media_destination
&where
, const media_format
&with_format
,
408 media_input
*out_input
)
410 PRINT_FORMAT("AudioMixer::Connected: ", with_format
);
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
;
424 // a BBufferProducer is connecting to our BBufferConsumer
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
;
433 // we assign a new id (!= 0) to the newly created input
434 out_input
->destination
.id
= fCore
->CreateInputID();
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
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
);
445 // add a new input to the mixer engine
447 input
= fCore
->AddInput(*out_input
);
449 fCore
->Settings()->LoadConnectionSettings(input
);
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
456 // But we have no special buffer requirements anyway...
458 UpdateParameterWeb();
465 AudioMixer::Disconnected(const media_source
&producer
,
466 const media_destination
&where
)
468 // One of our inputs has been disconnected
470 // check if it is really belongs to us
471 if (where
.port
!= ControlPort()) {
472 TRACE("AudioMixer::Disconnected wrong input port\n");
478 if (!fCore
->RemoveInput(where
.id
)) {
479 TRACE("AudioMixer::Disconnected can't remove input\n");
483 UpdateParameterWeb();
488 AudioMixer::FormatChanged(const media_source
&producer
,
489 const media_destination
&consumer
, int32 change_tag
,
490 const media_format
&format
)
492 // at some point in the future (indicated by change_tag and RequestCompleted()),
493 // we will receive buffers in a different format
495 TRACE("AudioMixer::FormatChanged\n");
497 if (consumer
.port
!= ControlPort() || consumer
.id
== 0)
498 return B_MEDIA_BAD_DESTINATION
;
500 if (fCore
->Settings()->RefuseInputFormatChange()) {
501 TRACE("AudioMixer::FormatChanged: input format change refused\n");
502 return B_NOT_ALLOWED
;
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
;
510 // tell core about format change
512 fCore
->InputFormatChanged(consumer
.id
, format
.u
.raw_audio
);
519 // #pragma mark - BBufferProducer methods
523 AudioMixer::FormatSuggestionRequested(media_type type
, int32 quality
,
524 media_format
*format
)
526 TRACE("AudioMixer::FormatSuggestionRequested\n");
528 // BBufferProducer function, a downstream consumer
529 // is asking for our output format
531 if (type
!= B_MEDIA_RAW_AUDIO
&& type
!= B_MEDIA_UNKNOWN_TYPE
)
532 return B_MEDIA_BAD_FORMAT
;
534 // we can produce any (wildcard) raw audio format
535 memset(format
, 0, sizeof(*format
));
536 format
->type
= B_MEDIA_RAW_AUDIO
;
542 AudioMixer::FormatProposal(const media_source
&output
, media_format
*ioFormat
)
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.
549 TRACE("AudioMixer::FormatProposal\n");
551 // we only have one output (id=0, port=ControlPort())
552 if (output
.id
!= 0 || output
.port
!= ControlPort())
553 return B_MEDIA_BAD_SOURCE
;
555 // specialize to raw audio format if necessary
556 if (ioFormat
->type
== B_MEDIA_UNKNOWN_TYPE
)
557 ioFormat
->type
= B_MEDIA_RAW_AUDIO
;
559 // we require a raw audio format
560 if (ioFormat
->type
!= B_MEDIA_RAW_AUDIO
)
561 return B_MEDIA_BAD_FORMAT
;
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.
573 AudioMixer::FormatChangeRequested(const media_source
&source
,
574 const media_destination
&destination
, media_format
*io_format
,
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.
581 TRACE("AudioMixer::FormatChangeRequested\n");
583 if (fCore
->Settings()->RefuseOutputFormatChange()) {
584 TRACE("AudioMixer::FormatChangeRequested: output format change refused\n");
590 status_t status
= B_OK
;
591 BBufferGroup
*group
= NULL
;
592 MixerOutput
*output
= fCore
->Output();
594 ERROR("AudioMixer::FormatChangeRequested: no output\n");
597 if (source
!= output
->MediaOutput().source
) {
598 ERROR("AudioMixer::FormatChangeRequested: wrong output source\n");
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");
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");
619 /* remove wildcards */
620 #if USE_MEDIA_FORMAT_WORKAROUND
621 multi_audio_format_specialize(&io_format
->u
.raw_audio
,
622 &fDefaultFormat
.u
.raw_audio
);
624 io_format
->SpecializeTo(&fDefaultFormat
);
628 FindLatencyFor(destination
, &fDownstreamLatency
, &id
);
629 TRACE("AudioMixer: Downstream Latency is %" B_PRIdBIGTIME
" usecs\n",
632 // SetDuration of one buffer
633 SetBufferDuration(buffer_duration(io_format
->u
.raw_audio
));
634 TRACE("AudioMixer: buffer duration is %" B_PRIdBIGTIME
" usecs\n",
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",
643 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
645 // we need to inform all connected *inputs* about *our* change in latency
646 PublishEventLatencyChange();
648 // TODO: we might need to create more buffers, to span a larger downstream
651 // apply latency change
652 fCore
->SetTimingInfo(TimeSource(), fDownstreamLatency
);
654 // apply format change
655 fCore
->OutputFormatChanged(io_format
->u
.raw_audio
);
657 status
= CreateBufferGroup(&group
);
662 fBufferGroup
= group
;
663 fCore
->SetOutputBufferGroup(fBufferGroup
);
673 AudioMixer::GetNextOutput(int32
*cookie
, media_output
*out_output
)
675 TRACE("AudioMixer::GetNextOutput\n");
681 MixerOutput
*output
= fCore
->Output();
683 *out_output
= output
->MediaOutput();
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");
701 AudioMixer::DisposeOutputCookie(int32 cookie
)
709 AudioMixer::SetBufferGroup(const media_source
&for_source
,
710 BBufferGroup
*newGroup
)
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
;
718 if (newGroup
== fBufferGroup
) {
719 // we're already using this buffergroup
725 status_t status
= CreateBufferGroup(&newGroup
);
729 fCore
->SetOutputBufferGroup(newGroup
);
731 fBufferGroup
= newGroup
;
739 AudioMixer::GetLatency(bigtime_t
*out_latency
)
741 // report our *total* latency: internal plus downstream plus scheduling
742 *out_latency
= EventLatency() + SchedulingLatency();
744 TRACE("AudioMixer::GetLatency %Ld\n", *out_latency
);
751 AudioMixer::LatencyChanged(const media_source
& source
,
752 const media_destination
& destination
, bigtime_t new_latency
, uint32 flags
)
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
);
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
);
768 FindLatencyFor(destination
, &l
, &id
);
769 TRACE("AudioMixer: Reported downstream Latency is %Ld usecs\n", l
);
773 fDownstreamLatency
= new_latency
;
774 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
776 // XXX we might need to create more buffers, to span a larger downstream
780 fCore
->SetTimingInfo(TimeSource(), fDownstreamLatency
);
781 PublishEventLatencyChange();
786 AudioMixer::PrepareToConnect(const media_source
&what
,
787 const media_destination
&where
, media_format
*format
,
788 media_source
*out_source
, char *out_name
)
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.
799 PRINT_FORMAT("AudioMixer::PrepareToConnect: suggested format", *format
);
801 // avoid loop connections
802 if (where
.port
== ControlPort())
803 return B_MEDIA_BAD_SOURCE
;
805 // is the source valid?
806 if (what
.port
!= ControlPort() || what
.id
!= 0)
807 return B_MEDIA_BAD_SOURCE
;
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
;
818 // are we already connected?
819 if (fCore
->Output() != 0) {
821 ERROR("AudioMixer::PrepareToConnect: already connected\n");
822 return B_MEDIA_ALREADY_CONNECTED
;
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
;
844 // other mixer's output is probably not connected
846 BMediaRoster
*roster
= BMediaRoster::Roster();
850 if (roster
->GetAudioMixer(&node
) == B_OK
851 && roster
->GetConnectedOutputsFor(node
, &out
, 1, &count
)
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
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
;
871 /* set source and suggest a name */
873 strcpy(out_name
, "Mixer Output");
875 /* remove wildcards */
876 #if USE_MEDIA_FORMAT_WORKAROUND
877 multi_audio_format_specialize(&format
->u
.raw_audio
,
878 &fDefaultFormat
.u
.raw_audio
);
880 format
->SpecializeTo(&fDefaultFormat
);
883 PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format
);
885 /* add output to core */
887 output
.node
= Node();
888 output
.source
= *out_source
;
889 output
.destination
= where
;
890 output
.format
= *format
;
891 strcpy(output
.name
, out_name
);
893 fCore
->EnableOutput(false);
894 fCore
->AddOutput(output
);
902 AudioMixer::Connect(status_t error
, const media_source
&source
,
903 const media_destination
&dest
, const media_format
&format
, char *io_name
)
905 TRACE("AudioMixer::Connect\n");
908 // are we still connected?
909 if (fCore
->Output() == 0) {
911 ERROR("AudioMixer::Connect: no longer connected\n");
917 // if an error occured, remove output from core
918 ERROR("AudioMixer::Connect failed with error 0x%08lX, removing "
919 "connection\n", error
);
921 fCore
->RemoveOutput();
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
;
931 // if the connection has no name, we set it now
932 if (strlen(io_name
) == 0)
933 strcpy(io_name
, "Mixer Output");
935 // Now that we're connected, we can determine our downstream latency.
937 FindLatencyFor(dest
, &fDownstreamLatency
, &id
);
938 TRACE("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency
);
940 // SetDuration of one buffer
941 SetBufferDuration(buffer_duration(format
.u
.raw_audio
));
942 TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
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
);
950 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
952 // we need to inform all connected *inputs* about *our* change in latency
953 PublishEventLatencyChange();
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.
962 BBufferGroup
*group
= NULL
;
963 if (CreateBufferGroup(&group
) != B_OK
)
965 fBufferGroup
= group
;
968 ASSERT(fCore
->Output() != 0);
970 // our source should still be valid, too
971 ASSERT(fCore
->Output()->MediaOutput().source
.id
== 0);
972 ASSERT(fCore
->Output()->MediaOutput().source
.port
== ControlPort());
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
;
979 fCore
->EnableOutput(true);
980 fCore
->SetTimingInfo(TimeSource(), fDownstreamLatency
);
981 fCore
->SetOutputBufferGroup(fBufferGroup
);
983 fCore
->Settings()->LoadConnectionSettings(fCore
->Output());
986 UpdateParameterWeb();
991 AudioMixer::Disconnect(const media_source
& what
, const media_destination
& where
)
993 TRACE("AudioMixer::Disconnect\n");
996 // Make sure that our connection is the one being disconnected
997 MixerOutput
* output
= fCore
->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");
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;
1015 fCore
->RemoveOutput();
1017 // destroy buffer group
1018 delete fBufferGroup
;
1019 fBufferGroup
= NULL
;
1020 fCore
->SetOutputBufferGroup(0);
1023 UpdateParameterWeb();
1028 AudioMixer::LateNoticeReceived(const media_source
& what
, bigtime_t howMuch
,
1029 bigtime_t performanceTime
)
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
1035 ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", howMuch
,
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
)
1045 fInternalLatency
+= howMuch
;
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
;
1052 fLastLateNotification
= TimeSource()->Now() + howMuch
;
1054 TRACE("AudioMixer: increasing internal latency to %"
1055 B_PRIdBIGTIME
" usec\n", fInternalLatency
);
1056 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
1058 PublishEventLatencyChange();
1064 AudioMixer::EnableOutput(const media_source
& what
, bool enabled
,
1065 int32 */
*deprecated*/
)
1067 // we only have one output
1068 if (what
.id
!= 0 || what
.port
!= ControlPort())
1072 fCore
->EnableOutput(enabled
);
1077 // #pragma mark - BMediaEventLooper methods
1081 AudioMixer::NodeRegistered()
1083 UpdateParameterWeb();
1084 SetPriority(B_REAL_TIME_PRIORITY
);
1090 AudioMixer::SetTimeSource(BTimeSource
* timeSource
)
1092 TRACE("AudioMixer::SetTimeSource: timesource is now %ld\n",
1095 fCore
->SetTimingInfo(timeSource
, fDownstreamLatency
);
1101 AudioMixer::HandleEvent(const media_timed_event
*event
, bigtime_t lateness
,
1104 switch (event
->type
) {
1105 case BTimedEventQueue::B_HANDLE_BUFFER
:
1107 HandleInputBuffer((BBuffer
*)event
->pointer
, lateness
);
1108 ((BBuffer
*)event
->pointer
)->Recycle();
1112 case BTimedEventQueue::B_START
:
1114 TRACE("AudioMixer::HandleEvent: B_START\n");
1115 if (RunState() != B_STARTED
) {
1123 case BTimedEventQueue::B_STOP
:
1125 TRACE("AudioMixer::HandleEvent: B_STOP\n");
1126 // stopped - don't process any more buffers, flush all buffers
1128 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS
, true,
1129 BTimedEventQueue::B_HANDLE_BUFFER
);
1136 case BTimedEventQueue::B_DATA_STATUS
:
1138 ERROR("DataStatus message\n");
1142 case MIXER_PROCESS_EVENT
:
1152 // #pragma mark - AudioMixer methods
1156 AudioMixer::PublishEventLatencyChange()
1158 // our event (processing + downstream) latency has changed,
1159 // and we need tell all inputs about this
1161 TRACE("AudioMixer::PublishEventLatencyChange\n");
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());
1181 AudioMixer::CreateBufferGroup(BBufferGroup
** buffer
) const
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;
1187 TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, "
1188 "BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency
,
1189 BufferDuration(), count
);
1195 uint32 size
= fCore
->Output()->MediaOutput().format
.u
.raw_audio
.buffer_size
;
1198 TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n",
1201 BBufferGroup
* buf
= new BBufferGroup(size
, count
);
1205 status_t status
= buf
->InitCheck();
1216 AudioMixer::SendBuffer(BBuffer
* buffer
, MixerOutput
* output
)
1218 return BBufferProducer::SendBuffer(buffer
, output
->MediaOutput().source
,
1219 output
->MediaOutput().destination
);
1224 AudioMixer::dB_to_Gain(float db
)
1226 TRACE("dB_to_Gain: dB in: %01.2f ", db
);
1227 if (fCore
->Settings()->NonLinearGainSlider()) {
1229 db
= db
* (pow(abs(DB_MAX
), (1.0 / DB_EXPONENT_POSITIVE
))
1231 db
= pow(db
, DB_EXPONENT_POSITIVE
);
1234 db
= db
* (pow(abs(DB_MIN
), (1.0 / DB_EXPONENT_NEGATIVE
))
1236 db
= pow(db
, DB_EXPONENT_NEGATIVE
);
1240 TRACE("dB out: %01.2f\n", db
);
1241 return pow(10.0, db
/ 20.0);
1246 AudioMixer::Gain_to_dB(float gain
)
1249 db
= 20.0 * log10(gain
);
1250 if (fCore
->Settings()->NonLinearGainSlider()) {
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
)));
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
)));
1267 // #pragma mark - BControllable methods
1271 AudioMixer::GetParameterValue(int32 id
, bigtime_t
*last_change
, void *value
,
1274 TRACE("GetParameterValue: id 0x%08lx, ioSize %ld\n", id
, *ioSize
);
1275 int param
= PARAM(id
);
1277 if (PARAM_IS_ETC(id
)) {
1279 case 10: // Attenuate mixer output by 3dB
1280 *ioSize
= sizeof(int32
);
1281 static_cast<int32
*>(value
)[0] = fCore
->Settings()->AttenuateOutput();
1283 case 20: // Use non linear gain sliders
1284 *ioSize
= sizeof(int32
);
1285 static_cast<int32
*>(value
)[0] = fCore
->Settings()->NonLinearGainSlider();
1287 case 30: // Display balance control for stereo connections
1288 *ioSize
= sizeof(int32
);
1289 static_cast<int32
*>(value
)[0] = fCore
->Settings()->UseBalanceControl();
1291 case 40: // Allow output channel remapping
1292 *ioSize
= sizeof(int32
);
1293 static_cast<int32
*>(value
)[0] = fCore
->Settings()->AllowOutputChannelRemapping();
1295 case 50: // Allow input channel remapping
1296 *ioSize
= sizeof(int32
);
1297 static_cast<int32
*>(value
)[0] = fCore
->Settings()->AllowInputChannelRemapping();
1299 case 60: // Input gain controls
1300 *ioSize
= sizeof(int32
);
1301 static_cast<int32
*>(value
)[0] = fCore
->Settings()->InputGainControls();
1303 case 70: // Resampling algorithm
1304 *ioSize
= sizeof(int32
);
1305 static_cast<int32
*>(value
)[0] = fCore
->Settings()->ResamplingAlgorithm();
1307 case 80: // Refuse output format changes
1308 *ioSize
= sizeof(int32
);
1309 static_cast<int32
*>(value
)[0] = fCore
->Settings()->RefuseOutputFormatChange();
1311 case 90: // Refuse input format changes
1312 *ioSize
= sizeof(int32
);
1313 static_cast<int32
*>(value
)[0] = fCore
->Settings()->RefuseInputFormatChange();
1316 ERROR("unhandled ETC 0x%08lx\n", id
);
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
)))
1323 if (PARAM_IS_MUTE(id
)) {
1324 // output mute control
1325 if (*ioSize
< sizeof(int32
))
1327 *ioSize
= sizeof(int32
);
1328 static_cast<int32
*>(value
)[0] = output
->IsMuted();
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))
1336 *ioSize
= sizeof(float);
1337 static_cast<float *>(value
)[0] = GAIN_TO_DB((output
->GetOutputChannelGain(0) + output
->GetOutputChannelGain(1)) / 2);
1339 // multi channel control
1340 if (*ioSize
== sizeof(float)) {
1341 // get combined gain for all controls
1343 for (int channel
= 0;
1344 channel
< output
->GetOutputChannelCount();
1347 output
->GetOutputChannelGain(channel
));
1349 static_cast<float *>(value
)[0] = gain
1350 / output
->GetOutputChannelCount();
1352 if (*ioSize
< output
->GetOutputChannelCount()
1356 *ioSize
= output
->GetOutputChannelCount() * sizeof(float);
1358 for (int channel
= 0;
1359 channel
< output
->GetOutputChannelCount();
1361 static_cast<float *>(value
)[channel
]
1362 = GAIN_TO_DB(output
->GetOutputChannelGain(channel
));
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))
1374 *ioSize
= sizeof(float);
1375 static_cast<float *>(value
)[0] = v
* 100;
1377 if (PARAM_IS_SRC_ENABLE(id
)) {
1378 if (*ioSize
< sizeof(int32
))
1380 *ioSize
= sizeof(int32
);
1381 static_cast<int32
*>(value
)[0] = output
->HasOutputChannelSource(PARAM_CHAN(id
), PARAM_SRC(id
));
1383 if (PARAM_IS_SRC_GAIN(id
)) {
1384 if (*ioSize
< sizeof(float))
1386 *ioSize
= sizeof(float);
1387 static_cast<float *>(value
)[0] = GAIN_TO_PERCENT(output
->GetOutputChannelSourceGain(PARAM_CHAN(id
), PARAM_SRC(id
)));
1391 for (int i
= 0; (input
= fCore
->Input(i
)); i
++)
1392 if (input
->ID() == param
)
1394 if (!input
|| (!PARAM_IS_MUTE(id
) && !PARAM_IS_GAIN(id
) && !PARAM_IS_DST_ENABLE(id
) && !PARAM_IS_BALANCE(id
)))
1396 if (PARAM_IS_MUTE(id
)) {
1397 // input mute control
1398 if (*ioSize
< sizeof(int32
))
1400 *ioSize
= sizeof(int32
);
1401 static_cast<int32
*>(value
)[0] = !input
->IsEnabled();
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))
1411 *ioSize
= sizeof(float);
1412 static_cast<float *>(value
)[0] = GAIN_TO_DB((input
->GetInputChannelGain(0) + input
->GetInputChannelGain(1)) / 2);
1414 // multi channel control
1415 if (*ioSize
< input
->GetInputChannelCount() * sizeof(float))
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
));
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))
1427 *ioSize
= sizeof(float);
1428 static_cast<float *>(value
)[0] = GAIN_TO_DB((input
->GetMixerChannelGain(0) + input
->GetMixerChannelGain(1)) / 2);
1430 // multi channel control
1431 if (*ioSize
< input
->GetMixerChannelCount() * sizeof(float))
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
));
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))
1448 *ioSize
= sizeof(float);
1449 static_cast<float *>(value
)[0] = v
* 100;
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))
1458 *ioSize
= sizeof(float);
1459 static_cast<float *>(value
)[0] = v
* 100;
1462 if (PARAM_IS_DST_ENABLE(id
)) {
1463 if (*ioSize
< sizeof(int32
))
1465 *ioSize
= sizeof(int32
);
1466 static_cast<int32
*>(value
)[0] = input
->HasInputChannelDestination(PARAM_CHAN(id
), PARAM_DST(id
));
1469 *last_change
= TimeSource()->Now(); // XXX we could do better
1479 AudioMixer::SetParameterValue(int32 id
, bigtime_t when
, const void *value
,
1482 TRACE("SetParameterValue: id 0x%08lx, size %ld\n", id
, size
);
1483 bool update
= false;
1484 int param
= PARAM(id
);
1486 if (PARAM_IS_ETC(id
)) {
1488 case 10: // Attenuate mixer output by 3dB
1489 if (size
!= sizeof(int32
))
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);
1495 case 20: // Use non linear gain sliders
1496 if (size
!= sizeof(int32
))
1498 fCore
->Settings()->SetNonLinearGainSlider(static_cast<const int32
*>(value
)[0]);
1499 update
= true; // XXX should use BroadcastChangedParameter()
1501 case 30: // Display balance control for stereo connections
1502 if (size
!= sizeof(int32
))
1504 fCore
->Settings()->SetUseBalanceControl(static_cast<const int32
*>(value
)[0]);
1507 case 40: // Allow output channel remapping
1508 if (size
!= sizeof(int32
))
1510 fCore
->Settings()->SetAllowOutputChannelRemapping(static_cast<const int32
*>(value
)[0]);
1513 case 50: // Allow input channel remapping
1514 if (size
!= sizeof(int32
))
1516 fCore
->Settings()->SetAllowInputChannelRemapping(static_cast<const int32
*>(value
)[0]);
1519 case 60: // Input gain controls represent
1520 // (0, "Physical input channels")
1521 // (1, "Virtual output channels")
1522 if (size
!= sizeof(int32
))
1524 fCore
->Settings()->SetInputGainControls(static_cast<const int32
*>(value
)[0]);
1525 update
= true; // XXX should use BroadcastChangedParameter()
1527 case 70: // Resampling algorithm
1528 if (size
!= sizeof(int32
))
1530 fCore
->Settings()->SetResamplingAlgorithm(static_cast<const int32
*>(value
)[0]);
1531 fCore
->UpdateResamplingAlgorithm();
1533 case 80: // Refuse output format changes
1534 if (size
!= sizeof(int32
))
1536 fCore
->Settings()->SetRefuseOutputFormatChange(static_cast<const int32
*>(value
)[0]);
1538 case 90: // Refuse input format changes
1539 if (size
!= sizeof(int32
))
1541 fCore
->Settings()->SetRefuseInputFormatChange(static_cast<const int32
*>(value
)[0]);
1544 ERROR("unhandled ETC 0x%08lx\n", id
);
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
)))
1551 if (PARAM_IS_MUTE(id
)) {
1552 // output mute control
1553 if (size
!= sizeof(int32
))
1555 output
->SetMuted(static_cast<const int32
*>(value
)[0]);
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
);
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();
1578 output
->SetOutputChannelGain(channel
,
1582 if (size
< output
->GetOutputChannelCount() * sizeof(float))
1584 for (int channel
= 0;
1585 channel
< output
->GetOutputChannelCount();
1587 output
->SetOutputChannelGain(channel
,
1588 DB_TO_GAIN(static_cast<const float *>(
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
);
1605 if (PARAM_IS_SRC_ENABLE(id
)) {
1606 if (size
!= sizeof(int32
))
1608 if (static_cast<const int32
*>(value
)[0]) {
1609 output
->AddOutputChannelSource(PARAM_CHAN(id
), PARAM_SRC(id
));
1611 output
->RemoveOutputChannelSource(PARAM_CHAN(id
), PARAM_SRC(id
));
1614 if (PARAM_IS_SRC_GAIN(id
)) {
1615 if (size
!= sizeof(float))
1617 output
->SetOutputChannelSourceGain(PARAM_CHAN(id
), PARAM_SRC(id
), PERCENT_TO_GAIN(static_cast<const float *>(value
)[0]));
1619 fCore
->Settings()->SaveConnectionSettings(output
);
1622 for (int i
= 0; (input
= fCore
->Input(i
)); i
++)
1623 if (input
->ID() == param
)
1625 if (!input
|| (!PARAM_IS_MUTE(id
) && !PARAM_IS_GAIN(id
) && !PARAM_IS_DST_ENABLE(id
) && !PARAM_IS_BALANCE(id
)))
1627 if (PARAM_IS_MUTE(id
)) {
1628 // input mute control
1629 if (size
!= sizeof(int32
))
1631 input
->SetEnabled(!static_cast<const int32
*>(value
)[0]);
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
);
1648 // multi channel control
1649 if (size
< input
->GetInputChannelCount() * sizeof(float))
1651 for (int chan
= 0; chan
< input
->GetInputChannelCount(); chan
++)
1652 input
->SetInputChannelGain(chan
, DB_TO_GAIN(static_cast<const float *>(value
)[chan
]));
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
);
1667 // multi channel control
1668 if (size
< input
->GetMixerChannelCount() * sizeof(float))
1670 for (int chan
= 0; chan
< input
->GetMixerChannelCount(); chan
++)
1671 input
->SetMixerChannelGain(chan
, DB_TO_GAIN(static_cast<const float *>(value
)[chan
]));
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
);
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
);
1700 if (PARAM_IS_DST_ENABLE(id
)) {
1701 if (size
!= sizeof(int32
))
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
));
1708 BroadcastNewParameterValue(when
, PARAM_DST_ENABLE(PARAM(id
), oldchan
, PARAM_DST(id
)), &null
, sizeof(null
));
1710 input
->AddInputChannelDestination(PARAM_CHAN(id
), PARAM_DST(id
));
1712 input
->RemoveInputChannelDestination(PARAM_CHAN(id
), PARAM_DST(id
));
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
1724 fCore
->Settings()->SaveConnectionSettings(input
);
1727 BroadcastNewParameterValue(when
, id
, const_cast<void *>(value
), size
);
1732 UpdateParameterWeb();
1737 AudioMixer::UpdateParameterWeb()
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
;
1752 top
= web
->MakeGroup(B_TRANSLATE("Gain controls"));
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
);
1759 group
->MakeNullParameter(PARAM_STR2(0), B_MEDIA_RAW_AUDIO
,
1760 B_TRANSLATE("not connected"), B_GENERIC
);
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);
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());
1782 group
->MakeNullParameter(PARAM_STR3(0), B_MEDIA_RAW_AUDIO
,
1783 B_TRANSLATE("To output"), B_WEB_BUFFER_OUTPUT
);
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);
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());
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);
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());
1833 group
->MakeNullParameter(PARAM_STR3(in
->ID()), B_MEDIA_RAW_AUDIO
,
1834 B_TRANSLATE("To master"), B_WEB_BUFFER_OUTPUT
);
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
);
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("");
1848 group
->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO
,
1849 B_TRANSLATE("not connected"), B_GENERIC
);
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
, "",
1861 subsubgroup
->MakeContinuousParameter(
1862 PARAM_SRC_GAIN(0, chan
, src
), B_MEDIA_RAW_AUDIO
,
1863 StringForChannelType(buf
, src
), B_GAIN
, "%", 0.0,
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
);
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("");
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
),
1896 top
= web
->MakeGroup(B_TRANSLATE("Setup")); // top level group
1897 group
= top
->MakeGroup("");
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"),
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
);
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"));
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"));
1922 // Note: The following code is outcommented on purpose
1923 // and is about to be modified at a later point
1925 dp->AddItem(1, B_TRANSLATE("Drop/repeat samples (template based)"));
1926 dp->AddItem(3, B_TRANSLATE("17th order filtering"));
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
);
1934 SetParameterWeb(web
);
1938 #if USE_MEDIA_FORMAT_WORKAROUND
1940 raw_audio_format_specialize(media_raw_audio_format
*format
,
1941 const media_raw_audio_format
*other
)
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
;
1959 multi_audio_info_specialize(media_multi_audio_info
*format
,
1960 const media_multi_audio_info
*other
)
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
;
1972 multi_audio_format_specialize(media_multi_audio_format
*format
,
1973 const media_multi_audio_format
*other
)
1975 raw_audio_format_specialize(format
, other
);
1976 multi_audio_info_specialize(format
, other
);