Implemented proper handling of latency changes that occur when connecting

a chain of mixer nodes. Also added a small hack to always pick the optimal
frame rate and channel count when connecting multiple audio mixer nodes.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3848 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2003-07-04 21:36:38 +00:00
parent 92db32b4b1
commit c3b1c2a692
2 changed files with 102 additions and 5 deletions

View File

@ -7,6 +7,7 @@
#include <Buffer.h>
#include <TimeSource.h>
#include <ParameterWeb.h>
#include <MediaRoster.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -25,6 +26,10 @@
static void multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other);
#endif
#define FORMAT_USER_DATA_TYPE 0x7294a8f3
#define FORMAT_USER_DATA_MAGIC_1 0xc84173bd
#define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d
AudioMixer::AudioMixer(BMediaAddOn *addOn)
: BMediaNode("Audio Mixer"),
BBufferConsumer(B_MEDIA_RAW_AUDIO),
@ -129,6 +134,21 @@ AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat)
if (ioFormat->type != B_MEDIA_RAW_AUDIO)
return B_MEDIA_BAD_FORMAT;
// We do not have special requirements, but just in case
// another mixer is connecting to us and my need a hint
// to create a connection at optimal frame rate and
// channel count, we place this information in the user_data
fCore->Lock();
MixerOutput *output = fCore->Output();
uint32 channel_count = output ? output->MediaOutput().format.u.raw_audio.channel_count : 0;
float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 0.0;
fCore->Unlock();
ioFormat->user_data_type = FORMAT_USER_DATA_TYPE;
*(uint32 *)&ioFormat->user_data[0] = FORMAT_USER_DATA_MAGIC_1;
*(uint32 *)&ioFormat->user_data[4] = channel_count;
*(float *)&ioFormat->user_data[20] = frame_rate;
*(uint32 *)&ioFormat->user_data[44] = FORMAT_USER_DATA_MAGIC_2;
return B_OK;
}
@ -385,7 +405,7 @@ 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;
}
@ -449,8 +469,8 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
SetEventLatency(fDownstreamLatency + fInternalLatency);
//printf("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
//SendLatencyChange(source, destination, EventLatency());
TRACE("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
SendLatencyChange(source, destination, EventLatency());
// apply latency change
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
@ -536,6 +556,30 @@ AudioMixer::GetLatency(bigtime_t *out_latency)
return B_OK;
}
void
AudioMixer::LatencyChanged(const media_source & source, const media_destination & destination,
bigtime_t new_latency, uint32 flags)
{
TRACE("AudioMixer::LatencyChanged: downstream latency changed from %Ld to %Ld\n", fDownstreamLatency, new_latency);
fDownstreamLatency = new_latency;
SetEventLatency(fDownstreamLatency + fInternalLatency);
fCore->Lock();
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
MixerInput *input;
for (int i = 0; (input = fCore->Input(i)) != 0; i++) {
TRACE("AudioMixer: SendLatencyChange from %d/%d to %d/%d event latency is now %Ld\n",
input->MediaInput().source.port, input->MediaInput().source.id,
input->MediaInput().destination.port, input->MediaInput().destination.id,
EventLatency());
SendLatencyChange(input->MediaInput().source, input->MediaInput().destination, EventLatency());
}
fCore->Unlock();
}
status_t
AudioMixer::PrepareToConnect(const media_source &what, const media_destination &where,
media_format *format, media_source *out_source, char *out_name)
@ -572,6 +616,43 @@ AudioMixer::PrepareToConnect(const media_source &what, const media_destination &
return B_MEDIA_ALREADY_CONNECTED;
}
// It is possible that another mixer is connecting.
// To avoid using the default format, we use one of
// a) the format that it indicated as hint in the user_data,
// b) the output format of the system audio mixer
// c) the input format of the system DAC device
// d) if everything failes, keep the wildcard
if (format->u.raw_audio.channel_count == 0
&& format->u.raw_audio.frame_rate < 1
&& format->user_data_type == FORMAT_USER_DATA_TYPE
&& *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1
&& *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) {
// ok, a mixer is connecting
uint32 channel_count = *(uint32 *)&format->user_data[4];
float frame_rate = *(float *)&format->user_data[20];
if (channel_count > 0 && frame_rate > 0) {
// format is good, use it
format->u.raw_audio.channel_count = channel_count;
format->u.raw_audio.frame_rate = frame_rate;
} else {
// other mixer's output is probably not connected
media_node node;
BMediaRoster *roster = BMediaRoster::Roster();
media_output out;
media_input in;
int32 count;
if (B_OK == roster->GetAudioMixer(&node) && B_OK == roster->GetConnectedOutputsFor(node, &out, 1, &count) && count == 1) {
// use mixer output format
format->u.raw_audio.channel_count = out.format.u.raw_audio.channel_count;
format->u.raw_audio.frame_rate = out.format.u.raw_audio.frame_rate;
} else if (B_OK == roster->GetAudioOutput(&node) && B_OK == roster->GetAllInputsFor(node, &in, 1, &count) && count == 1) {
// use DAC input format
format->u.raw_audio.channel_count = in.format.u.raw_audio.channel_count;
format->u.raw_audio.frame_rate = in.format.u.raw_audio.frame_rate;
}
}
}
/* set source and suggest a name */
*out_source = what;
strcpy(out_name, "Mixer Output");
@ -626,6 +707,12 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
return;
}
/* Switch our prefered format to have the same
* frame_rate and channel count as the output.
*/
fDefaultFormat.u.raw_audio.frame_rate = format.u.raw_audio.frame_rate;
fDefaultFormat.u.raw_audio.channel_count = format.u.raw_audio.channel_count;
// if the connection has no name, we set it now
if (strlen(io_name) == 0)
strcpy(io_name, "Mixer Output");
@ -645,8 +732,8 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
SetEventLatency(fDownstreamLatency + fInternalLatency);
//printf("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
//SendLatencyChange(source, dest, EventLatency());
TRACE("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
SendLatencyChange(source, dest, EventLatency());
// Set up the buffer group for our connection, as long as nobody handed us a
// buffer group (via SetBufferGroup()) prior to this. That can happen, for example,
@ -692,6 +779,12 @@ AudioMixer::Disconnect(const media_source &what, const media_destination &where)
fCore->Unlock();
return;
}
/* Switch our prefered format back to default
* frame rate and channel count.
*/
fDefaultFormat.u.raw_audio.frame_rate = 96000;
fDefaultFormat.u.raw_audio.channel_count = 2;
// force a stop
fCore->Stop();

View File

@ -173,6 +173,10 @@ class AudioMixer :
const media_source & what,
bool enabled,
int32* _deprecated_);
void LatencyChanged(const media_source & source,
const media_destination & destination,
bigtime_t new_latency, uint32 flags);
// BMediaEventLooper methods