[haiku-commits] BRANCH jessicah-github.desklink [bf1e9de5641b] in src: kits/media bin/desklink

  • From: jessicah-github.desklink <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 15 Jan 2017 15:15:30 +0100 (CET)

added 2 changesets to branch 'refs/remotes/jessicah-github/desklink'
old head: 0988c65d472772008c2e89ec8a9499524ddd51a8
new head: bf1e9de5641b7dd426f87900c0bbd80ad5eeb6dc
overview: https://github.com/jessicah/haiku/compare/0988c65d4727...bf1e9de5641b

----------------------------------------------------------------------------

4f581d85c815: DefaultMediaTheme: improve watching for parameter value changes.
  
  * Addresses TODO of sub-classing controls, registering with the
    media roster for parameter changes.
  * Also adds support for discrete parameter controls, which didn't
    have this functionality.
  * With this change, the controls no longer need to be focused or
    modified for the parameter changes to register.

bf1e9de5641b: desklink: use media_server notifications instead of polling.
  
  * This removes Pulse(), which would constantly reconnect to
    the mixer. With the previous changes to the
    DefaultMediaTheme, this also makes changes to the muted
    state instaneous when modified by some other app.

                         [ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ]

----------------------------------------------------------------------------

4 files changed, 347 insertions(+), 87 deletions(-)
src/bin/desklink/MediaReplicant.cpp  | 147 ++++++++++++----
src/bin/desklink/MixerControl.cpp    |   9 +-
src/bin/desklink/MixerControl.h      |   2 +
src/kits/media/DefaultMediaTheme.cpp | 276 +++++++++++++++++++++++++------

############################################################################

Commit:      4f581d85c815b8b3920fbc9395685fb48d3306d2
Author:      Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date:        Sun Jan 15 07:09:05 2017 UTC

DefaultMediaTheme: improve watching for parameter value changes.

* Addresses TODO of sub-classing controls, registering with the
  media roster for parameter changes.
* Also adds support for discrete parameter controls, which didn't
  have this functionality.
* With this change, the controls no longer need to be focused or
  modified for the parameter changes to register.

----------------------------------------------------------------------------

diff --git a/src/kits/media/DefaultMediaTheme.cpp 
b/src/kits/media/DefaultMediaTheme.cpp
index 3198fe1..20ca080 100644
--- a/src/kits/media/DefaultMediaTheme.cpp
+++ b/src/kits/media/DefaultMediaTheme.cpp
@@ -105,6 +105,51 @@ class TitleView : public BView {
                const char *fTitle;
 };
 
