From d5848e21a402ad57ae434b9982560e0f9c2c0dbf Mon Sep 17 00:00:00 2001 From: beveloper Date: Sun, 29 Jun 2003 00:31:36 +0000 Subject: [PATCH] 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 --- .../media/media-add-ons/mixer/AudioMixer.cpp | 6 +- .../media/media-add-ons/mixer/MixerCore.cpp | 87 +++++++++++++++---- .../media/media-add-ons/mixer/MixerCore.h | 13 ++- .../media/media-add-ons/mixer/MixerInput.cpp | 34 ++++++-- 4 files changed, 108 insertions(+), 32 deletions(-) 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 bcd22162e8..2987a8a65f 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -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; 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 a052b43013..592d558193 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.cpp @@ -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) 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 5f38ff4de5..a142722124 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerCore.h +++ b/src/add-ons/media/media-add-ons/mixer/MixerCore.h @@ -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 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 6a50513852..142f5e5a60 100644 --- a/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp +++ b/src/add-ons/media/media-add-ons/mixer/MixerInput.cpp @@ -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(); }