3

I have a project with a MPVolumeView in it. It is set up, and it works, the only thing is that when I mute the device, the text "No Volume Available" comes up instead of the MPVolumeView. I would rather like the slider of the MPVolumeView to be disabled when the device is muted.

The volumeView is initialized in the view volumeBounds, with that view's bounds.

MPVolumeView *volumeView = [[[MPVolumeView alloc] initWithFrame:volumeBounds.bounds] autorelease];
[volumeBounds addSubview:volumeView]; 
[volumeView sizeToFit];

Thanks :)

If you are interested in helping me with something else, check out this question

Community
  • 1
  • 1
Emil
  • 7,220
  • 17
  • 76
  • 135
  • How? The only way to change the volume of the device is with an `MPVolumeView`. – Emil May 13 '10 at 19:43
  • 1
    You can change the volume starting with OS 3.0, See http://developer.apple.com/iphone/library/documentation/MediaPlayer/Reference/MPMusicPlayerController_ClassReference/Reference/Reference.html#//apple_ref/occ/instp/MPMusicPlayerController/volume – progrmr May 14 '10 at 00:03
  • That won't work with an `AVAudioPlayer`, would it? – Emil May 14 '10 at 05:38
  • 1
    AVAudioPlayer also has a volume property. You can use a UISlider like Kenny suggested and send it's value to the volume property. Thus MPVolumeView is not the only way to control volume. – progrmr May 14 '10 at 16:05
  • How can I achieve it with an MPVolumeView? Thats what I want. – Emil May 14 '10 at 19:01
  • My question is, how do I avoid displaying the text "No Volume Available" when a device is muted, I would rather like a way to disable the slider of the `MPVolumeView`. – Emil May 15 '10 at 19:33

2 Answers2

3

Use AudioServices to listen for the hardware volume. When the volume goes to zero, set the alpha of the MPVolumeSlider to zero and place your own disabled UISlider in the same position. Skin your slider to look like the volume slider.

AudioSessionAddPropertyListener( kAudioSessionProperty_CurrentHardwareOutputVolume , ... );

kAudioSessionProperty_AudioRouteChanged might also be useful.

If you walk the view hierarchy under the MPVolumeView, you should find a UISlider. If not, or if it is hidden, you know the mute string is showing.

Edit:

This describes the function prototype for your listener. To pass the message to an instance of your class, do something similar to:

void MyPropertyListener ( void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData );

void MyPropertyListener ( void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData ) {
  if ( inID == kAudioSessionProperty_CurrentHardwareOutputVolume ) {
    Float32 volume = *(Float32 *)inData;
    [(MyDelegateClass *)inClientData hardwareVolumeChanged:volume];
  }
}

AudioSessionAddPropertyListener( kAudioSessionProperty_CurrentHardwareOutputVolume ,
  MyPropertyListener , aDelegateInstance );
drawnonward
  • 53,459
  • 16
  • 107
  • 112
  • I just don't seem to get it; take a look at this code: `AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume, @selector(volumeChanged), self);`. That gets a warning that argument 2 is an incompitable pointer type. – Emil May 22 '10 at 21:24
  • and again, when I do this: `- (void) volumeChanged (void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue) { code }` I get the error "Expected { before ( token". What's wrong? All of this AudioSession-stuff is very new to me... – Emil May 22 '10 at 21:25
  • You have to pass a C function pointer to AddPropertyListener, not a selector, and have the C function call your Objective-C member. Return type of volumeChanged should be `void` not `-(void)` as it is a C function. – drawnonward May 23 '10 at 00:42
  • Do I need to type anything more than volumeChanged where the selector is now? I will try it. – Emil May 23 '10 at 08:31
  • I no longer get an error at the `void`-part, but I get an error saying that `volumeView` is undeclared. I have declared it allready in the .h-file and connected it properly in IB and everything, but it still won't say that it is declared.. – Emil May 23 '10 at 09:24
  • In .h: ` IBOutlet MPVolumeView *volumeView;` and `@property (retain) MPVolumeView *volumeView;`. .m: `@synthesize volumeView;` – Emil May 23 '10 at 09:25
  • I did not understand what your post said, that is why I didn't accept it, if you wondered. How can I use Obective-C objects in these `C`-functions? – Emil May 24 '10 at 08:10
  • You could as easily ask how to use a C++ object from C. You just do it. Objective-C is C. – drawnonward May 24 '10 at 17:37
1

I ended up with this solution for simplicity.

In Objective-C:

[UILabel appearanceWhenContainedIn: [MPVolumeView class], nil].textColor = [UIColor clearColor];

In Swift:

UILabel.appearanceWhenContainedWithin([MPVolumeView.self]).textColor = UIColor.clearColor()

Refer to the following answer for appearanceWhenContainedWithin method: appearanceWhenContainedIn in Swift

It just hides "No Volume Available" text rather than replacing with a disabled UISlider not to worry about the alignment between the MPVolumeView slider and UISlider.

AVPlayer has volume property but its document says:

Use this property to control a player’s audio volume relative to other audio output.

AVAudioSession has read-only outputVolume property and its document says:

The system wide output volume can be set directly only by the user; to provide volume control in your app, use the MPVolumeView class.

For the limitations, the simple solution (or workaround) is just setting the text color to clear.

Community
  • 1
  • 1
Yoichi Tagaya
  • 4,547
  • 2
  • 27
  • 38