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.

6 comments:

abhishek said...

Is there any (public or undocumented...but not private) way to get the current system volume...

Mostly Torn said...

I'm sure there must be a simpler way, but you can use the existing code I describe with MPVolumeView and query the slider's value to find out the current master volume setting. It's a totally over-complicated way to do it, but it works.

Anonymous said...

Anyone know if doing this will get your app rejected? I suppose it probably will, but I haven't found any other way to programatically max out the volume.

Mostly Torn said...

Anonymous,

I would assume making such an undocumented call would most likely have your app rejected. Apple now scans apps for undocumented system calls.

I have not tried to use this in an app store submission. For apps being used in the app store, I *highly* recommend using only documented APIs.

Anonymous said...

Mostly Torn,

Do you know of any other possible avenues to adjusting the system volume through code? I know it's possible because there are apps out there that do it (many alarm clocks for example will always play at full volume, even if you manually adjust it). Thanks for the info.

Anonymous said...

[[MPMusicPlayerController applicationMusicPlayer] setVolume:0.0f];


use this code to increase or decrease volume on ios devices.


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