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:
beveloper
2003-06-29 00:31:36 +00:00
parent 90f98241f4
commit d5848e21a4
4 changed files with 108 additions and 32 deletions
@@ -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();
}