rewrote start and stop handling to allow connecting an input without
having an output, followed by starting the node. fix some bugs of handling an unconnected output added better locking to the mix thread git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3727 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -450,7 +450,7 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
||||
printf("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
|
||||
|
||||
// Our internal latency is at least the length of a full output buffer
|
||||
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
||||
fInternalLatency = bigtime_t(1.6 * BufferDuration());
|
||||
printf("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
|
||||
|
||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||
@@ -634,7 +634,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
||||
printf("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
|
||||
|
||||
// Our internal latency is at least the length of a full output buffer
|
||||
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
||||
fInternalLatency = bigtime_t(1.6 * BufferDuration());
|
||||
printf("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
|
||||
|
||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||
@@ -778,7 +778,7 @@ AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool
|
||||
printf("AudioMixer::HandleEvent: B_START\n");
|
||||
if (RunState() != B_STARTED) {
|
||||
fCore->Lock();
|
||||
fCore->Start(event->event_time);
|
||||
fCore->Start();
|
||||
fCore->Unlock();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -36,6 +36,8 @@ MixerCore::MixerCore(AudioMixer *node)
|
||||
fOutput(0),
|
||||
fNextInputID(1),
|
||||
fRunning(false),
|
||||
fStarted(false),
|
||||
fOutputEnabled(true),
|
||||
fResampler(0),
|
||||
fMixBuffer(0),
|
||||
fMixBufferFrameRate(0),
|
||||
@@ -93,6 +95,10 @@ MixerCore::AddOutput(const media_output &output)
|
||||
fOutput = new MixerOutput(this, output);
|
||||
// the output format might have been adjusted inside MixerOutput
|
||||
ApplyOutputFormat();
|
||||
|
||||
ASSERT(!fRunning);
|
||||
if (fStarted && fOutputEnabled)
|
||||
StartMixThread();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -116,8 +122,13 @@ MixerCore::RemoveOutput()
|
||||
ASSERT_LOCKED();
|
||||
if (!fOutput)
|
||||
return false;
|
||||
|
||||
if (fStarted)
|
||||
StopMixThread();
|
||||
|
||||
delete fOutput;
|
||||
fOutput = 0;
|
||||
fOutputEnabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -169,16 +180,16 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
|
||||
bool wasrunning = fRunning;
|
||||
bool was_started = fStarted;
|
||||
|
||||
if (wasrunning)
|
||||
if (was_started)
|
||||
Stop();
|
||||
|
||||
fOutput->ChangeFormat(format);
|
||||
ApplyOutputFormat();
|
||||
|
||||
if (wasrunning)
|
||||
Start(0);
|
||||
if (was_started)
|
||||
Start();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -258,16 +269,55 @@ MixerCore::EnableOutput(bool enabled)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::EnableOutput %d\n", enabled);
|
||||
fOutputEnabled = enabled;
|
||||
|
||||
if (fRunning && !fOutputEnabled)
|
||||
StopMixThread();
|
||||
|
||||
if (!fRunning && fOutput && fStarted && fOutputEnabled)
|
||||
StartMixThread();
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::Start(bigtime_t time)
|
||||
bool
|
||||
MixerCore::Start()
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::Start\n");
|
||||
if (fRunning)
|
||||
return;
|
||||
if (fStarted)
|
||||
return false;
|
||||
|
||||
fStarted = true;
|
||||
|
||||
ASSERT(!fRunning);
|
||||
|
||||
// only start the mix thread if we have an output
|
||||
if (fOutput && fOutputEnabled)
|
||||
StartMixThread();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MixerCore::Stop()
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::Stop\n");
|
||||
if (!fStarted)
|
||||
return false;
|
||||
|
||||
if (fRunning)
|
||||
StopMixThread();
|
||||
|
||||
fStarted = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::StartMixThread()
|
||||
{
|
||||
ASSERT(fOutputEnabled == true);
|
||||
ASSERT(fRunning == false);
|
||||
ASSERT(fOutput);
|
||||
fRunning = true;
|
||||
fMixThreadWaitSem = create_sem(0, "mix thread wait");
|
||||
fMixThread = spawn_thread(_mix_thread_, "Yeah baby, very shagadelic", 12, this);
|
||||
@@ -275,13 +325,9 @@ MixerCore::Start(bigtime_t time)
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::Stop()
|
||||
MixerCore::StopMixThread()
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::Stop\n");
|
||||
if (!fRunning)
|
||||
return;
|
||||
|
||||
ASSERT(fRunning == true);
|
||||
ASSERT(fMixThread > 0);
|
||||
ASSERT(fMixThreadWaitSem > 0);
|
||||
|
||||
@@ -294,12 +340,14 @@ MixerCore::Stop()
|
||||
fRunning = false;
|
||||
}
|
||||
|
||||
/*
|
||||
bool
|
||||
MixerCore::IsStarted()
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
return fRunning;
|
||||
}
|
||||
*/
|
||||
|
||||
int32
|
||||
MixerCore::_mix_thread_(void *arg)
|
||||
@@ -321,14 +369,19 @@ MixerCore::MixThread()
|
||||
// The broken BeOS R5 multiaudio node starts with time 0,
|
||||
// then publishes negative times for about 50ms, publishes 0
|
||||
// again until it finally reaches time values > 0
|
||||
Lock();
|
||||
start = fTimeSource->Now();
|
||||
Unlock();
|
||||
while (start <= 0) {
|
||||
printf("MixerCore: delaying MixThread start, timesource is at %Ld\n", start);
|
||||
snooze(1000);
|
||||
Lock();
|
||||
start = fTimeSource->Now();
|
||||
Unlock();
|
||||
}
|
||||
|
||||
latency = bigtime_t(0.2 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio));
|
||||
Lock();
|
||||
latency = bigtime_t(0.4 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio));
|
||||
|
||||
printf("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld\n", start, latency, fDownstreamLatency);
|
||||
|
||||
@@ -337,6 +390,7 @@ MixerCore::MixThread()
|
||||
int64 temp = frames_for_duration(fMixBufferFrameRate, start );
|
||||
frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount;
|
||||
time_base = duration_for_frames(fMixBufferFrameRate, frame_base);
|
||||
Unlock();
|
||||
|
||||
printf("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
|
||||
|
||||
@@ -344,7 +398,8 @@ MixerCore::MixThread()
|
||||
frame_pos = 0;
|
||||
for (;;) {
|
||||
status_t rv;
|
||||
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, latency + fDownstreamLatency));
|
||||
// rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, latency + fDownstreamLatency));
|
||||
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, 0) - latency - fDownstreamLatency);
|
||||
if (rv == B_INTERRUPTED)
|
||||
continue;
|
||||
if (rv != B_TIMED_OUT && rv < B_OK)
|
||||
|
||||
@@ -37,10 +37,13 @@ public:
|
||||
void SetOutputBufferGroup(BBufferGroup *group);
|
||||
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency);
|
||||
void EnableOutput(bool enabled);
|
||||
void Start(bigtime_t time);
|
||||
void Stop();
|
||||
bool Start();
|
||||
bool Stop();
|
||||
|
||||
void StartMixThread();
|
||||
void StopMixThread();
|
||||
|
||||
bool IsStarted();
|
||||
// bool IsStarted();
|
||||
|
||||
uint32 OutputChannelCount();
|
||||
|
||||
@@ -55,7 +58,9 @@ private:
|
||||
BList *fInputs;
|
||||
MixerOutput *fOutput;
|
||||
int32 fNextInputID;
|
||||
bool fRunning;
|
||||
bool fRunning; // true = the mix thread is running
|
||||
bool fStarted; // true = mix thread should be started of it is not running
|
||||
bool fOutputEnabled; // true = mix thread should be started of it is not running
|
||||
|
||||
Resampler **fResampler; // array
|
||||
|
||||
|
||||
@@ -61,9 +61,6 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
|
||||
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
|
||||
|
||||
SetMixBufferFormat(mixFrameRate, mixFrameCount);
|
||||
UpdateChannelDesignations();
|
||||
UpdateMixerChannels();
|
||||
|
||||
|
||||
// XXX a test:
|
||||
/*
|
||||
@@ -95,7 +92,10 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
||||
size_t size;
|
||||
bigtime_t start;
|
||||
|
||||
ASSERT(fMixBuffer);
|
||||
if (!fMixBuffer) {
|
||||
printf("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
data = buffer->Data();
|
||||
size = buffer->SizeUsed();
|
||||
@@ -305,8 +305,6 @@ MixerInput::UpdateMixerChannels()
|
||||
mixer_chan_info *old_mixer_channel_info;
|
||||
uint32 old_mixer_channel_count;
|
||||
|
||||
ASSERT(fMixBuffer);
|
||||
|
||||
printf("UpdateMixerChannels: enter\n");
|
||||
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
@@ -350,7 +348,7 @@ MixerInput::UpdateMixerChannels()
|
||||
int j;
|
||||
for (j = 0; j < fInputChannelCount; j++) {
|
||||
if (fInputChannelInfo[j].designations & ChannelTypeToChannelMask(fMixerChannelInfo[i].type)) {
|
||||
fMixerChannelInfo[i].buffer_base = &fMixBuffer[j];
|
||||
fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -389,7 +387,7 @@ MixerInput::GetMixerChannelCount()
|
||||
void
|
||||
MixerInput::GetMixerChannelInfo(int channel, int64 framepos, const float **buffer, uint32 *sample_offset, int *type, float *gain)
|
||||
{
|
||||
ASSERT(fMixBuffer);
|
||||
ASSERT(fMixBuffer); // this function should not be called if we don't have a mix buffer!
|
||||
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
||||
int32 offset = framepos % fMixBufferFrameCount;
|
||||
if (channel == 0) printf("GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames);
|
||||
@@ -420,10 +418,25 @@ MixerInput::GetMixerChannelGain(int channel)
|
||||
void
|
||||
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
||||
{
|
||||
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
|
||||
|
||||
fMixBufferFrameRate = framerate;
|
||||
debugMixBufferFrames = frames;
|
||||
|
||||
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
|
||||
// frames and/or framerate can be 0 (if no output is connected)
|
||||
if (framerate == 0 || frames == 0) {
|
||||
if (fMixBuffer) {
|
||||
rtm_free(fMixBuffer);
|
||||
fMixBuffer = 0;
|
||||
}
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
fInputChannelInfo[i].buffer_base = 0;
|
||||
fMixBufferFrameCount = 0;
|
||||
|
||||
UpdateChannelDesignations();
|
||||
UpdateMixerChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
// make fMixBufferFrameCount an integral multiple of frames,
|
||||
// but at least 3 times duration of our input buffer
|
||||
@@ -451,4 +464,7 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
||||
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
|
||||
|
||||
UpdateChannelDesignations();
|
||||
UpdateMixerChannels();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user