+class CheckBox : public BCheckBox {
+       public:
+               CheckBox(BRect area, const char* name, const char* label,
+                       BDiscreteParameter &parameter);
+               virtual ~CheckBox();
+
+               virtual void AttachedToWindow();
+       private:
+               BDiscreteParameter &fParameter;
+};
+
+class OptionPopUp : public BOptionPopUp {
+       public:
+               OptionPopUp(BRect area, const char* name, const char* label,
+                       BDiscreteParameter &parameter);
+               virtual ~OptionPopUp();
+
+               virtual void AttachedToWindow();
+       private:
+               BDiscreteParameter &fParameter;
+};
+
+class Slider : public BSlider {
+       public:
+               Slider(BRect area, const char* name, const char*label, int32 
minValue,
+                       int32 maxValue, BContinuousParameter &parameter);
+               virtual ~Slider();
+
+               virtual void AttachedToWindow();
+       private:
+               BContinuousParameter &fParameter;
+};
+
+class ChannelSlider : public BChannelSlider {
+       public:
+               ChannelSlider(BRect area, const char* name, const char* label,
+                       orientation orientation, int32 channels,
+                       BContinuousParameter &parameter);
+               virtual ~ChannelSlider();
+
+               virtual void AttachedToWindow();
+       private:
+               BContinuousParameter &fParameter;
+};
+
 class MessageFilter : public BMessageFilter {
        public:
                static MessageFilter *FilterFor(BView *view, BParameter 
&parameter);
@@ -126,7 +171,6 @@ class ContinuousMessageFilter : public MessageFilter {
 
                BControl                                *fControl;
                BContinuousParameter    &fParameter;
-               bool                                    fRegistered;
 };
 
 class DiscreteMessageFilter : public MessageFilter {
@@ -146,7 +190,7 @@ class DiscreteMessageFilter : public MessageFilter {
 const uint32 kMsgParameterChanged = '_mPC';
 
 
-static bool 
+static bool
 parameter_should_be_hidden(BParameter &parameter)
 {
        // ToDo: note, this is probably completely stupid, but it's the only
@@ -165,6 +209,25 @@ parameter_should_be_hidden(BParameter &parameter)
 }
 
 
+static void
+start_watching_for_parameter_changes(BControl* control, BParameter &parameter)
+{
+       if (BMediaRoster* roster = BMediaRoster::CurrentRoster()) {
+               roster->StartWatching(control, parameter.Web()->Node(),
+                       B_MEDIA_NEW_PARAMETER_VALUE);
+       }
+}
+
+
+static void
+stop_watching_for_parameter_changes(BControl* control, BParameter &parameter)
+{
+       if (BMediaRoster* roster = BMediaRoster::CurrentRoster()) {
+               roster->StopWatching(control, parameter.Web()->Node(),
+                       B_MEDIA_NEW_PARAMETER_VALUE);
+       }
+}
+
 //     #pragma mark -
 
 
@@ -203,21 +266,21 @@ DynamicScrollView::AttachedToWindow(void)
 }
 
 
-void 
+void
 DynamicScrollView::FrameResized(float width, float height)
 {
        UpdateBars();
 }
 
 
-void 
+void
 DynamicScrollView::FrameMoved(BPoint newPosition)
 {
        UpdateBars();
 }
 
 
-void 
+void
 DynamicScrollView::GetPreferredSize(float *_width, float *_height)
 {
        float width = 50;
@@ -233,7 +296,7 @@ DynamicScrollView::GetPreferredSize(float *_width, float 
*_height)
 }
 
 
-void 
+void
 DynamicScrollView::SetContentBounds(BRect bounds)
 {
        fContentBounds = bounds;
@@ -242,7 +305,7 @@ DynamicScrollView::SetContentBounds(BRect bounds)
 }
 
 
-void 
+void
 DynamicScrollView::UpdateBars()
 {
        // we need the size that the view wants to have, and the one
@@ -326,7 +389,7 @@ DynamicScrollView::UpdateBars()
                }
                if (vertical || fIsDocumentScroller)
                        barWidth -= B_V_SCROLL_BAR_WIDTH + 1;
-               
+
                fHorizontalScrollBar->MoveTo(bounds.left, bounds.bottom + 1);
                fHorizontalScrollBar->ResizeTo(barWidth, B_H_SCROLL_BAR_HEIGHT);
        }
@@ -368,7 +431,7 @@ GroupView::~GroupView()
 }
 
 
