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(); }