added connecting/disconnecting of inputs/outputs

changed debug functions
added multiaudio format correction
added workaround for broken BeOS R5 media_format:SpecializeTo()
fixed AudioMixer::Connect function to use correct destination
added utility functions
fixed locking bugs


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3575 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-06-19 14:09:00 +00:00
parent 77584bdf01
commit e6c7c99fc9
11 changed files with 275 additions and 34 deletions
@@ -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
@@ -8,6 +8,7 @@ Addon mixer.media_addon : media :
MixerCore.cpp
MixerInput.cpp
MixerOutput.cpp
MixerUtils.cpp
Resampler.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
@@ -58,6 +58,8 @@ private:
BList *fInputs;
MixerOutput *fOutput;
int32 fNextInputID;
bool fRunning;
};
@@ -1,11 +1,16 @@
#include <MediaNode.h>
#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;
}
@@ -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();
@@ -1,11 +1,16 @@
#include <MediaNode.h>
#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()
@@ -6,7 +6,7 @@ class MixerCore;
class MixerOutput
{
public:
MixerOutput(MixerCore *core);
MixerOutput(MixerCore *core, const media_output &output);
~MixerOutput();
media_output & MediaOutput();
@@ -0,0 +1,96 @@
#include <MediaDefs.h>
#include <stdio.h>
#include <string.h>
#include "MixerUtils.h"
void string_for_channel_mask(char *str, uint32 mask)
{
str[0] = 0;
if (mask == 0) {
strcpy(str, "<none>");
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;
}
}
@@ -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)
@@ -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()