diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp index babe68bde1..7caca28819 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -18,6 +18,12 @@ #include "MixerOutput.h" #include "debug.h" +#define USE_MEDIA_FORMAT_WORKAROUND 1 + +#if USE_MEDIA_FORMAT_WORKAROUND +static void multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other); +#endif + AudioMixer::AudioMixer(BMediaAddOn *addOn) : BMediaNode("Audio Mixer"), BBufferConsumer(B_MEDIA_RAW_AUDIO), @@ -208,8 +214,10 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness) } } */ - + + fCore->Lock(); fCore->BufferReceived(buffer, lateness); + fCore->Unlock(); /* if ((B_OFFLINE == RunMode()) && (B_DATA_AVAILABLE == channel->fProducerDataStatus)) @@ -242,8 +250,6 @@ AudioMixer::GetLatencyFor(const media_destination &for_whom, bigtime_t *out_latency, media_node_id *out_timesource) { - printf("AudioMixer::GetLatencyFor\n"); - // we have multiple inputs with different IDs, but // the port number must match our ControlPort() if (for_whom.port != ControlPort()) @@ -254,7 +260,7 @@ AudioMixer::GetLatencyFor(const media_destination &for_whom, *out_latency = EventLatency(); *out_timesource = TimeSource()->ID(); - printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n", *out_latency, *out_timesource); + //printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n", *out_latency, *out_timesource); return B_OK; @@ -360,6 +366,8 @@ AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat) // proposed media_format is suitable for the specified output. If any fields // in the format are wildcards, and we have a specific requirement, adjust // those fields to match our requirements before returning. + + printf("AudioMixer::FormatProposal\n"); // we only have one output (id=0, port=ControlPort()) if (output.id != 0 || output.port != ControlPort()) @@ -372,6 +380,8 @@ AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat) // we require a raw audio format if (ioFormat->type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT; + + return B_OK; } status_t @@ -385,24 +395,28 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin fCore->Lock(); MixerOutput *output = fCore->Output(); if (!output) { - FATAL("AudioMixer::FormatChangeRequested: no output\n"); + ERROR("AudioMixer::FormatChangeRequested: no output\n"); goto err; } if (source != output->MediaOutput().source) { - FATAL("AudioMixer::FormatChangeRequested: wrong output source\n"); + ERROR("AudioMixer::FormatChangeRequested: wrong output source\n"); goto err; } if (destination != output->MediaOutput().destination) { - FATAL("AudioMixer::FormatChangeRequested: wrong output destination\n"); + ERROR("AudioMixer::FormatChangeRequested: wrong output destination\n"); goto err; } if (io_format->type != B_MEDIA_RAW_AUDIO && io_format->type != B_MEDIA_UNKNOWN_TYPE) { - FATAL("AudioMixer::FormatChangeRequested: wrong format type\n"); + ERROR("AudioMixer::FormatChangeRequested: wrong format type\n"); goto err; } /* remove wildcards */ - io_format->SpecializeTo(&fDefaultFormat); + #if USE_MEDIA_FORMAT_WORKAROUND + multi_audio_format_specialize(&io_format->u.raw_audio, &fDefaultFormat.u.raw_audio); + #else + io_format->SpecializeTo(&fDefaultFormat); + #endif // apply format change fCore->Lock(); @@ -427,11 +441,12 @@ AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output) if (output) { *out_output = output->MediaOutput(); } else { + out_output->node = Node(); out_output->source.port = ControlPort(); out_output->source.id = 0; out_output->destination = media_destination::null; + memset(&out_output->format, 0, sizeof(out_output->format)); out_output->format.type = B_MEDIA_RAW_AUDIO; - out_output->format.u.raw_audio = media_multi_audio_format::wildcard; strcpy(out_output->name, "Mixer Output"); } fCore->Unlock(); @@ -491,19 +506,24 @@ AudioMixer::PrepareToConnect(const media_source &what, const media_destination & // *must* fully specialize the format before returning! // we also create the new output connection and return it in out_source. + PRINT_FORMAT("AudioMixer::PrepareToConnect: suggested format", *format); + // is the source valid? if (what.port != ControlPort() || what.id != 0) return B_MEDIA_BAD_SOURCE; // 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); return B_MEDIA_BAD_FORMAT; + } fCore->Lock(); // are we already connected? if (fCore->Output() != 0) { fCore->Unlock(); + ERROR("AudioMixer::PrepareToConnect: already connected\n"); return B_MEDIA_ALREADY_CONNECTED; } @@ -512,7 +532,13 @@ AudioMixer::PrepareToConnect(const media_source &what, const media_destination & strcpy(out_name, "Mixer Output"); /* remove wildcards */ - format->SpecializeTo(&fDefaultFormat); + #if USE_MEDIA_FORMAT_WORKAROUND + multi_audio_format_specialize(&format->u.raw_audio, &fDefaultFormat.u.raw_audio); + #else + format->SpecializeTo(&fDefaultFormat); + #endif + + PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format); /* add output to core */ media_output output; @@ -539,7 +565,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest if (error != B_OK) { // if an error occured, remove output from core - printf("AudioMixer::Connect failed, removing connction\n"); + printf("AudioMixer::Connect failed with error 0x%08lX, removing connction\n", error); fCore->Lock(); fCore->RemoveOutput(); fCore->Unlock(); @@ -577,10 +603,19 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest if (!fBufferGroup) fBufferGroup = CreateBufferGroup(); - ASSERT(fCore->Output() != 0); - ASSERT(fCore->Output()->MediaOutput().format == format); - fCore->Lock(); + + ASSERT(fCore->Output() != 0); + + // our source should still be valid, too + ASSERT(fCore->Output()->MediaOutput().source.id == 0); + ASSERT(fCore->Output()->MediaOutput().source.port == ControlPort()); + + // BBufferConsumer::Connected() may return a different input for the + // newly created connection. The destination can have changed since + // AudioMixer::PrepareToConnect() and we need to update it. + fCore->Output()->MediaOutput().destination = dest; + fCore->EnableOutput(true); fCore->SetTimeSource(TimeSource()->ID()); fCore->SetOutputBufferGroup(fBufferGroup); @@ -599,7 +634,7 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where) // Make sure that our connection is the one being disconnected MixerOutput * output = fCore->Output(); if (!output || output->MediaOutput().node != Node() || output->MediaOutput().source != what || output->MediaOutput().destination != where) { - FATAL("AudioMixer::Disconnect can't disconnect (wrong connection)\n"); + ERROR("AudioMixer::Disconnect can't disconnect (wrong connection)\n"); fCore->Unlock(); return; } @@ -741,3 +776,40 @@ AudioMixer::CreateBufferGroup() printf("AudioMixer: allocating %ld buffers of %ld bytes each\n", count, size); return new BBufferGroup(size, count); } + +#if USE_MEDIA_FORMAT_WORKAROUND +static void +raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other) +{ + if (format->frame_rate == 0) + format->frame_rate = other->frame_rate; + if (format->channel_count == 0) + format->channel_count = other->channel_count; + if (format->format == 0) + format->format = other->format; + if (format->byte_order == 0) + format->byte_order = other->byte_order; + if (format->buffer_size == 0) + format->buffer_size = other->buffer_size; + if (format->frame_rate == 0) + format->frame_rate = other->frame_rate; +} + +static void +multi_audio_info_specialize(media_multi_audio_info *format, const media_multi_audio_info *other) +{ + if (format->channel_mask == 0) + format->channel_mask = other->channel_mask; + if (format->valid_bits == 0) + format->valid_bits = other->valid_bits; + if (format->matrix_mask == 0) + format->matrix_mask = other->matrix_mask; +} + +static void +multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other) +{ + raw_audio_format_specialize(format, other); + multi_audio_info_specialize(format, other); +} +#endif diff --git a/src/add-ons/media/media-add-ons/mixer/Jamfile b/src/add-ons/media/media-add-ons/mixer/Jamfile index 72d4e50194..ff04afd557 100644 --- a/src/add-ons/media/media-add-ons/mixer/Jamfile +++ b/src/add-ons/media/media-add-ons/mixer/Jamfile @@ -8,6 +8,7 @@ Addon mixer.media_addon : media : MixerCore.cpp MixerInput.cpp MixerOutput.cpp + MixerUtils.cpp Resampler.cpp ; diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp index 16f15fba70..24f72006ec 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -2,116 +2,161 @@ #include "MixerCore.h" #include "MixerInput.h" #include "MixerOutput.h" +#include "Debug.h" #define MAX_OUTPUT_BUFFER_LENGTH 50000LL /* 50 ms */ +#define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred") MixerCore::MixerCore() : fLocker(new BLocker), fOutputBufferLength(MAX_OUTPUT_BUFFER_LENGTH), fInputBufferLength(3 * MAX_OUTPUT_BUFFER_LENGTH), - fOutput(0) - + fInputs(new BList), + fOutput(0), + fNextInputID(1), + fRunning(false) { } MixerCore::~MixerCore() { delete fLocker; + delete fInputs; } bool MixerCore::AddInput(const media_input &input) { + ASSERT_LOCKED(); + fInputs->AddItem(new MixerInput(this, input)); return true; } bool MixerCore::AddOutput(const media_output &output) { - return true; + ASSERT_LOCKED(); + if (fOutput) + return false; + fOutput = new MixerOutput(this, output); } bool MixerCore::RemoveInput(int32 inputID) { - return true; + ASSERT_LOCKED(); + MixerInput *input; + for (int i = 0; (input = (MixerInput *)fInputs->ItemAt(i)) != 0; i++) { + if (input->ID() == inputID) { + fInputs->RemoveItem(i); + delete input; + return true; + } + } + return false; } bool MixerCore::RemoveOutput() { + ASSERT_LOCKED(); + if (!fOutput) + return false; + delete fOutput; + fOutput = 0; return true; } int32 MixerCore::CreateInputID() { - return 1; + ASSERT_LOCKED(); + return fNextInputID++; } MixerInput * MixerCore::Input(int i) { + ASSERT_LOCKED(); return (MixerInput *)fInputs->ItemAt(i); } MixerOutput * MixerCore::Output() { + ASSERT_LOCKED(); return fOutput; } void MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness) { + ASSERT_LOCKED(); } void MixerCore::InputFormatChanged(int32 inputID, const media_format *format) { + ASSERT_LOCKED(); } void MixerCore::OutputFormatChanged(const media_format *format) { + ASSERT_LOCKED(); } void MixerCore::SetOutputBufferGroup(BBufferGroup *group) { + ASSERT_LOCKED(); } void MixerCore::SetTimeSource(media_node_id id) { + ASSERT_LOCKED(); } void MixerCore::EnableOutput(bool enabled) { + ASSERT_LOCKED(); } void MixerCore::Start(bigtime_t time) { + ASSERT_LOCKED(); + if (fRunning) + return; + + fRunning = true; } void MixerCore::Stop() { + ASSERT_LOCKED(); + if (!fRunning) + return; + + fRunning = false; } uint32 MixerCore::OutputBufferSize() { + ASSERT_LOCKED(); return 1; } bool MixerCore::IsStarted() { - return false; + ASSERT_LOCKED(); + return fRunning; } void diff --git a/src/add-ons/media/media-add-ons/mixer/MixerCore.h b/src/add-ons/media/media-add-ons/mixer/MixerCore.h index b7b486c832..2ece2b6a73 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -58,6 +58,8 @@ private: BList *fInputs; MixerOutput *fOutput; + int32 fNextInputID; + bool fRunning; }; diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp index e1fcae8f0a..3d933e613c 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -1,11 +1,16 @@ #include #include "MixerInput.h" #include "MixerCore.h" +#include "MixerUtils.h" +#include "debug.h" - -MixerInput::MixerInput(MixerCore *core) - : fCore(core) +MixerInput::MixerInput(MixerCore *core, const media_input &input) + : fCore(core), + fInput(input) { + fix_multiaudio_format(&fInput.format.u.raw_audio); + PRINT_INPUT("MixerInput::MixerInput", fInput); + PRINT_CHANNEL_MASK(fInput.format); } MixerInput::~MixerInput() @@ -22,3 +27,11 @@ MixerInput::MediaInput() { return fInput; } + +int32 +MixerInput::ID() +{ + return fInput.destination.id; +} + + diff --git a/src/add-ons/media/media-add-ons/mixer/MixerInput.h b/src/add-ons/media/media-add-ons/mixer/MixerInput.h index ae0daee336..79584db8d6 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.h @@ -6,9 +6,11 @@ class MixerCore; class MixerInput { public: - MixerInput(MixerCore *core); + MixerInput(MixerCore *core, const media_input &input); ~MixerInput(); + int32 ID(); + void BufferReceived(BBuffer *buffer); media_input & MediaInput(); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp b/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp index 86120876ba..f79f0e2005 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp @@ -1,11 +1,16 @@ #include #include "MixerOutput.h" #include "MixerCore.h" +#include "MixerUtils.h" +#include "debug.h" - -MixerOutput::MixerOutput(MixerCore *core) - : fCore(core) +MixerOutput::MixerOutput(MixerCore *core, const media_output &output) + : fCore(core), + fOutput(output) { + fix_multiaudio_format(&fOutput.format.u.raw_audio); + PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput); + PRINT_CHANNEL_MASK(fOutput.format); } MixerOutput::~MixerOutput() diff --git a/src/add-ons/media/media-add-ons/mixer/MixerOutput.h b/src/add-ons/media/media-add-ons/mixer/MixerOutput.h index ef4445b911..40be973521 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerOutput.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerOutput.h @@ -6,7 +6,7 @@ class MixerCore; class MixerOutput { public: - MixerOutput(MixerCore *core); + MixerOutput(MixerCore *core, const media_output &output); ~MixerOutput(); media_output & MediaOutput(); diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp new file mode 100644 index 0000000000..a9eef8a1c5 --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.cpp @@ -0,0 +1,96 @@ +#include +#include +#include + +#include "MixerUtils.h" + +void string_for_channel_mask(char *str, uint32 mask) +{ + str[0] = 0; + if (mask == 0) { + strcpy(str, ""); + return; + } + #define DECODE(type, text) if (mask & (type)) \ + do { strcat(str, text); mask &= ~(type); if (mask != 0) strcat(str, ", "); } while (0) + DECODE(B_CHANNEL_LEFT, "Left"); + DECODE(B_CHANNEL_RIGHT, "Right"); + DECODE(B_CHANNEL_CENTER, "Center"); + DECODE(B_CHANNEL_SUB, "Sub"); + DECODE(B_CHANNEL_REARLEFT, "Rear-Left"); + DECODE(B_CHANNEL_REARRIGHT, "Rear-Right"); + DECODE(B_CHANNEL_FRONT_LEFT_CENTER, "Front-Left-Center"); + DECODE(B_CHANNEL_FRONT_RIGHT_CENTER, "Front-Right-Center"); + DECODE(B_CHANNEL_BACK_CENTER, "Back-Center"); + DECODE(B_CHANNEL_SIDE_LEFT, "Side-Left"); + DECODE(B_CHANNEL_SIDE_RIGHT, "Side-Right"); + DECODE(B_CHANNEL_TOP_CENTER, "Top-Center"); + DECODE(B_CHANNEL_TOP_FRONT_LEFT, "Top-Front-Left"); + DECODE(B_CHANNEL_TOP_FRONT_CENTER, "Top-Front-Center"); + DECODE(B_CHANNEL_TOP_FRONT_RIGHT, "Top-Front-Right"); + DECODE(B_CHANNEL_TOP_BACK_LEFT, "Top-Back-Left"); + DECODE(B_CHANNEL_TOP_BACK_CENTER, "Top-Back-Center"); + DECODE(B_CHANNEL_TOP_BACK_RIGHT, "Top-Back-Right"); + #undef DECODE + if (mask) + sprintf(str + strlen(str), "0x%08X", mask); +} + +int count_nonzero_bits(uint32 value) +{ + int count = 0; + for (int i = 0; i < 32; i++) + if (value & (1 << i)) + count++; + return count; +} + +void fix_multiaudio_format(media_multi_audio_format *format) +{ + if (format->format == media_raw_audio_format::B_AUDIO_INT) { + if (format->valid_bits != 0 && (format->valid_bits < 16 || format->valid_bits >= 32)) + format->valid_bits = 0; + } + switch (format->channel_count) { + case 0: + format->channel_mask = 0; + format->matrix_mask = 0; + break; + case 1: + if (count_nonzero_bits(format->channel_mask) != 1) { + format->channel_mask = B_CHANNEL_LEFT; + format->matrix_mask = 0; + } + break; + case 2: + if (count_nonzero_bits(format->channel_mask) != 2) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; + format->matrix_mask = 0; + } + break; + case 4: + if (count_nonzero_bits(format->channel_mask) != 4) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT; + format->matrix_mask = 0; + } + break; + case 5: + if (count_nonzero_bits(format->channel_mask) != 5) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER; + format->matrix_mask = 0; + } + break; + case 6: + if (count_nonzero_bits(format->channel_mask) != 6) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER | B_CHANNEL_SUB; + format->matrix_mask = 0; + } + break; + case 7: + if (count_nonzero_bits(format->channel_mask) != 7) { + format->channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER | B_CHANNEL_SUB | B_CHANNEL_BACK_CENTER; + format->matrix_mask = 0; + } + break; + } +} diff --git a/src/add-ons/media/media-add-ons/mixer/MixerUtils.h b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h new file mode 100644 index 0000000000..8fee6c6a37 --- /dev/null +++ b/src/add-ons/media/media-add-ons/mixer/MixerUtils.h @@ -0,0 +1,5 @@ + +void string_for_channel_mask(char *str, uint32 mask); +void fix_multiaudio_format(media_multi_audio_format *format); + +#define PRINT_CHANNEL_MASK(fmt) do { char s[200]; string_for_channel_mask(s, (fmt).u.raw_audio.channel_mask); printf(" channel_mask 0x%08X %s\n", (fmt).u.raw_audio.channel_mask, s); } while (0) diff --git a/src/add-ons/media/media-add-ons/mixer/Resampler.cpp b/src/add-ons/media/media-add-ons/mixer/Resampler.cpp index 3e7043f9e1..74595d82d9 100644 --- a/src/add-ons/media/media-add-ons/mixer/Resampler.cpp +++ b/src/add-ons/media/media-add-ons/mixer/Resampler.cpp @@ -34,7 +34,7 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format) fFunc = &Resampler::uint8_to_float; return; default: - FATAL("Resampler::Resampler: unknown source format 0x%x\n", src_format); + ERROR("Resampler::Resampler: unknown source format 0x%x\n", src_format); return; } } @@ -55,12 +55,12 @@ Resampler::Resampler(uint32 src_format, uint32 dst_format) fFunc = &Resampler::float_to_uint8; return; default: - FATAL("Resampler::Resampler: unknown destination format 0x%x\n", dst_format); + ERROR("Resampler::Resampler: unknown destination format 0x%x\n", dst_format); return; } } - FATAL("Resampler::Resampler: source or destination format must be B_AUDIO_FLOAT\n"); + ERROR("Resampler::Resampler: source or destination format must be B_AUDIO_FLOAT\n"); } Resampler::~Resampler()