From da30b4bf83d8c142830ade0d8e45be548452f843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 30 Jun 2009 10:14:54 +0000 Subject: [PATCH] * With the help of Stippi's "I Will Survive" article, the VolumeControl replicant should now handle media server restarts, or late starts gracefully. * This fixed ticket #4002. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31322 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/bin/desklink/MixerControl.cpp | 79 +++++++++++++------ src/bin/desklink/MixerControl.h | 10 ++- src/bin/desklink/VolumeControl.cpp | 118 ++++++++++++++++++++++++----- src/bin/desklink/VolumeControl.h | 7 +- 4 files changed, 167 insertions(+), 47 deletions(-) diff --git a/src/bin/desklink/MixerControl.cpp b/src/bin/desklink/MixerControl.cpp index 52ba9b17b8..6a69f1e8fd 100644 --- a/src/bin/desklink/MixerControl.cpp +++ b/src/bin/desklink/MixerControl.cpp @@ -17,8 +17,7 @@ #include -MixerControl::MixerControl(int32 volumeWhich, float* _value, - const char** _error) +MixerControl::MixerControl(int32 volumeWhich) : fVolumeWhich(volumeWhich), fGainMediaNode(media_node::null), @@ -28,12 +27,28 @@ MixerControl::MixerControl(int32 volumeWhich, float* _value, fMax(0.0f), fStep(0.0f) { +} + + +MixerControl::~MixerControl() +{ + _Disconnect(); +} + + +bool +MixerControl::Connect(int32 volumeWhich, float* _value, const char** _error) +{ + fVolumeWhich = volumeWhich; + + _Disconnect(); + bool retrying = false; - status_t err = B_OK; - /* BMediaRoster::Roster() doesn't set it if all is ok */ + status_t status = B_OK; + // BMediaRoster::Roster() doesn't set it if all is ok const char* errorString = NULL; - BMediaRoster* roster = BMediaRoster::Roster(&err); + BMediaRoster* roster = BMediaRoster::Roster(&status); retry: // Here we release the BMediaRoster once if we can't access the system @@ -49,22 +64,22 @@ retry: roster->Quit(); } snooze(10000); - roster = BMediaRoster::Roster(&err); + roster = BMediaRoster::Roster(&status); } - - if (roster && err == B_OK) { + + if (roster != NULL && status == B_OK) { switch (volumeWhich) { case VOLUME_USE_MIXER: - err = roster->GetAudioMixer(&fGainMediaNode); + status = roster->GetAudioMixer(&fGainMediaNode); break; case VOLUME_USE_PHYS_OUTPUT: - err = roster->GetAudioOutput(&fGainMediaNode); + status = roster->GetAudioOutput(&fGainMediaNode); break; } - if (err == B_OK) { - err = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb); - if (err == B_OK) { - // Finding the Mixer slider in the audio output ParameterWeb + if (status == B_OK) { + status = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb); + if (status == B_OK) { + // Finding the Mixer slider in the audio output ParameterWeb int32 numParams = fParameterWeb->CountParameters(); BParameter* p = NULL; bool foundMixerLabel = false; @@ -102,11 +117,14 @@ retry: if (!strcmp(p->Kind(), B_MASTER_GAIN)) { for (; i < numParams; i++) { p = fParamWeb->ParameterAt(i); - if (strcmp(p->Kind(), B_MASTER_GAIN)) p=NULL; - else break; + if (strcmp(p->Kind(), B_MASTER_GAIN)) + p = NULL; + else + break; } break; - } else p = NULL; + } else + p = NULL; #endif p = NULL; } @@ -149,7 +167,7 @@ retry: errorString = "No Media Roster"; } - if (err != B_OK) + if (status != B_OK) fGainMediaNode = media_node::null; if (errorString) { @@ -159,16 +177,15 @@ retry: } if (fMixerParameter == NULL && _value != NULL) *_value = 0; + + return errorString == NULL; } -MixerControl::~MixerControl() +bool +MixerControl::Connected() { - delete fParameterWeb; - - BMediaRoster* roster = BMediaRoster::CurrentRoster(); - if (roster != NULL && fGainMediaNode != media_node::null) - roster->ReleaseNode(fGainMediaNode); + return fGainMediaNode != media_node::null; } @@ -220,3 +237,17 @@ MixerControl::ChangeVolumeBy(float value) SetVolume(volume + value); } + +void +MixerControl::_Disconnect() +{ + delete fParameterWeb; + fParameterWeb = NULL; + fMixerParameter = NULL; + + BMediaRoster* roster = BMediaRoster::CurrentRoster(); + if (roster != NULL && fGainMediaNode != media_node::null) + roster->ReleaseNode(fGainMediaNode); + + fGainMediaNode = media_node::null; +} diff --git a/src/bin/desklink/MixerControl.h b/src/bin/desklink/MixerControl.h index 4091a2e221..1766585e92 100644 --- a/src/bin/desklink/MixerControl.h +++ b/src/bin/desklink/MixerControl.h @@ -23,11 +23,13 @@ class BContinuousParameter; class MixerControl { public: - MixerControl(int32 volumeWhich, - float* _value = NULL, - const char** _error = NULL); + MixerControl(int32 volumeWhich); ~MixerControl(); + bool Connect(int32 volumeWhich, float* _value = NULL, + const char** _error = NULL); + bool Connected(); + int32 VolumeWhich() const; float Volume() const; @@ -40,6 +42,8 @@ public: media_node GainNode() { return fGainMediaNode; } private: + void _Disconnect(); + int32 fVolumeWhich; media_node fGainMediaNode; BParameterWeb* fParameterWeb; diff --git a/src/bin/desklink/VolumeControl.cpp b/src/bin/desklink/VolumeControl.cpp index dbf1cdbca3..99062cdfad 100644 --- a/src/bin/desklink/VolumeControl.cpp +++ b/src/bin/desklink/VolumeControl.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -28,17 +29,23 @@ #include "VolumeWindow.h" +static const char* kMediaServerSignature = "application/x-vnd.Be.media-server"; +static const char* kAddOnServerSignature = "application/x-vnd.Be.addon-host"; + +static const uint32 kMsgReconnectVolume = 'rcms'; + + VolumeControl::VolumeControl(int32 volumeWhich, bool beep, BMessage* message) : BSlider("VolumeControl", "Volume", message, 0, 1, B_HORIZONTAL), + fMixerControl(new MixerControl(volumeWhich)), fBeep(beep), - fSnapping(false) + fSnapping(false), + fConnectRetries(0) { font_height fontHeight; GetFontHeight(&fontHeight); SetBarThickness(ceilf((fontHeight.ascent + fontHeight.descent) * 0.7)); - _InitVolume(volumeWhich); - BRect rect(Bounds()); rect.top = rect.bottom - 7; rect.left = rect.right - 7; @@ -49,7 +56,10 @@ VolumeControl::VolumeControl(int32 volumeWhich, bool beep, BMessage* message) VolumeControl::VolumeControl(BMessage* archive) - : BSlider(archive) + : BSlider(archive), + fMixerControl(NULL), + fSnapping(false), + fConnectRetries(0) { if (archive->FindBool("beep", &fBeep) != B_OK) fBeep = false; @@ -58,7 +68,7 @@ VolumeControl::VolumeControl(BMessage* archive) if (archive->FindInt32("volume which", &volumeWhich) != B_OK) volumeWhich = VOLUME_USE_MIXER; - _InitVolume(volumeWhich); + fMixerControl = new MixerControl(volumeWhich); } @@ -109,10 +119,16 @@ VolumeControl::AttachedToWindow() else SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); - BMediaRoster* roster = BMediaRoster::CurrentRoster(); - if (roster != NULL && fMixerControl->GainNode() != media_node::null) { - roster->StartWatching(this, fMixerControl->GainNode(), - B_MEDIA_NEW_PARAMETER_VALUE); + be_roster->StartWatching(this, B_REQUEST_LAUNCHED | B_REQUEST_QUIT); + + _ConnectVolume(); + + if (!fMixerControl->Connected()) { + // Wait a bit, and try again - the media server might not have been + // ready yet + BMessage reconnect(kMsgReconnectVolume); + BMessageRunner::StartSending(this, &reconnect, 1000000LL, 1); + fConnectRetries = 3; } } @@ -120,11 +136,9 @@ VolumeControl::AttachedToWindow() void VolumeControl::DetachedFromWindow() { - BMediaRoster* roster = BMediaRoster::CurrentRoster(); - if (roster != NULL && fMixerControl->GainNode() != media_node::null) { - roster->StopWatching(this, fMixerControl->GainNode(), - B_MEDIA_NEW_PARAMETER_VALUE); - } + _DisconnectVolume(); + + be_roster->StopWatching(this); } @@ -267,6 +281,53 @@ VolumeControl::MessageReceived(BMessage* msg) "OK"))->Go(NULL); break; + case B_SOME_APP_LAUNCHED: + case B_SOME_APP_QUIT: + { + const char* signature; + if (msg->FindString("be:signature", &signature) != B_OK) + break; + + bool isMediaServer = !strcmp(signature, kMediaServerSignature); + bool isAddOnServer = !strcmp(signature, kAddOnServerSignature); + if (isMediaServer) + fMediaServerRunning = msg->what == B_SOME_APP_LAUNCHED; + if (isAddOnServer) + fAddOnServerRunning = msg->what == B_SOME_APP_LAUNCHED; + + if (isMediaServer || isAddOnServer) { + if (!fMediaServerRunning && !fAddOnServerRunning) { + // No media server around + SetLabel("No media server running"); + SetEnabled(false); + } else if (fMediaServerRunning && fAddOnServerRunning) { + // HACK! + // quit our now invalid instance of the media roster + // so that before new nodes are created, + // we get a new roster + BMediaRoster* roster = BMediaRoster::CurrentRoster(); + if (roster != NULL) { + roster->Lock(); + roster->Quit(); + } + + BMessage reconnect(kMsgReconnectVolume); + BMessageRunner::StartSending(this, &reconnect, 1000000LL, 1); + fConnectRetries = 3; + } + } + break; + } + + case kMsgReconnectVolume: + _ConnectVolume(); + if (!fMixerControl->Connected() && --fConnectRetries > 1) { + BMessage reconnect(kMsgReconnectVolume); + BMessageRunner::StartSending(this, &reconnect, + 6000000LL / fConnectRetries, 1); + } + break; + default: return BView::MessageReceived(msg); } @@ -324,11 +385,24 @@ VolumeControl::UpdateText() const void -VolumeControl::_InitVolume(int32 volumeWhich) +VolumeControl::_DisconnectVolume() { + BMediaRoster* roster = BMediaRoster::CurrentRoster(); + if (roster != NULL && fMixerControl->GainNode() != media_node::null) { + roster->StopWatching(this, fMixerControl->GainNode(), + B_MEDIA_NEW_PARAMETER_VALUE); + } +} + + +void +VolumeControl::_ConnectVolume() +{ + _DisconnectVolume(); + const char* errorString = NULL; float volume = 0.0; - fMixerControl = new MixerControl(volumeWhich, &volume, &errorString); + fMixerControl->Connect(fMixerControl->VolumeWhich(), &volume, &errorString); if (errorString != NULL) { SetLabel(errorString); @@ -337,6 +411,12 @@ VolumeControl::_InitVolume(int32 volumeWhich) SetLabel("Volume"); SetLimits((int32)floorf(fMixerControl->Minimum()), (int32)ceilf(fMixerControl->Maximum())); + + BMediaRoster* roster = BMediaRoster::CurrentRoster(); + if (roster != NULL && fMixerControl->GainNode() != media_node::null) { + roster->StartWatching(this, fMixerControl->GainNode(), + B_MEDIA_NEW_PARAMETER_VALUE); + } } SetEnabled(errorString == NULL); @@ -355,10 +435,10 @@ VolumeControl::_PointForValue(int32 value) const if (Orientation() == B_HORIZONTAL) { return ceilf(1.0f * (value - min) / (max - min) * (BarFrame().Width() - 2) + BarFrame().left + 1); - } else { - return ceilf(BarFrame().top - 1.0f * (value - min) / (max - min) - * BarFrame().Height()); } + + return ceilf(BarFrame().top - 1.0f * (value - min) / (max - min) + * BarFrame().Height()); } diff --git a/src/bin/desklink/VolumeControl.h b/src/bin/desklink/VolumeControl.h index 9294917964..8fe9ab6c64 100644 --- a/src/bin/desklink/VolumeControl.h +++ b/src/bin/desklink/VolumeControl.h @@ -42,7 +42,8 @@ protected: virtual const char* UpdateText() const; private: - void _InitVolume(int32 volumeWhich); + void _DisconnectVolume(); + void _ConnectVolume(); bool _IsReplicant() const; float _PointForValue(int32 value) const; @@ -54,6 +55,10 @@ private: bool fSnapping; float fMinSnap; float fMaxSnap; + + int32 fConnectRetries; + bool fMediaServerRunning; + bool fAddOnServerRunning; }; #endif // VOLUME_SLIDER_H