* Minor cleanup.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30074 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-04-09 17:22:00 +00:00
parent 9cfc4c2ff8
commit e7cdf7f3f5
@@ -1,9 +1,11 @@
/* /*
* Copyright 2002 David Shipman, * Copyright 2002 David Shipman,
* Copyright 2003-2007 Marcus Overhagen * Copyright 2003-2007 Marcus Overhagen
* Copyright 2007 Haiku Inc. All rights reserved. * Copyright 2007-2009 Haiku Inc. All rights reserved.
*
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "AudioMixer.h" #include "AudioMixer.h"
#include "MixerCore.h" #include "MixerCore.h"
#include "MixerInput.h" #include "MixerInput.h"
@@ -31,29 +33,69 @@
#define USE_MEDIA_FORMAT_WORKAROUND 1 #define USE_MEDIA_FORMAT_WORKAROUND 1
#define DB_TO_GAIN(db) dB_to_Gain((db))
#define GAIN_TO_DB(gain) Gain_to_dB((gain))
#define PERCENT_TO_GAIN(pct) ((pct) / 100.0)
#define GAIN_TO_PERCENT(gain) ((gain) * 100.0)
// the id is encoded with 16 bits
// then chan and src (or dst) are encoded with 6 bits
// the unique number with 4 bits
// the PARAM_ETC etc is encoded with 26 bits
#define PARAM_SRC_ENABLE(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x1)
#define PARAM_SRC_GAIN(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x2)
#define PARAM_DST_ENABLE(id, chan, dst) (((id) << 16) | ((chan) << 10) | ((dst) << 4) | 0x3)
#define PARAM_ETC(etc) (((etc) << 16) | 0x4)
#define PARAM_SRC_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x5)
#define PARAM_DST_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x6)
#define PARAM_MUTE(id) (((id) << 16) | 0x7)
#define PARAM_GAIN(id) (((id) << 16) | 0x8)
#define PARAM_BALANCE(id) (((id) << 16) | 0x9)
#define PARAM_STR1(id) (((id) << 16) | ((1) << 10) | 0xa)
#define PARAM_STR2(id) (((id) << 16) | ((2) << 10) | 0xa)
#define PARAM_STR3(id) (((id) << 16) | ((3) << 10) | 0xa)
#define PARAM_STR4(id) (((id) << 16) | ((4) << 10) | 0xa)
#define PARAM_STR5(id) (((id) << 16) | ((5) << 10) | 0xa)
#define PARAM_STR6(id) (((id) << 16) | ((6) << 10) | 0xa)
#define PARAM_STR7(id) (((id) << 16) | ((7) << 10) | 0xa)
#define PARAM(id) ((id) >> 16)
#define ETC(id) ((id) >> 16)
#define PARAM_CHAN(id) (((id) >> 10) & 0x3f)
#define PARAM_SRC(id) (((id) >> 4) & 0x3f)
#define PARAM_DST(id) (((id) >> 4) & 0x3f)
#define PARAM_IS_SRC_ENABLE(id) (((id) & 0xf) == 0x1)
#define PARAM_IS_SRC_GAIN(id) (((id) & 0xf) == 0x2)
#define PARAM_IS_DST_ENABLE(id) (((id) & 0xf) == 0x3)
#define PARAM_IS_ETC(id) (((id) & 0xf) == 0x4)
#define PARAM_IS_MUTE(id) (((id) & 0xf) == 0x7)
#define PARAM_IS_GAIN(id) (((id) & 0xf) == 0x8)
#define PARAM_IS_BALANCE(id) (((id) & 0xf) == 0x9)
#if USE_MEDIA_FORMAT_WORKAROUND #if USE_MEDIA_FORMAT_WORKAROUND
static void static void
multi_audio_format_specialize(media_multi_audio_format *format, multi_audio_format_specialize(media_multi_audio_format *format,
const media_multi_audio_format *other); const media_multi_audio_format *other);
#endif #endif
#define FORMAT_USER_DATA_TYPE 0x7294a8f3 #define FORMAT_USER_DATA_TYPE 0x7294a8f3
#define FORMAT_USER_DATA_MAGIC_1 0xc84173bd #define FORMAT_USER_DATA_MAGIC_1 0xc84173bd
#define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d #define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d
AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer) AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
: BMediaNode("Audio Mixer"), : BMediaNode("Audio Mixer"),
BBufferConsumer(B_MEDIA_RAW_AUDIO), BBufferConsumer(B_MEDIA_RAW_AUDIO),
BBufferProducer(B_MEDIA_RAW_AUDIO), BBufferProducer(B_MEDIA_RAW_AUDIO),
BControllable(), BControllable(),
BMediaEventLooper(), BMediaEventLooper(),
fAddOn(addOn), fAddOn(addOn),
fCore(new MixerCore(this)), fCore(new MixerCore(this)),
fWeb(0), fWeb(0),
fBufferGroup(0), fBufferGroup(0),
fDownstreamLatency(1), fDownstreamLatency(1),
fInternalLatency(1), fInternalLatency(1),
fDisableStop(false) fDisableStop(false)
{ {
BMediaNode::AddNodeKind(B_SYSTEM_MIXER); BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
@@ -83,6 +125,7 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
ApplySettings(); ApplySettings();
} }
AudioMixer::~AudioMixer() AudioMixer::~AudioMixer()
{ {
BMediaEventLooper::Quit(); BMediaEventLooper::Quit();
@@ -102,6 +145,7 @@ AudioMixer::~AudioMixer()
DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0); DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0);
} }
void void
AudioMixer::ApplySettings() AudioMixer::ApplySettings()
{ {
@@ -110,17 +154,19 @@ AudioMixer::ApplySettings()
fCore->Unlock(); fCore->Unlock();
} }
void void
AudioMixer::DisableNodeStop() AudioMixer::DisableNodeStop()
{ {
fDisableStop = true; fDisableStop = true;
} }
//
// BMediaNode methods
//
void AudioMixer::Stop(bigtime_t performance_time, bool immediate) // #pragma mark - BMediaNode methods
void
AudioMixer::Stop(bigtime_t performance_time, bool immediate)
{ {
if (fDisableStop) { if (fDisableStop) {
TRACE("AudioMixer STOP is disabled\n"); TRACE("AudioMixer STOP is disabled\n");
@@ -130,16 +176,17 @@ void AudioMixer::Stop(bigtime_t performance_time, bool immediate)
} }
} }
BMediaAddOn *
BMediaAddOn*
AudioMixer::AddOn(int32 *internal_id) const AudioMixer::AddOn(int32 *internal_id) const
{ {
*internal_id = 0; *internal_id = 0;
return fAddOn; return fAddOn;
} }
//
// BBufferConsumer methods // #pragma mark - BBufferConsumer methods
//
status_t status_t
AudioMixer::HandleMessage(int32 message, const void *data, size_t size) AudioMixer::HandleMessage(int32 message, const void *data, size_t size)
@@ -148,6 +195,7 @@ AudioMixer::HandleMessage(int32 message, const void *data, size_t size)
return B_ERROR; return B_ERROR;
} }
status_t status_t
AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat) AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat)
{ {
@@ -187,6 +235,7 @@ AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat)
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::GetNextInput(int32 *cookie, media_input *out_input) AudioMixer::GetNextInput(int32 *cookie, media_input *out_input)
{ {
@@ -219,12 +268,14 @@ AudioMixer::GetNextInput(int32 *cookie, media_input *out_input)
return B_OK; return B_OK;
} }
void void
AudioMixer::DisposeInputCookie(int32 cookie) AudioMixer::DisposeInputCookie(int32 cookie)
{ {
// nothing to do // nothing to do
} }
void void
AudioMixer::BufferReceived(BBuffer *buffer) AudioMixer::BufferReceived(BBuffer *buffer)
{ {
@@ -248,9 +299,8 @@ AudioMixer::BufferReceived(BBuffer *buffer)
// to receive the buffer at the right time, // to receive the buffer at the right time,
// push it through the event looper // push it through the event looper
media_timed_event event(buffer->Header()->start_time, media_timed_event event(buffer->Header()->start_time,
BTimedEventQueue::B_HANDLE_BUFFER, BTimedEventQueue::B_HANDLE_BUFFER, buffer,
buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
BTimedEventQueue::B_RECYCLE_BUFFER);
EventQueue()->AddEvent(event); EventQueue()->AddEvent(event);
} }
@@ -289,9 +339,10 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness)
*/ */
} }
void void
AudioMixer::ProducerDataStatus( const media_destination &for_whom, AudioMixer::ProducerDataStatus(const media_destination& for_whom,
int32 status, bigtime_t at_performance_time) int32 status, bigtime_t at_performance_time)
{ {
/* /*
if (IsValidDest(for_whom)) if (IsValidDest(for_whom))
@@ -307,10 +358,10 @@ AudioMixer::ProducerDataStatus( const media_destination &for_whom,
*/ */
} }
status_t status_t
AudioMixer::GetLatencyFor(const media_destination &for_whom, AudioMixer::GetLatencyFor(const media_destination &for_whom,
bigtime_t *out_latency, bigtime_t *out_latency, media_node_id *out_timesource)
media_node_id *out_timesource)
{ {
// we have multiple inputs with different IDs, but // we have multiple inputs with different IDs, but
// the port number must match our ControlPort() // the port number must match our ControlPort()
@@ -323,15 +374,16 @@ AudioMixer::GetLatencyFor(const media_destination &for_whom,
*out_timesource = TimeSource()->ID(); *out_timesource = TimeSource()->ID();
printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n", printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n",
*out_latency, *out_latency, *out_timesource);
*out_timesource);
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::Connected(const media_source &producer, const media_destination &where, AudioMixer::Connected(const media_source &producer,
const media_format &with_format, media_input *out_input) const media_destination &where, const media_format &with_format,
media_input *out_input)
{ {
PRINT_FORMAT("AudioMixer::Connected: ", with_format); PRINT_FORMAT("AudioMixer::Connected: ", with_format);
@@ -339,11 +391,11 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
// BBufferProducer::PrepareToConnect() should have removed all wildcards. // BBufferProducer::PrepareToConnect() should have removed all wildcards.
if (out_input->format.u.raw_audio.frame_rate == 0) { if (out_input->format.u.raw_audio.frame_rate == 0) {
fprintf(stderr, "Audio Mixer Warning: " fprintf(stderr, "Audio Mixer Warning: "
"Producer (port %ld, id %ld) connected with frame_rate=0\n", "Producer (port %ld, id %ld) connected with frame_rate=0\n",
producer.port, producer.port, producer.id);
producer.id);
MixerOutput *output = fCore->Output(); MixerOutput *output = fCore->Output();
float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f; float frame_rate = output
? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f;
out_input->format.u.raw_audio.frame_rate = frame_rate; out_input->format.u.raw_audio.frame_rate = frame_rate;
} }
@@ -359,8 +411,9 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
// we assign a new id (!= 0) to the newly created input // we assign a new id (!= 0) to the newly created input
out_input->destination.id = fCore->CreateInputID(); out_input->destination.id = fCore->CreateInputID();
// We need to make sure that the outInput's name field contains a valid name, // We need to make sure that the outInput's name field contains a valid
// the name given the connection by the producer may still be an empty string. // name, the name given the connection by the producer may still be an
// empty string.
// if the input has no name, assign one // if the input has no name, assign one
if (strlen(out_input->name) == 0) if (strlen(out_input->name) == 0)
sprintf(out_input->name, "Input %ld", out_input->destination.id); sprintf(out_input->name, "Input %ld", out_input->destination.id);
@@ -373,8 +426,9 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
fCore->Unlock(); fCore->Unlock();
// If we want the producer to use a specific BBufferGroup, we now need to call // If we want the producer to use a specific BBufferGroup, we now need
// BMediaRoster::SetOutputBuffersFor() here to set the producer's buffer group. // to call BMediaRoster::SetOutputBuffersFor() here to set the producer's
// buffer group.
// But we have no special buffer requirements anyway... // But we have no special buffer requirements anyway...
UpdateParameterWeb(); UpdateParameterWeb();
@@ -382,8 +436,10 @@ AudioMixer::Connected(const media_source &producer, const media_destination &whe
return B_OK; return B_OK;
} }
void void
AudioMixer::Disconnected(const media_source &producer, const media_destination &where) AudioMixer::Disconnected(const media_source &producer,
const media_destination &where)
{ {
// One of our inputs has been disconnected // One of our inputs has been disconnected
@@ -403,9 +459,11 @@ AudioMixer::Disconnected(const media_source &producer, const media_destination &
UpdateParameterWeb(); UpdateParameterWeb();
} }
status_t status_t
AudioMixer::FormatChanged(const media_source &producer, const media_destination &consumer, AudioMixer::FormatChanged(const media_source &producer,
int32 change_tag, const media_format &format) const media_destination &consumer, int32 change_tag,
const media_format &format)
{ {
// at some point in the future (indicated by change_tag and RequestCompleted()), // at some point in the future (indicated by change_tag and RequestCompleted()),
// we will receive buffers in a different format // we will receive buffers in a different format
@@ -430,12 +488,13 @@ AudioMixer::FormatChanged(const media_source &producer, const media_destination
return B_OK; return B_OK;
} }
//
// BBufferProducer methods // #pragma mark - BBufferProducer methods
//
status_t status_t
AudioMixer::FormatSuggestionRequested(media_type type, int32 quality, media_format *format) AudioMixer::FormatSuggestionRequested(media_type type, int32 quality,
media_format *format)
{ {
TRACE("AudioMixer::FormatSuggestionRequested\n"); TRACE("AudioMixer::FormatSuggestionRequested\n");
@@ -451,6 +510,7 @@ AudioMixer::FormatSuggestionRequested(media_type type, int32 quality, media_form
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat) AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
{ {
@@ -476,14 +536,16 @@ AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
return B_OK; return B_OK;
} }
// If the format isn't good, put a good format into *io_format and return error /*! If the format isn't good, put a good format into *io_format and return error
// If format has wildcard, specialize to what you can do (and change). If format has wildcard, specialize to what you can do (and change).
// If you can change the format, return OK. If you can change the format, return OK.
// The request comes from your destination sychronously, so you cannot ask it The request comes from your destination sychronously, so you cannot ask it
// whether it likes it -- you should assume it will since it asked. whether it likes it -- you should assume it will since it asked.
*/
status_t status_t
AudioMixer::FormatChangeRequested(const media_source &source, const media_destination &destination, AudioMixer::FormatChangeRequested(const media_source &source,
media_format *io_format, int32 *_deprecated_) const media_destination &destination, media_format *io_format,
int32 *_deprecated_)
{ {
// the downstream consumer node (soundcard) requested that we produce // the downstream consumer node (soundcard) requested that we produce
// another format, we need to check if the format is acceptable and // another format, we need to check if the format is acceptable and
@@ -508,25 +570,30 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
goto err; goto err;
} }
if (destination != output->MediaOutput().destination) { if (destination != output->MediaOutput().destination) {
ERROR("AudioMixer::FormatChangeRequested: wrong output destination (port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port, destination.id, output->MediaOutput().destination.port, output->MediaOutput().destination.id); ERROR("AudioMixer::FormatChangeRequested: wrong output destination "
if (destination.port == output->MediaOutput().destination.port && destination.id == output->MediaOutput().destination.id + 1) { "(port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port,
ERROR("AudioMixer::FormatChangeRequested: this might be the broken R5 multi audio add-on\n"); destination.id, output->MediaOutput().destination.port,
goto err; output->MediaOutput().destination.id);
} else { if (destination.port == output->MediaOutput().destination.port
goto err; && destination.id == output->MediaOutput().destination.id + 1) {
ERROR("AudioMixer::FormatChangeRequested: this might be the broken "
"R5 multi audio add-on\n");
} }
goto err;
} }
if (io_format->type != B_MEDIA_RAW_AUDIO && io_format->type != B_MEDIA_UNKNOWN_TYPE) { if (io_format->type != B_MEDIA_RAW_AUDIO
&& io_format->type != B_MEDIA_UNKNOWN_TYPE) {
ERROR("AudioMixer::FormatChangeRequested: wrong format type\n"); ERROR("AudioMixer::FormatChangeRequested: wrong format type\n");
goto err; goto err;
} }
/* remove wildcards */ /* remove wildcards */
#if USE_MEDIA_FORMAT_WORKAROUND #if USE_MEDIA_FORMAT_WORKAROUND
multi_audio_format_specialize(&io_format->u.raw_audio, &fDefaultFormat.u.raw_audio); multi_audio_format_specialize(&io_format->u.raw_audio,
#else &fDefaultFormat.u.raw_audio);
io_format->SpecializeTo(&fDefaultFormat); #else
#endif io_format->SpecializeTo(&fDefaultFormat);
#endif
media_node_id id; media_node_id id;
FindLatencyFor(destination, &fDownstreamLatency, &id); FindLatencyFor(destination, &fDownstreamLatency, &id);
@@ -537,7 +604,8 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration()); TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
// Our internal latency is at least the length of a full output buffer // Our internal latency is at least the length of a full output buffer
fInternalLatency = BufferDuration() + max(4500LL, bigtime_t(0.5 * BufferDuration())); fInternalLatency = BufferDuration()
+ max(4500LL, bigtime_t(0.5 * BufferDuration()));
TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency); TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
SetEventLatency(fDownstreamLatency + fInternalLatency); SetEventLatency(fDownstreamLatency + fInternalLatency);
@@ -545,7 +613,8 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
// we need to inform all connected *inputs* about *our* change in latency // we need to inform all connected *inputs* about *our* change in latency
PublishEventLatencyChange(); PublishEventLatencyChange();
// XXX we might need to create more buffers, to span a larger downstream latency // TODO: we might need to create more buffers, to span a larger downstream
// latency
// apply latency change // apply latency change
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
@@ -565,6 +634,7 @@ err:
return B_ERROR; return B_ERROR;
} }
status_t status_t
AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output) AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
{ {
@@ -592,6 +662,7 @@ AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::DisposeOutputCookie(int32 cookie) AudioMixer::DisposeOutputCookie(int32 cookie)
{ {
@@ -599,8 +670,10 @@ AudioMixer::DisposeOutputCookie(int32 cookie)
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGroup) AudioMixer::SetBufferGroup(const media_source &for_source,
BBufferGroup *newGroup)
{ {
PRINT("AudioMixer::SetBufferGroup\n"); PRINT("AudioMixer::SetBufferGroup\n");
// the downstream consumer (soundcard) node asks us to use another // the downstream consumer (soundcard) node asks us to use another
@@ -624,6 +697,7 @@ AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGrou
return B_OK; return B_OK;
} }
status_t status_t
AudioMixer::GetLatency(bigtime_t *out_latency) AudioMixer::GetLatency(bigtime_t *out_latency)
{ {
@@ -635,17 +709,20 @@ AudioMixer::GetLatency(bigtime_t *out_latency)
return B_OK; return B_OK;
} }
void void
AudioMixer::LatencyChanged(const media_source & source, const media_destination & destination, AudioMixer::LatencyChanged(const media_source& source,
bigtime_t new_latency, uint32 flags) const media_destination& destination, bigtime_t new_latency, uint32 flags)
{ {
if (source.port != ControlPort() || source.id != 0) { if (source.port != ControlPort() || source.id != 0) {
ERROR("AudioMixer::LatencyChanged: received but has wrong source %ld/%ld\n", source.port, source.id); ERROR("AudioMixer::LatencyChanged: received but has wrong source "
"%ld/%ld\n", source.port, source.id);
return; return;
} }
TRACE("AudioMixer::LatencyChanged: downstream latency from %ld/%ld to %ld/%ld changed from %Ld to %Ld\n", TRACE("AudioMixer::LatencyChanged: downstream latency from %ld/%ld to "
source.port, source.id, destination.port, destination.id, fDownstreamLatency, new_latency); "%ld/%ld changed from %Ld to %Ld\n", source.port, source.id,
destination.port, destination.id, fDownstreamLatency, new_latency);
#if DEBUG #if DEBUG
{ {
@@ -659,7 +736,8 @@ AudioMixer::LatencyChanged(const media_source & source, const media_destination
fDownstreamLatency = new_latency; fDownstreamLatency = new_latency;
SetEventLatency(fDownstreamLatency + fInternalLatency); SetEventLatency(fDownstreamLatency + fInternalLatency);
// XXX we might need to create more buffers, to span a larger downstream latency // XXX we might need to create more buffers, to span a larger downstream
// latency
fCore->Lock(); fCore->Lock();
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
@@ -669,16 +747,15 @@ AudioMixer::LatencyChanged(const media_source & source, const media_destination
status_t status_t
AudioMixer::PrepareToConnect(const media_source &what, AudioMixer::PrepareToConnect(const media_source &what,
const media_destination &where, const media_destination &where, media_format *format,
media_format *format, media_source *out_source, char *out_name)
media_source *out_source,
char *out_name)
{ {
TRACE("AudioMixer::PrepareToConnect\n"); TRACE("AudioMixer::PrepareToConnect\n");
// PrepareToConnect() is the second stage of format negotiations that happens // PrepareToConnect() is the second stage of format negotiations that
// inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat() // happens inside BMediaRoster::Connect(). At this point, the consumer's
// method has been called, and that node has potentially changed the proposed // AcceptFormat() method has been called, and that node has potentially
// format. It may also have left wildcards in the format. PrepareToConnect() // changed the proposed format.
// It may also have left wildcards in the format. PrepareToConnect()
// *must* fully specialize the format before returning! // *must* fully specialize the format before returning!
// we also create the new output connection and return it in out_source. // we also create the new output connection and return it in out_source.
@@ -693,7 +770,8 @@ AudioMixer::PrepareToConnect(const media_source &what,
return B_MEDIA_BAD_SOURCE; return B_MEDIA_BAD_SOURCE;
// is the format acceptable? // is the format acceptable?
if (format->type != B_MEDIA_RAW_AUDIO && format->type != B_MEDIA_UNKNOWN_TYPE) { if (format->type != B_MEDIA_RAW_AUDIO
&& format->type != B_MEDIA_UNKNOWN_TYPE) {
PRINT_FORMAT("AudioMixer::PrepareToConnect: bad format", *format); PRINT_FORMAT("AudioMixer::PrepareToConnect: bad format", *format);
return B_MEDIA_BAD_FORMAT; return B_MEDIA_BAD_FORMAT;
} }
@@ -732,14 +810,23 @@ AudioMixer::PrepareToConnect(const media_source &what,
media_output out; media_output out;
media_input in; media_input in;
int32 count; int32 count;
if (B_OK == roster->GetAudioMixer(&node) && B_OK == roster->GetConnectedOutputsFor(node, &out, 1, &count) && count == 1) { if (roster->GetAudioMixer(&node) == B_OK
&& roster->GetConnectedOutputsFor(node, &out, 1, &count)
== B_OK
&& count == 1) {
// use mixer output format // use mixer output format
format->u.raw_audio.channel_count = out.format.u.raw_audio.channel_count; format->u.raw_audio.channel_count
format->u.raw_audio.frame_rate = out.format.u.raw_audio.frame_rate; = out.format.u.raw_audio.channel_count;
} else if (B_OK == roster->GetAudioOutput(&node) && B_OK == roster->GetAllInputsFor(node, &in, 1, &count) && count == 1) { format->u.raw_audio.frame_rate
= out.format.u.raw_audio.frame_rate;
} else if (roster->GetAudioOutput(&node) == B_OK
&& roster->GetAllInputsFor(node, &in, 1, &count) == B_OK
&& count == 1) {
// use DAC input format // use DAC input format
format->u.raw_audio.channel_count = in.format.u.raw_audio.channel_count; format->u.raw_audio.channel_count
format->u.raw_audio.frame_rate = in.format.u.raw_audio.frame_rate; = in.format.u.raw_audio.channel_count;
format->u.raw_audio.frame_rate
= in.format.u.raw_audio.frame_rate;
} }
} }
} }
@@ -749,11 +836,12 @@ AudioMixer::PrepareToConnect(const media_source &what,
strcpy(out_name, "Mixer Output"); strcpy(out_name, "Mixer Output");
/* remove wildcards */ /* remove wildcards */
#if USE_MEDIA_FORMAT_WORKAROUND #if USE_MEDIA_FORMAT_WORKAROUND
multi_audio_format_specialize(&format->u.raw_audio, &fDefaultFormat.u.raw_audio); multi_audio_format_specialize(&format->u.raw_audio,
#else &fDefaultFormat.u.raw_audio);
format->SpecializeTo(&fDefaultFormat); #else
#endif format->SpecializeTo(&fDefaultFormat);
#endif
PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format); PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format);
@@ -772,11 +860,10 @@ AudioMixer::PrepareToConnect(const media_source &what,
return B_OK; return B_OK;
} }
void void
AudioMixer::Connect(status_t error, const media_source &source, AudioMixer::Connect(status_t error, const media_source &source,
const media_destination &dest, const media_destination &dest, const media_format &format, char *io_name)
const media_format &format,
char *io_name)
{ {
TRACE("AudioMixer::Connect\n"); TRACE("AudioMixer::Connect\n");
@@ -791,7 +878,8 @@ AudioMixer::Connect(status_t error, const media_source &source,
if (error != B_OK) { if (error != B_OK) {
// if an error occured, remove output from core // if an error occured, remove output from core
ERROR("AudioMixer::Connect failed with error 0x%08lX, removing connection\n", error); ERROR("AudioMixer::Connect failed with error 0x%08lX, removing "
"connection\n", error);
fCore->Lock(); fCore->Lock();
fCore->RemoveOutput(); fCore->RemoveOutput();
fCore->Unlock(); fCore->Unlock();
@@ -818,7 +906,8 @@ AudioMixer::Connect(status_t error, const media_source &source,
TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration()); TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
// Our internal latency is at least the length of a full output buffer // Our internal latency is at least the length of a full output buffer
fInternalLatency = BufferDuration() + max(4500LL, bigtime_t(0.5 * BufferDuration())); fInternalLatency = BufferDuration()
+ max(4500LL, bigtime_t(0.5 * BufferDuration()));
TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency); TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
SetEventLatency(fDownstreamLatency + fInternalLatency); SetEventLatency(fDownstreamLatency + fInternalLatency);
@@ -826,10 +915,10 @@ AudioMixer::Connect(status_t error, const media_source &source,
// we need to inform all connected *inputs* about *our* change in latency // we need to inform all connected *inputs* about *our* change in latency
PublishEventLatencyChange(); PublishEventLatencyChange();
// Set up the buffer group for our connection, as long as nobody handed us a // Set up the buffer group for our connection, as long as nobody handed
// buffer group (via SetBufferGroup()) prior to this. That can happen, for example, // us a buffer group (via SetBufferGroup()) prior to this. That can
// if the consumer calls SetOutputBuffersFor() on us from within its Connected() // happen, for example, if the consumer calls SetOutputBuffersFor() on
// method. // us from within its Connected() method.
if (!fBufferGroup) if (!fBufferGroup)
fBufferGroup = CreateBufferGroup(); fBufferGroup = CreateBufferGroup();
@@ -864,7 +953,10 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
// Make sure that our connection is the one being disconnected // Make sure that our connection is the one being disconnected
MixerOutput * output = fCore->Output(); MixerOutput * output = fCore->Output();
if (!output || output->MediaOutput().node != Node() || output->MediaOutput().source != what || output->MediaOutput().destination != where) { if (!output
|| output->MediaOutput().node != Node()
|| output->MediaOutput().source != what
|| output->MediaOutput().destination != where) {
ERROR("AudioMixer::Disconnect can't disconnect (wrong connection)\n"); ERROR("AudioMixer::Disconnect can't disconnect (wrong connection)\n");
fCore->Unlock(); fCore->Unlock();
return; return;
@@ -891,12 +983,14 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
void void
AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much, bigtime_t performance_time) AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much,
bigtime_t performance_time)
{ {
// We've produced some late buffers... Increase Latency // We've produced some late buffers... Increase Latency
// is the only runmode in which we can do anything about this // is the only runmode in which we can do anything about this
ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", how_much, performance_time); ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", how_much,
performance_time);
// Note: The following code is outcommented on purpose // Note: The following code is outcommented on purpose
// and is about to be modified at a later point // and is about to be modified at a later point
/* /*
@@ -918,7 +1012,8 @@ AudioMixer::LateNoticeReceived(const media_source &what, bigtime_t how_much, big
void void
AudioMixer::EnableOutput(const media_source &what, bool enabled, int32 *_deprecated_) AudioMixer::EnableOutput(const media_source &what, bool enabled,
int32 *_deprecated_)
{ {
// we only have one output // we only have one output
if (what.id != 0 || what.port != ControlPort()) if (what.id != 0 || what.port != ControlPort())
@@ -930,9 +1025,8 @@ AudioMixer::EnableOutput(const media_source &what, bool enabled, int32 *_depreca
} }
// // #pragma mark - BMediaEventLooper methods
// BMediaEventLooper methods
//
void void
AudioMixer::NodeRegistered() AudioMixer::NodeRegistered()
@@ -942,21 +1036,23 @@ AudioMixer::NodeRegistered()
UpdateParameterWeb(); UpdateParameterWeb();
} }
void void
AudioMixer::SetTimeSource(BTimeSource * time_source) AudioMixer::SetTimeSource(BTimeSource * time_source)
{ {
TRACE("AudioMixer::SetTimeSource: timesource is now %ld\n", time_source->ID()); TRACE("AudioMixer::SetTimeSource: timesource is now %ld\n",
time_source->ID());
fCore->Lock(); fCore->Lock();
fCore->SetTimingInfo(time_source, fDownstreamLatency); fCore->SetTimingInfo(time_source, fDownstreamLatency);
fCore->Unlock(); fCore->Unlock();
} }
void
AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool realTimeEvent)
{
switch (event->type)
{
void
AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness,
bool realTimeEvent)
{
switch (event->type) {
case BTimedEventQueue::B_HANDLE_BUFFER: case BTimedEventQueue::B_HANDLE_BUFFER:
{ {
HandleInputBuffer((BBuffer *)event->pointer, lateness); HandleInputBuffer((BBuffer *)event->pointer, lateness);
@@ -978,8 +1074,10 @@ AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool
case BTimedEventQueue::B_STOP: case BTimedEventQueue::B_STOP:
{ {
TRACE("AudioMixer::HandleEvent: B_STOP\n"); TRACE("AudioMixer::HandleEvent: B_STOP\n");
// stopped - don't process any more buffers, flush all buffers from eventqueue // stopped - don't process any more buffers, flush all buffers
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); // from event queue
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
BTimedEventQueue::B_HANDLE_BUFFER);
fCore->Lock(); fCore->Lock();
fCore->Stop(); fCore->Stop();
fCore->Unlock(); fCore->Unlock();
@@ -994,13 +1092,12 @@ AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool
default: default:
break; break;
} }
} }
//
// AudioMixer methods // #pragma mark - AudioMixer methods
//
void void
AudioMixer::PublishEventLatencyChange() AudioMixer::PublishEventLatencyChange()
@@ -1014,24 +1111,29 @@ AudioMixer::PublishEventLatencyChange()
MixerInput *input; MixerInput *input;
for (int i = 0; (input = fCore->Input(i)) != 0; i++) { for (int i = 0; (input = fCore->Input(i)) != 0; i++) {
TRACE("AudioMixer::PublishEventLatencyChange: SendLatencyChange, connection %ld/%ld to %ld/%ld event latency is now %Ld\n", TRACE("AudioMixer::PublishEventLatencyChange: SendLatencyChange, "
"connection %ld/%ld to %ld/%ld event latency is now %Ld\n",
input->MediaInput().source.port, input->MediaInput().source.id, input->MediaInput().source.port, input->MediaInput().source.id,
input->MediaInput().destination.port, input->MediaInput().destination.id, input->MediaInput().destination.port,
EventLatency()); input->MediaInput().destination.id, EventLatency());
SendLatencyChange(input->MediaInput().source, input->MediaInput().destination, EventLatency()); SendLatencyChange(input->MediaInput().source,
input->MediaInput().destination, EventLatency());
} }
fCore->Unlock(); fCore->Unlock();
} }
BBufferGroup *
BBufferGroup*
AudioMixer::CreateBufferGroup() AudioMixer::CreateBufferGroup()
{ {
// allocate enough buffers to span our downstream latency // allocate enough buffers to span our downstream latency
// (plus one for rounding up), plus one extra // (plus one for rounding up), plus one extra
int32 count = int32(fDownstreamLatency / BufferDuration()) + 2; int32 count = int32(fDownstreamLatency / BufferDuration()) + 2;
TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency, BufferDuration(), count); TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, "
"BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency,
BufferDuration(), count);
if (count < 3) if (count < 3)
count = 3; count = 3;
@@ -1040,21 +1142,25 @@ AudioMixer::CreateBufferGroup()
uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size; uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size;
fCore->Unlock(); fCore->Unlock();
TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n", count, size); TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n",
count, size);
return new BBufferGroup(size, count); return new BBufferGroup(size, count);
} }
float float
AudioMixer::dB_to_Gain(float db) AudioMixer::dB_to_Gain(float db)
{ {
TRACE("dB_to_Gain: dB in: %01.2f ", db); TRACE("dB_to_Gain: dB in: %01.2f ", db);
if (fCore->Settings()->NonLinearGainSlider()) { if (fCore->Settings()->NonLinearGainSlider()) {
if (db > 0) { if (db > 0) {
db = db * (pow(abs(DB_MAX), (1.0 / DB_EXPONENT_POSITIVE)) / abs(DB_MAX)); db = db * (pow(abs(DB_MAX), (1.0 / DB_EXPONENT_POSITIVE))
/ abs(DB_MAX));
db = pow(db, DB_EXPONENT_POSITIVE); db = pow(db, DB_EXPONENT_POSITIVE);
} else { } else {
db = -db; db = -db;
db = db * (pow(abs(DB_MIN), (1.0 / DB_EXPONENT_NEGATIVE)) / abs(DB_MIN)); db = db * (pow(abs(DB_MIN), (1.0 / DB_EXPONENT_NEGATIVE))
/ abs(DB_MIN));
db = pow(db, DB_EXPONENT_NEGATIVE); db = pow(db, DB_EXPONENT_NEGATIVE);
db = -db; db = -db;
} }
@@ -1063,6 +1169,7 @@ AudioMixer::dB_to_Gain(float db)
return pow(10.0, db / 20.0); return pow(10.0, db / 20.0);
} }
float float
AudioMixer::Gain_to_dB(float gain) AudioMixer::Gain_to_dB(float gain)
{ {
@@ -1071,59 +1178,21 @@ AudioMixer::Gain_to_dB(float gain)
if (fCore->Settings()->NonLinearGainSlider()) { if (fCore->Settings()->NonLinearGainSlider()) {
if (db > 0) { if (db > 0) {
db = pow(db, (1.0 / DB_EXPONENT_POSITIVE)); db = pow(db, (1.0 / DB_EXPONENT_POSITIVE));
db = db * (abs(DB_MAX) / pow(abs(DB_MAX), (1.0 / DB_EXPONENT_POSITIVE))); db = db * (abs(DB_MAX) / pow(abs(DB_MAX),
(1.0 / DB_EXPONENT_POSITIVE)));
} else { } else {
db = -db; db = -db;
db = pow(db, (1.0 / DB_EXPONENT_NEGATIVE)); db = pow(db, (1.0 / DB_EXPONENT_NEGATIVE));
db = db * (abs(DB_MIN) / pow(abs(DB_MIN), (1.0 / DB_EXPONENT_NEGATIVE))); db = db * (abs(DB_MIN) / pow(abs(DB_MIN),
(1.0 / DB_EXPONENT_NEGATIVE)));
db = -db; db = -db;
} }
} }
return db; return db;
} }
//
// BControllable methods
//
#define DB_TO_GAIN(db) dB_to_Gain((db)) // #pragma markß - BControllable methods
#define GAIN_TO_DB(gain) Gain_to_dB((gain))
#define PERCENT_TO_GAIN(pct) ((pct) / 100.0)
#define GAIN_TO_PERCENT(gain) ((gain) * 100.0)
// the id is encoded with 16 bits
// then chan and src (or dst) are encoded with 6 bits
// the unique number with 4 bits
// the PARAM_ETC etc is encoded with 26 bits
#define PARAM_SRC_ENABLE(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x1)
#define PARAM_SRC_GAIN(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x2)
#define PARAM_DST_ENABLE(id, chan, dst) (((id) << 16) | ((chan) << 10) | ((dst) << 4) | 0x3)
#define PARAM_ETC(etc) (((etc) << 16) | 0x4)
#define PARAM_SRC_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x5)
#define PARAM_DST_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x6)
#define PARAM_MUTE(id) (((id) << 16) | 0x7)
#define PARAM_GAIN(id) (((id) << 16) | 0x8)
#define PARAM_BALANCE(id) (((id) << 16) | 0x9)
#define PARAM_STR1(id) (((id) << 16) | ((1) << 10) | 0xa)
#define PARAM_STR2(id) (((id) << 16) | ((2) << 10) | 0xa)
#define PARAM_STR3(id) (((id) << 16) | ((3) << 10) | 0xa)
#define PARAM_STR4(id) (((id) << 16) | ((4) << 10) | 0xa)
#define PARAM_STR5(id) (((id) << 16) | ((5) << 10) | 0xa)
#define PARAM_STR6(id) (((id) << 16) | ((6) << 10) | 0xa)
#define PARAM_STR7(id) (((id) << 16) | ((7) << 10) | 0xa)
#define PARAM(id) ((id) >> 16)
#define ETC(id) ((id) >> 16)
#define PARAM_CHAN(id) (((id) >> 10) & 0x3f)
#define PARAM_SRC(id) (((id) >> 4) & 0x3f)
#define PARAM_DST(id) (((id) >> 4) & 0x3f)
#define PARAM_IS_SRC_ENABLE(id) (((id) & 0xf) == 0x1)
#define PARAM_IS_SRC_GAIN(id) (((id) & 0xf) == 0x2)
#define PARAM_IS_DST_ENABLE(id) (((id) & 0xf) == 0x3)
#define PARAM_IS_ETC(id) (((id) & 0xf) == 0x4)
#define PARAM_IS_MUTE(id) (((id) & 0xf) == 0x7)
#define PARAM_IS_GAIN(id) (((id) & 0xf) == 0x8)
#define PARAM_IS_BALANCE(id) (((id) & 0xf) == 0x9)
status_t status_t
@@ -1570,7 +1639,7 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when, const void *value,
} else { } else {
input->RemoveInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id)); input->RemoveInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id));
} }
// XXX this is really annoying // TODO: this is really annoying
// The slider count of the gain control needs to be changed, // The slider count of the gain control needs to be changed,
// but calling SetChannelCount(input->GetMixerChannelCount()) // but calling SetChannelCount(input->GetMixerChannelCount())
// on it has no effect on remote BParameterWebs in other apps. // on it has no effect on remote BParameterWebs in other apps.
@@ -1582,13 +1651,16 @@ AudioMixer::SetParameterValue(int32 id, bigtime_t when, const void *value,
} }
fCore->Settings()->SaveConnectionSettings(input); fCore->Settings()->SaveConnectionSettings(input);
} }
BroadcastNewParameterValue(when, id, const_cast<void *>(value), size); BroadcastNewParameterValue(when, id, const_cast<void *>(value), size);
err: err:
fCore->Unlock(); fCore->Unlock();
if (update) if (update)
UpdateParameterWeb(); UpdateParameterWeb();
} }
void void
AudioMixer::UpdateParameterWeb() AudioMixer::UpdateParameterWeb()
{ {
@@ -1673,13 +1745,18 @@ AudioMixer::UpdateParameterWeb()
} else { } else {
for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) { for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) {
subgroup = group->MakeGroup(""); subgroup = group->MakeGroup("");
subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), B_MEDIA_RAW_AUDIO, subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan),
StringForChannelType(buf, out->GetOutputChannelType(chan)), B_GENERIC); B_MEDIA_RAW_AUDIO, StringForChannelType(buf,
out->GetOutputChannelType(chan)), B_GENERIC);
for (int src = 0; src < MAX_CHANNEL_TYPES; src++) { for (int src = 0; src < MAX_CHANNEL_TYPES; src++) {
subsubgroup = subgroup->MakeGroup(""); subsubgroup = subgroup->MakeGroup("");
subsubgroup->MakeDiscreteParameter(PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", B_ENABLE); subsubgroup->MakeDiscreteParameter(
subsubgroup->MakeContinuousParameter(PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO, PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "",
StringForChannelType(buf, src), B_GAIN, "%", 0.0, 100.0, 0.1); B_ENABLE);
subsubgroup->MakeContinuousParameter(
PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO,
StringForChannelType(buf, src), B_GAIN, "%", 0.0,
100.0, 0.1);
} }
} }
} }
@@ -1737,9 +1814,11 @@ AudioMixer::UpdateParameterWeb()
SetParameterWeb(web); SetParameterWeb(web);
} }
#if USE_MEDIA_FORMAT_WORKAROUND #if USE_MEDIA_FORMAT_WORKAROUND
static void static void
raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other) raw_audio_format_specialize(media_raw_audio_format *format,
const media_raw_audio_format *other)
{ {
if (format->frame_rate == 0) if (format->frame_rate == 0)
format->frame_rate = other->frame_rate; format->frame_rate = other->frame_rate;
@@ -1755,8 +1834,10 @@ raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audi
format->frame_rate = other->frame_rate; format->frame_rate = other->frame_rate;
} }
static void static void
multi_audio_info_specialize(media_multi_audio_info *format, const media_multi_audio_info *other) multi_audio_info_specialize(media_multi_audio_info *format,
const media_multi_audio_info *other)
{ {
if (format->channel_mask == 0) if (format->channel_mask == 0)
format->channel_mask = other->channel_mask; format->channel_mask = other->channel_mask;
@@ -1766,8 +1847,10 @@ multi_audio_info_specialize(media_multi_audio_info *format, const media_multi_au
format->matrix_mask = other->matrix_mask; format->matrix_mask = other->matrix_mask;
} }
static void static void
multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other) multi_audio_format_specialize(media_multi_audio_format *format,
const media_multi_audio_format *other)
{ {
raw_audio_format_specialize(format, other); raw_audio_format_specialize(format, other);
multi_audio_info_specialize(format, other); multi_audio_info_specialize(format, other);