Friday, June 5, 2009

Adjusting the iPhone master volume programmatically

Looking for a way to adjust the master volume control on the iPhone via a function call? It's been said it can't be done without using the private Celestial framework, but that's not true!

If you are using an MPVolumeView to provide a slider interface for adjusting the iPhone system volume, you can adjust the value of this slider and in turn adjust the master volume on the iPhone.

Here's how I figured it out.

Assuming you already have an instance of the MPVolumeView class, you need to search its subviews to find the MPVolumeSlider view:


UISlider *volumeViewSlider;

// Find the MPVolumeSlider
for (UIView *view in [volumeView subviews]){
if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
volumeViewSlider = view;
}
}


So, what is an MPVolumeSlider and what can you do with it? Well, here's where Erica Sadun's documentation on the iPhone SDK classes comes in handy. Specifically the page which documents the MPVolumeSlider.

If you take a look at that documentation, you can see an MPVolumeSlider is a subclass of the UISlider. This means you can do all the UISlider type stuff to it, such as change the look, color, etc. I've already documented taking advantage of that in a sample XCode project in a previous blog post.

So, if it's a UISlider, what happens if we try to adjust its slider value via this call?


[volumeViewSlider setValue: 1.0f animated:YES];


Well, the slider does change to the maximum value, but the system volume remains the same. If we then just tap on the thumb control for the slider, the volume then immediately jumps to the new volume level, but we are looking for a solution that requires no user interaction. We are getting close, but not quite a complete answer.

Since the volume does change when the slider is tapped, I then tried looking at the targets that might have registered with the UIControl methods of the slider:


NSSet *mySet = [volumeViewSlider allTargets];
NSLog(@"%@", mySet);


No such luck. The targets was null. So, how is the system volume getting changed when someone drags the slider? Something has to be monitoring the slider, right?

Well, I tried to see if any targets were registered as being notified by any UIControl event:

NSArray *actions = [volumeViewSlider actionsForTarget:nil forControlEvent:UIControlEventAllEvents];
NSLog(@"Actions:%@", actions);

But, again the results were nil.

So, not having any luck there, I took another look at the documentation on Erica's site. I noticed a class method for the MPVolumeSlider class called _commitVolumeChange. Hmmm.... could this be useful? Indeed, it is!

A simple two function call as follows does the trick!

[volumeViewSlider setValue: 1.0f animated:YES];
[volumeViewSlider _commitVolumeChange];


So, this turns out to be a very easy way to adjust the master volume of the iPhone. You should be aware the _commitVolumeChange method is NOT documented, which means Apple could change it at any time. It currently works for all versions of the iPhone OS, but that doesn't mean it won't change in the future.

All content copyright © 2009  Brian Stormont, unless otherwise noted.   All rights reserved.