-void 
+void
 GroupView::AttachedToWindow()
 {
        for (int32 i = CountChildren(); i-- > 0;) {
@@ -381,13 +444,13 @@ GroupView::AttachedToWindow()
 }
 
 
-void 
+void
 GroupView::AllAttached()
 {
 }
 
 
-void 
+void
 GroupView::GetPreferredSize(float *_width, float *_height)
 {
        if (_width)
@@ -421,7 +484,7 @@ GroupView::MaxSize()
 }
 
 
-void 
+void
 GroupView::SetContentBounds(BRect bounds)
 {
        fContentBounds = bounds;
@@ -445,7 +508,7 @@ TabView::TabView(BRect frame, const char *name, 
button_width width,
 }
 
 
-void 
+void
 TabView::FrameResized(float width, float height)
 {
        BRect rect = Bounds();
@@ -457,7 +520,7 @@ TabView::FrameResized(float width, float height)
 }
 
 
-void 
+void
 TabView::Select(int32 tab)
 {
        BTabView::Select(tab);
@@ -486,7 +549,7 @@ SeparatorView::~SeparatorView()
 }
 
 
-void 
+void
 SeparatorView::Draw(BRect updateRect)
 {
        rgb_color color = ui_color(B_PANEL_BACKGROUND_COLOR);
@@ -523,7 +586,7 @@ TitleView::~TitleView()
 }
 
 
-void 
+void
 TitleView::Draw(BRect updateRect)
 {
        BRect rect(Bounds());
@@ -538,7 +601,7 @@ TitleView::Draw(BRect updateRect)
 }
 
 
-void 
+void
 TitleView::GetPreferredSize(float *_width, float *_height)
 {
        if (_width)
@@ -557,6 +620,93 @@ TitleView::GetPreferredSize(float *_width, float *_height)
 //     #pragma mark -
 
 
+CheckBox::CheckBox(BRect area, const char* name, const char* label,
+       BDiscreteParameter &parameter)
+       : BCheckBox(area, name, label, NULL),
+       fParameter(parameter)
+{
+}
+
+
+CheckBox::~CheckBox()
+{
+       stop_watching_for_parameter_changes(this, fParameter);
+}
+
+
+void
+CheckBox::AttachedToWindow()
+{
+       start_watching_for_parameter_changes(this, fParameter);
+}
+
+
+OptionPopUp::OptionPopUp(BRect area, const char* name, const char* label,
+       BDiscreteParameter &parameter)
+       : BOptionPopUp(area, name, label, NULL),
+       fParameter(parameter)
+{
+}
+
+
+OptionPopUp::~OptionPopUp()
+{
+       stop_watching_for_parameter_changes(this, fParameter);
+}
+
+
+void
+OptionPopUp::AttachedToWindow()
+{
+       start_watching_for_parameter_changes(this, fParameter);
+}
+
+
+Slider::Slider(BRect area, const char* name, const char* label, int32 minValue,
+       int32 maxValue, BContinuousParameter &parameter)
+       : BSlider(area, name, label, NULL, minValue, maxValue),
+       fParameter(parameter)
+{
+}
+
+
+Slider::~Slider()
+{
+       stop_watching_for_parameter_changes(this, fParameter);
+}
+
+
+void
+Slider::AttachedToWindow()
+{
+       start_watching_for_parameter_changes(this, fParameter);
+}
+
+
+ChannelSlider::ChannelSlider(BRect area, const char* name, const char* label,
+       orientation orientation, int32 channels, BContinuousParameter 
&parameter)
+       : BChannelSlider(area, name, label, NULL, orientation, channels),
+       fParameter(parameter)
+{
+}
+
+
+ChannelSlider::~ChannelSlider()
+{
+       stop_watching_for_parameter_changes(this, fParameter);
+}
+
+
+void
+ChannelSlider::AttachedToWindow()
+{
+       start_watching_for_parameter_changes(this, fParameter);
+}
+
+
+//     #pragma mark -
+
+
 MessageFilter::MessageFilter()
        : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE)
 {
@@ -593,8 +743,7 @@ ContinuousMessageFilter::ContinuousMessageFilter(BControl 
*control,
                BContinuousParameter &parameter)
        : MessageFilter(),
        fControl(control),
-       fParameter(parameter),
-       fRegistered(false)
+       fParameter(parameter)
 {
        // initialize view for us
        control->SetMessage(new BMessage(kMsgParameterChanged));
@@ -616,22 +765,12 @@ ContinuousMessageFilter::~ContinuousMessageFilter()
 }
 
 
-filter_result 
+filter_result
 ContinuousMessageFilter::Filter(BMessage *message, BHandler **target)
 {
        if (*target != fControl)
                return B_DISPATCH_MESSAGE;
 
-       // TODO: remove this work-around! We can solve this by subclassing the
-       // slider classes, and start watching in their AttachedToWindow() method
-       if (!fRegistered) {
-               if (BMediaRoster* roster = BMediaRoster::CurrentRoster()) {
-                       roster->StartWatching(fControl, 
fParameter.Web()->Node(),
-                               B_MEDIA_NEW_PARAMETER_VALUE);
-               }
-               fRegistered = true;
-       }
-               
        if (message->what == kMsgParameterChanged) {
                // update parameter from control
                // TODO: support for response!
@@ -715,7 +854,6 @@ DiscreteMessageFilter::DiscreteMessageFilter(BControl 
*control,
        control->SetMessage(new BMessage(kMsgParameterChanged));
 
        // set initial value
-
        size_t size = sizeof(int32);
        int32 value;
        if (parameter.GetValue((void *)&value, &size, NULL) < B_OK) {
@@ -739,13 +877,44 @@ DiscreteMessageFilter::~DiscreteMessageFilter()
 }
 
 
-filter_result 
+filter_result
 DiscreteMessageFilter::Filter(BMessage *message, BHandler **target)
 {
        BControl *control;
 
-       if (message->what != kMsgParameterChanged
-               || (control = dynamic_cast<BControl *>(*target)) == NULL)
+       if ((control = dynamic_cast<BControl *>(*target)) == NULL)
+               return B_DISPATCH_MESSAGE;
+
+       if (message->what == B_MEDIA_NEW_PARAMETER_VALUE) {
+               TRACE("DiscreteMessageFilter::Filter: Got a new parameter 
value\n");
+               const media_node* node;
+               int32 parameterID;
+               ssize_t size;
+               if (message->FindInt32("parameter", &parameterID) != B_OK
+                       || fParameter.ID() != parameterID
+                       || message->FindData("node", B_RAW_TYPE, (const 
void**)&node,
+                                       &size) != B_OK
+                       || fParameter.Web()->Node() != *node)
+                       return B_DISPATCH_MESSAGE;
+
+               int32 value = 0;
+               size_t valueSize = sizeof(int32);
+               if (fParameter.GetValue((void*)&value, &valueSize, NULL) < 
B_OK) {
+                       ERROR("DiscreteMessageFilter: Could not get value for 
continuous "
+                       "parameter %p (name '%s', node %d)\n", &fParameter,
+                       fParameter.Name(), (int)fParameter.Web()->Node().node);
+                       return B_SKIP_MESSAGE;
+               }
+               if (BCheckBox* checkBox = dynamic_cast<BCheckBox*>(control)) {
+                       checkBox->SetValue(value);
+               } else if (BOptionPopUp* popUp = 
dynamic_cast<BOptionPopUp*>(control)) {
+                       popUp->SetValue(value);
+               }
+
+               return B_SKIP_MESSAGE;
+       }
+
+       if (message->what != kMsgParameterChanged)
                return B_DISPATCH_MESSAGE;
 
        // update view
@@ -801,7 +970,7 @@ DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const 
BRect *hintRect)
        BRect rect;
        if (hintRect)
                rect = *hintRect;
-               
+
        BRect bestRect;
 
        // do we have more than one attached parameter group?
@@ -844,20 +1013,20 @@ DefaultMediaTheme::MakeViewFor(BParameterWeb *web, const 
BRect *hintRect)
 
                        return new DynamicScrollView(groupView->Name(), 
groupView);
                }
-               
-               DynamicScrollView *scrollView = new 
DynamicScrollView(groupView->Name(), groupView);            
+
+               DynamicScrollView *scrollView = new 
DynamicScrollView(groupView->Name(), groupView);
                tabView->AddTab(scrollView);
-               
-               if (!hintRect) {                        
-                       bestRect = bestRect | scrollView->Bounds();             
        
-               }       
+
+               if (!hintRect) {
+                       bestRect = bestRect | scrollView->Bounds();
+               }
        }
-       
-       if (tabView != NULL) {          
+
+       if (tabView != NULL) {
                // this adjustment must be kept in sync with 
TabView::FrameResized
                bestRect.bottom += tabView->TabHeight();
-               bestRect.InsetBy(-3.0,-3.0);    
-               
+               bestRect.InsetBy(-3.0,-3.0);
+
                tabView->ResizeTo(bestRect.Width(), bestRect.Height());
                tabView->FrameResized(bestRect.Width(), bestRect.Height());
                        //needed since we're not attached to a window yet
@@ -1077,8 +1246,8 @@ DefaultMediaTheme::MakeViewFor(BParameter *parameter, 
const BRect *hintRect)
                                || discrete.CountItems() == 0) {
                                // create a checkbox item
 
-                               BCheckBox *checkBox = new BCheckBox(rect, 
discrete.Name(),
-                                       discrete.Name(), NULL);
+                               BCheckBox *checkBox = new CheckBox(rect, 
discrete.Name(),
+                                       discrete.Name(), discrete);
                                checkBox->ResizeToPreferred();
 
                                return checkBox;
@@ -1099,8 +1268,8 @@ DefaultMediaTheme::MakeViewFor(BParameter *parameter, 
const BRect *hintRect)
                                width += font.StringWidth(discrete.Name()) + 55;
                                rect.right = rect.left + width;
 
-                               BOptionPopUp *popUp = new BOptionPopUp(rect, 
discrete.Name(),
-                                       discrete.Name(), NULL);
+                               BOptionPopUp *popUp = new OptionPopUp(rect, 
discrete.Name(),
+                                       discrete.Name(), discrete);
 
                                for (int32 i = 0; i < discrete.CountItems(); 
i++) {
                                        
popUp->AddOption(discrete.ItemNameAt(i), discrete.ItemValueAt(i));
@@ -1118,8 +1287,9 @@ DefaultMediaTheme::MakeViewFor(BParameter *parameter, 
const BRect *hintRect)
 
                        if (!strcmp(continuous.Kind(), B_MASTER_GAIN)
                                || !strcmp(continuous.Kind(), B_GAIN)) {
-                               BChannelSlider *slider = new 
BChannelSlider(rect, continuous.Name(),
-                                       continuous.Name(), NULL, B_VERTICAL, 
continuous.CountChannels());
+                               BChannelSlider *slider = new ChannelSlider(rect,
+                                       continuous.Name(), continuous.Name(), 
B_VERTICAL,
+                                       continuous.CountChannels(), continuous);
 
                                char minLabel[64], maxLabel[64];
 
@@ -1148,8 +1318,8 @@ DefaultMediaTheme::MakeViewFor(BParameter *parameter, 
const BRect *hintRect)
                                return slider;
                        }
 
-                       BSlider *slider = new BSlider(rect, parameter->Name(), 
parameter->Name(),
-                               NULL, 0, 100);
+                       BSlider *slider = new Slider(rect, parameter->Name(),
+                               parameter->Name(), 0, 100, continuous);
 
                        float width, height;
                        slider->GetPreferredSize(&width, &height);

############################################################################

Commit:      bf1e9de5641b7dd426f87900c0bbd80ad5eeb6dc
Author:      Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date:        Sun Jan 15 15:40:54 2017 UTC

desklink: use media_server notifications instead of polling.

* This removes Pulse(), which would constantly reconnect to
  the mixer. With the previous changes to the
  DefaultMediaTheme, this also makes changes to the muted
  state instaneous when modified by some other app.

----------------------------------------------------------------------------

diff --git a/src/bin/desklink/MediaReplicant.cpp 
b/src/bin/desklink/MediaReplicant.cpp
index 6ce5f7c..64f3bf4 100644
--- a/src/bin/desklink/MediaReplicant.cpp
+++ b/src/bin/desklink/MediaReplicant.cpp
@@ -131,7 +131,6 @@ public:
        virtual void                    MouseDown(BPoint point);
        virtual void                    Draw(BRect updateRect);
        virtual void                    MessageReceived(BMessage* message);
-       virtual void                    Pulse();
 
 private:
                        status_t                _LaunchByPath(const char* path);
@@ -143,6 +142,11 @@ private:
                        void                    _SaveSettings();
                        void                    _Init();
 
+                       void                    _DisconnectMixer();
+                       status_t                _ConnectMixer();
+
+                       MixerControl*   fMixerControl;
+
                        BBitmap*                fIcon;
                        BBitmap*                fMutedIcon;
                        VolumeWindow*   fVolumeSlider;
@@ -179,6 +183,7 @@ MediaReplicant::~MediaReplicant()
 {
        delete fIcon;
        _SaveSettings();
+       _DisconnectMixer();
 }
 
 
@@ -208,6 +213,8 @@ MediaReplicant::AttachedToWindow()
 {
        AdoptParentColors();
 
+       _ConnectMixer();
+
        BView::AttachedToWindow();
 }
 
@@ -267,13 +274,13 @@ MediaReplicant::MouseDown(BPoint point)
                        where + BPoint(4, 4)));
 
        } else if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
-               MixerControl mixerControl;
-               if (mixerControl.Connect(fVolumeWhich)) {
-                       mixerControl.SetMute(!fMuted);
-                       fMuted = mixerControl.Mute();
+               if (fMixerControl != NULL) {
+                       fMixerControl->SetMute(!fMuted);
+                       fMuted = fMixerControl->Mute();
                        VolumeToolTip* tip = 
dynamic_cast<VolumeToolTip*>(ToolTip());
                        if (tip != NULL) {
                                tip->SetMuteMessage(fMuted ? 
B_TRANSLATE("Muted"): NULL);
+                               tip->Update();
                                ShowToolTip(tip);
                        }
                        Invalidate();
@@ -289,28 +296,6 @@ MediaReplicant::MouseDown(BPoint point)
 
 
 void
-MediaReplicant::Pulse()
-{
-       bool setMuted = false;
-       MixerControl mixerControl;
-       const char* errorString = NULL;
-       if (!mixerControl.Connect(fVolumeWhich, NULL, &errorString)) {
-               fMuted = true;
-               errorString = NULL;
-       } else
-               setMuted = mixerControl.Mute();
-
-       if (setMuted != fMuted) {
-               fMuted = setMuted;
-               VolumeToolTip* tip = dynamic_cast<VolumeToolTip*>(ToolTip());
-               if (tip != NULL)
-                       tip->SetMuteMessage(errorString);
-               Invalidate();
-       }
-}
-
-
-void
 MediaReplicant::MessageReceived(BMessage* message)
 {
        switch (message->what) {
@@ -350,8 +335,18 @@ MediaReplicant::MessageReceived(BMessage* message)
                        fVolumeWhich = item->IsMarked()
                                ? VOLUME_USE_PHYS_OUTPUT : VOLUME_USE_MIXER;
 
-                       if (VolumeToolTip* tip = 
dynamic_cast<VolumeToolTip*>(ToolTip()))
+                       if (_ConnectMixer() != B_OK
+                               && fVolumeWhich == VOLUME_USE_PHYS_OUTPUT) {
+                               // unable to switch to physical output
+                               item->SetMarked(false);
+                               fVolumeWhich = VOLUME_USE_MIXER;
+                               _ConnectMixer();
+                       }
+
+                       if (VolumeToolTip* tip = 
dynamic_cast<VolumeToolTip*>(ToolTip())) {
                                tip->SetWhich(fVolumeWhich);
+                               tip->Update();
+                       }
                        break;
                }
 
@@ -359,10 +354,8 @@ MediaReplicant::MessageReceived(BMessage* message)
                {
                        float deltaY;
                        if (message->FindFloat("be:wheel_delta_y", &deltaY) == 
B_OK
-                               && deltaY != 0.0) {
-                               MixerControl mixerControl;
-                               mixerControl.Connect(fVolumeWhich);
-                               mixerControl.ChangeVolumeBy(deltaY < 0 ? 6 : 
-6);
+                               && deltaY != 0.0 && fMixerControl != NULL) {
+                               fMixerControl->ChangeVolumeBy(deltaY < 0 ? 6 : 
-6);
 
                                VolumeToolTip* tip = 
dynamic_cast<VolumeToolTip*>(ToolTip());
                                if (tip != NULL) {
@@ -373,6 +366,46 @@ MediaReplicant::MessageReceived(BMessage* message)
                        break;
                }
 
+               case B_MEDIA_NEW_PARAMETER_VALUE:
+               {
+                       if (fMixerControl != NULL && 
!fMixerControl->Connected())
+                               return;
+
+                       bool setMuted = fMixerControl->Mute();
+                       if (setMuted != fMuted) {
+                               fMuted = setMuted;
+                               VolumeToolTip* tip = 
dynamic_cast<VolumeToolTip*>(ToolTip());
+                               if (tip != NULL) {
+                                       tip->SetMuteMessage(fMuted ? 
B_TRANSLATE("Muted") : NULL);
+                                       tip->Update();
+                               }
+                               Invalidate();
+                       }
+                       break;
+               }
+
+               case B_MEDIA_SERVER_STARTED:
+                       _ConnectMixer();
+                       break;
+
+               case B_MEDIA_NODE_CREATED:
+               {
+                       // It's not enough to wait for B_MEDIA_SERVER_STARTED 
message, as
+                       // the mixer will still be getting loaded by the media 
server
+                       media_node mixerNode;
+                       media_node_id mixerNodeID;
+                       BMediaRoster* roster = BMediaRoster::CurrentRoster();
+                       if (roster != NULL
+                               && 
message->FindInt32("media_node_id",&mixerNodeID) == B_OK
+                               && roster->GetNodeFor(mixerNodeID, &mixerNode) 
== B_OK) {
+                               if (mixerNode.kind == B_SYSTEM_MIXER) {
+                                       _ConnectMixer();
+                                       roster->ReleaseNode(mixerNode);
+                               }
+                       }
+                       break;
+               }
+
                default:
                        BView::MessageReceived(message);
                        break;
@@ -509,6 +542,56 @@ MediaReplicant::_Init()
 }
 
 
+void
+MediaReplicant::_DisconnectMixer()
+{
+       BMediaRoster* roster = BMediaRoster::CurrentRoster();
+       if (roster == NULL)
+               return;
+
+       roster->StopWatching(this, B_MEDIA_SERVER_STARTED | 
B_MEDIA_NODE_CREATED);
+
+       if (fMixerControl->MuteNode() != media_node::null) {
+               roster->StopWatching(this, fMixerControl->MuteNode(),
+                       B_MEDIA_NEW_PARAMETER_VALUE);
+       }
+
+       delete fMixerControl;
+       fMixerControl = NULL;
+}
+
+
+status_t
+MediaReplicant::_ConnectMixer()
+{
+       _DisconnectMixer();
+
+       BMediaRoster* roster = BMediaRoster::Roster();
+       if (roster == NULL)
+               return B_ERROR;
+
+       roster->StartWatching(this, B_MEDIA_SERVER_STARTED | 
B_MEDIA_NODE_CREATED);
+
+       fMixerControl = new MixerControl(fVolumeWhich);
+
+       const char* errorString = NULL;
+       float volume = 0.0;
+       fMixerControl->Connect(fVolumeWhich, &volume, &errorString);
+
+       if (errorString != NULL) {
+               SetToolTip(errorString);
+               return B_ERROR;
+       }
+
+       if (fMixerControl->MuteNode() != media_node::null) {
+               roster->StartWatching(this, fMixerControl->MuteNode(),
+                       B_MEDIA_NEW_PARAMETER_VALUE);
+       }
+
+       return B_OK;
+}
+
+
 //     #pragma mark -
 
 
diff --git a/src/bin/desklink/MixerControl.cpp 
b/src/bin/desklink/MixerControl.cpp
index 81cb36c..cdc6d3f 100644
--- a/src/bin/desklink/MixerControl.cpp
+++ b/src/bin/desklink/MixerControl.cpp
@@ -23,6 +23,7 @@ MixerControl::MixerControl(int32 volumeWhich)
        :
        fVolumeWhich(volumeWhich),
        fGainMediaNode(media_node::null),
+       fMuteMediaNode(media_node::null),
        fParameterWeb(NULL),
        fMixerParameter(NULL),
        fMuteParameter(NULL),
@@ -74,8 +75,10 @@ MixerControl::Connect(int32 volumeWhich, float* _value, 
const char** _error)
                                        p = fParameterWeb->ParameterAt(i);
 
                                        // assume the mute preceeding master 
gain control
-                                       if (!strcmp(p->Kind(), B_MUTE))
+                                       if (!strcmp(p->Kind(), B_MUTE)) {
                                                fMuteParameter = p;
+                                               fMuteMediaNode = 
fMuteParameter->Web()->Node();
+                                       }
 
                                        PRINT(("BParameter[%i]: %s\n", i, 
p->Name()));
                                        if (volumeWhich == VOLUME_USE_MIXER) {
@@ -151,8 +154,10 @@ MixerControl::Connect(int32 volumeWhich, float* _value, 
const char** _error)
        } else
                errorString = "Media services not running";
 
-       if (status != B_OK)
+       if (status != B_OK) {
                fGainMediaNode = media_node::null;
+               fMuteMediaNode = media_node::null;
+       }
 
        if (errorString) {
                fprintf(stderr, "MixerControl: %s.\n", errorString);
diff --git a/src/bin/desklink/MixerControl.h b/src/bin/desklink/MixerControl.h
index 68fd125..159ee38 100644
--- a/src/bin/desklink/MixerControl.h
+++ b/src/bin/desklink/MixerControl.h
@@ -44,12 +44,14 @@ public:
                        float                   Maximum() const { return fMax; }
 
                        media_node              GainNode() { return 
fGainMediaNode; }
+                       media_node              MuteNode() { return 
fMuteMediaNode; }
 
 private:
                        void                    _Disconnect();
 
                        int32                   fVolumeWhich;
                        media_node              fGainMediaNode;
+                       media_node              fMuteMediaNode;
                        BParameterWeb*  fParameterWeb;
                        BContinuousParameter* fMixerParameter;
                        BParameter*             fMuteParameter;


Other related posts: