* 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
This commit is contained in:
parent
5b60969c5c
commit
da30b4bf83
@ -17,8 +17,7 @@
|
|||||||
#include <ParameterWeb.h>
|
#include <ParameterWeb.h>
|
||||||
|
|
||||||
|
|
||||||
MixerControl::MixerControl(int32 volumeWhich, float* _value,
|
MixerControl::MixerControl(int32 volumeWhich)
|
||||||
const char** _error)
|
|
||||||
:
|
:
|
||||||
fVolumeWhich(volumeWhich),
|
fVolumeWhich(volumeWhich),
|
||||||
fGainMediaNode(media_node::null),
|
fGainMediaNode(media_node::null),
|
||||||
@ -28,12 +27,28 @@ MixerControl::MixerControl(int32 volumeWhich, float* _value,
|
|||||||
fMax(0.0f),
|
fMax(0.0f),
|
||||||
fStep(0.0f)
|
fStep(0.0f)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MixerControl::~MixerControl()
|
||||||
|
{
|
||||||
|
_Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerControl::Connect(int32 volumeWhich, float* _value, const char** _error)
|
||||||
|
{
|
||||||
|
fVolumeWhich = volumeWhich;
|
||||||
|
|
||||||
|
_Disconnect();
|
||||||
|
|
||||||
bool retrying = false;
|
bool retrying = false;
|
||||||
|
|
||||||
status_t err = B_OK;
|
status_t status = B_OK;
|
||||||
/* BMediaRoster::Roster() doesn't set it if all is ok */
|
// BMediaRoster::Roster() doesn't set it if all is ok
|
||||||
const char* errorString = NULL;
|
const char* errorString = NULL;
|
||||||
BMediaRoster* roster = BMediaRoster::Roster(&err);
|
BMediaRoster* roster = BMediaRoster::Roster(&status);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
// Here we release the BMediaRoster once if we can't access the system
|
// Here we release the BMediaRoster once if we can't access the system
|
||||||
@ -49,22 +64,22 @@ retry:
|
|||||||
roster->Quit();
|
roster->Quit();
|
||||||
}
|
}
|
||||||
snooze(10000);
|
snooze(10000);
|
||||||
roster = BMediaRoster::Roster(&err);
|
roster = BMediaRoster::Roster(&status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roster && err == B_OK) {
|
if (roster != NULL && status == B_OK) {
|
||||||
switch (volumeWhich) {
|
switch (volumeWhich) {
|
||||||
case VOLUME_USE_MIXER:
|
case VOLUME_USE_MIXER:
|
||||||
err = roster->GetAudioMixer(&fGainMediaNode);
|
status = roster->GetAudioMixer(&fGainMediaNode);
|
||||||
break;
|
break;
|
||||||
case VOLUME_USE_PHYS_OUTPUT:
|
case VOLUME_USE_PHYS_OUTPUT:
|
||||||
err = roster->GetAudioOutput(&fGainMediaNode);
|
status = roster->GetAudioOutput(&fGainMediaNode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (err == B_OK) {
|
if (status == B_OK) {
|
||||||
err = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb);
|
status = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb);
|
||||||
if (err == B_OK) {
|
if (status == B_OK) {
|
||||||
// Finding the Mixer slider in the audio output ParameterWeb
|
// Finding the Mixer slider in the audio output ParameterWeb
|
||||||
int32 numParams = fParameterWeb->CountParameters();
|
int32 numParams = fParameterWeb->CountParameters();
|
||||||
BParameter* p = NULL;
|
BParameter* p = NULL;
|
||||||
bool foundMixerLabel = false;
|
bool foundMixerLabel = false;
|
||||||
@ -102,11 +117,14 @@ retry:
|
|||||||
if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
|
if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
|
||||||
for (; i < numParams; i++) {
|
for (; i < numParams; i++) {
|
||||||
p = fParamWeb->ParameterAt(i);
|
p = fParamWeb->ParameterAt(i);
|
||||||
if (strcmp(p->Kind(), B_MASTER_GAIN)) p=NULL;
|
if (strcmp(p->Kind(), B_MASTER_GAIN))
|
||||||
else break;
|
p = NULL;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else p = NULL;
|
} else
|
||||||
|
p = NULL;
|
||||||
#endif
|
#endif
|
||||||
p = NULL;
|
p = NULL;
|
||||||
}
|
}
|
||||||
@ -149,7 +167,7 @@ retry:
|
|||||||
errorString = "No Media Roster";
|
errorString = "No Media Roster";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != B_OK)
|
if (status != B_OK)
|
||||||
fGainMediaNode = media_node::null;
|
fGainMediaNode = media_node::null;
|
||||||
|
|
||||||
if (errorString) {
|
if (errorString) {
|
||||||
@ -159,16 +177,15 @@ retry:
|
|||||||
}
|
}
|
||||||
if (fMixerParameter == NULL && _value != NULL)
|
if (fMixerParameter == NULL && _value != NULL)
|
||||||
*_value = 0;
|
*_value = 0;
|
||||||
|
|
||||||
|
return errorString == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MixerControl::~MixerControl()
|
bool
|
||||||
|
MixerControl::Connected()
|
||||||
{
|
{
|
||||||
delete fParameterWeb;
|
return fGainMediaNode != media_node::null;
|
||||||
|
|
||||||
BMediaRoster* roster = BMediaRoster::CurrentRoster();
|
|
||||||
if (roster != NULL && fGainMediaNode != media_node::null)
|
|
||||||
roster->ReleaseNode(fGainMediaNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -220,3 +237,17 @@ MixerControl::ChangeVolumeBy(float value)
|
|||||||
SetVolume(volume + 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;
|
||||||
|
}
|
||||||
|
@ -23,11 +23,13 @@ class BContinuousParameter;
|
|||||||
|
|
||||||
class MixerControl {
|
class MixerControl {
|
||||||
public:
|
public:
|
||||||
MixerControl(int32 volumeWhich,
|
MixerControl(int32 volumeWhich);
|
||||||
float* _value = NULL,
|
|
||||||
const char** _error = NULL);
|
|
||||||
~MixerControl();
|
~MixerControl();
|
||||||
|
|
||||||
|
bool Connect(int32 volumeWhich, float* _value = NULL,
|
||||||
|
const char** _error = NULL);
|
||||||
|
bool Connected();
|
||||||
|
|
||||||
int32 VolumeWhich() const;
|
int32 VolumeWhich() const;
|
||||||
float Volume() const;
|
float Volume() const;
|
||||||
|
|
||||||
@ -40,6 +42,8 @@ public:
|
|||||||
media_node GainNode() { return fGainMediaNode; }
|
media_node GainNode() { return fGainMediaNode; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _Disconnect();
|
||||||
|
|
||||||
int32 fVolumeWhich;
|
int32 fVolumeWhich;
|
||||||
media_node fGainMediaNode;
|
media_node fGainMediaNode;
|
||||||
BParameterWeb* fParameterWeb;
|
BParameterWeb* fParameterWeb;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <Beep.h>
|
#include <Beep.h>
|
||||||
#include <ControlLook.h>
|
#include <ControlLook.h>
|
||||||
#include <Dragger.h>
|
#include <Dragger.h>
|
||||||
|
#include <MessageRunner.h>
|
||||||
#include <Roster.h>
|
#include <Roster.h>
|
||||||
|
|
||||||
#include <AppMisc.h>
|
#include <AppMisc.h>
|
||||||
@ -28,17 +29,23 @@
|
|||||||
#include "VolumeWindow.h"
|
#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)
|
VolumeControl::VolumeControl(int32 volumeWhich, bool beep, BMessage* message)
|
||||||
: BSlider("VolumeControl", "Volume", message, 0, 1, B_HORIZONTAL),
|
: BSlider("VolumeControl", "Volume", message, 0, 1, B_HORIZONTAL),
|
||||||
|
fMixerControl(new MixerControl(volumeWhich)),
|
||||||
fBeep(beep),
|
fBeep(beep),
|
||||||
fSnapping(false)
|
fSnapping(false),
|
||||||
|
fConnectRetries(0)
|
||||||
{
|
{
|
||||||
font_height fontHeight;
|
font_height fontHeight;
|
||||||
GetFontHeight(&fontHeight);
|
GetFontHeight(&fontHeight);
|
||||||
SetBarThickness(ceilf((fontHeight.ascent + fontHeight.descent) * 0.7));
|
SetBarThickness(ceilf((fontHeight.ascent + fontHeight.descent) * 0.7));
|
||||||
|
|
||||||
_InitVolume(volumeWhich);
|
|
||||||
|
|
||||||
BRect rect(Bounds());
|
BRect rect(Bounds());
|
||||||
rect.top = rect.bottom - 7;
|
rect.top = rect.bottom - 7;
|
||||||
rect.left = rect.right - 7;
|
rect.left = rect.right - 7;
|
||||||
@ -49,7 +56,10 @@ VolumeControl::VolumeControl(int32 volumeWhich, bool beep, BMessage* message)
|
|||||||
|
|
||||||
|
|
||||||
VolumeControl::VolumeControl(BMessage* archive)
|
VolumeControl::VolumeControl(BMessage* archive)
|
||||||
: BSlider(archive)
|
: BSlider(archive),
|
||||||
|
fMixerControl(NULL),
|
||||||
|
fSnapping(false),
|
||||||
|
fConnectRetries(0)
|
||||||
{
|
{
|
||||||
if (archive->FindBool("beep", &fBeep) != B_OK)
|
if (archive->FindBool("beep", &fBeep) != B_OK)
|
||||||
fBeep = false;
|
fBeep = false;
|
||||||
@ -58,7 +68,7 @@ VolumeControl::VolumeControl(BMessage* archive)
|
|||||||
if (archive->FindInt32("volume which", &volumeWhich) != B_OK)
|
if (archive->FindInt32("volume which", &volumeWhich) != B_OK)
|
||||||
volumeWhich = VOLUME_USE_MIXER;
|
volumeWhich = VOLUME_USE_MIXER;
|
||||||
|
|
||||||
_InitVolume(volumeWhich);
|
fMixerControl = new MixerControl(volumeWhich);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -109,10 +119,16 @@ VolumeControl::AttachedToWindow()
|
|||||||
else
|
else
|
||||||
SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
|
SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
|
||||||
|
|
||||||
BMediaRoster* roster = BMediaRoster::CurrentRoster();
|
be_roster->StartWatching(this, B_REQUEST_LAUNCHED | B_REQUEST_QUIT);
|
||||||
if (roster != NULL && fMixerControl->GainNode() != media_node::null) {
|
|
||||||
roster->StartWatching(this, fMixerControl->GainNode(),
|
_ConnectVolume();
|
||||||
B_MEDIA_NEW_PARAMETER_VALUE);
|
|
||||||
|
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
|
void
|
||||||
VolumeControl::DetachedFromWindow()
|
VolumeControl::DetachedFromWindow()
|
||||||
{
|
{
|
||||||
BMediaRoster* roster = BMediaRoster::CurrentRoster();
|
_DisconnectVolume();
|
||||||
if (roster != NULL && fMixerControl->GainNode() != media_node::null) {
|
|
||||||
roster->StopWatching(this, fMixerControl->GainNode(),
|
be_roster->StopWatching(this);
|
||||||
B_MEDIA_NEW_PARAMETER_VALUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -267,6 +281,53 @@ VolumeControl::MessageReceived(BMessage* msg)
|
|||||||
"OK"))->Go(NULL);
|
"OK"))->Go(NULL);
|
||||||
break;
|
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:
|
default:
|
||||||
return BView::MessageReceived(msg);
|
return BView::MessageReceived(msg);
|
||||||
}
|
}
|
||||||
@ -324,11 +385,24 @@ VolumeControl::UpdateText() const
|
|||||||
|
|
||||||
|
|
||||||
void
|
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;
|
const char* errorString = NULL;
|
||||||
float volume = 0.0;
|
float volume = 0.0;
|
||||||
fMixerControl = new MixerControl(volumeWhich, &volume, &errorString);
|
fMixerControl->Connect(fMixerControl->VolumeWhich(), &volume, &errorString);
|
||||||
|
|
||||||
if (errorString != NULL) {
|
if (errorString != NULL) {
|
||||||
SetLabel(errorString);
|
SetLabel(errorString);
|
||||||
@ -337,6 +411,12 @@ VolumeControl::_InitVolume(int32 volumeWhich)
|
|||||||
SetLabel("Volume");
|
SetLabel("Volume");
|
||||||
SetLimits((int32)floorf(fMixerControl->Minimum()),
|
SetLimits((int32)floorf(fMixerControl->Minimum()),
|
||||||
(int32)ceilf(fMixerControl->Maximum()));
|
(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);
|
SetEnabled(errorString == NULL);
|
||||||
@ -355,10 +435,10 @@ VolumeControl::_PointForValue(int32 value) const
|
|||||||
if (Orientation() == B_HORIZONTAL) {
|
if (Orientation() == B_HORIZONTAL) {
|
||||||
return ceilf(1.0f * (value - min) / (max - min)
|
return ceilf(1.0f * (value - min) / (max - min)
|
||||||
* (BarFrame().Width() - 2) + BarFrame().left + 1);
|
* (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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +42,8 @@ protected:
|
|||||||
virtual const char* UpdateText() const;
|
virtual const char* UpdateText() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _InitVolume(int32 volumeWhich);
|
void _DisconnectVolume();
|
||||||
|
void _ConnectVolume();
|
||||||
bool _IsReplicant() const;
|
bool _IsReplicant() const;
|
||||||
float _PointForValue(int32 value) const;
|
float _PointForValue(int32 value) const;
|
||||||
|
|
||||||
@ -54,6 +55,10 @@ private:
|
|||||||
bool fSnapping;
|
bool fSnapping;
|
||||||
float fMinSnap;
|
float fMinSnap;
|
||||||
float fMaxSnap;
|
float fMaxSnap;
|
||||||
|
|
||||||
|
int32 fConnectRetries;
|
||||||
|
bool fMediaServerRunning;
|
||||||
|
bool fAddOnServerRunning;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VOLUME_SLIDER_H
|
#endif // VOLUME_SLIDER_H
|
||||||
|
Loading…
Reference in New Issue
Block a user