How to change device Volume on iOS - not music volume

30,382

Solution 1

To answer brush51's question:

How can i do that? just change the DEVICE volume?

As 0x7fffffff suggested:

You cannot change device volume programatically, however MPVolumeView (volume slider) is there to change device volume but only through user interaction.

So, Apple recommends using MPVolumeView, so I came up with this:

Add volumeSlider property:

@property (nonatomic, strong) UISlider *volumeSlider;

Init MPVolumeView and add somewhere to your view (can be hidden, without frame, or empty because of showsRouteButton = NO and showsVolumeSlider = NO):

MPVolumeView *volumeView = [MPVolumeView new];
volumeView.showsRouteButton = NO;
volumeView.showsVolumeSlider = NO;
[self.view addSubview:volumeView];

Find and save reference to UISlider:

__weak __typeof(self)weakSelf = self;
[[volumeView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj isKindOfClass:[UISlider class]]) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        strongSelf.volumeSlider = obj;
        *stop = YES;
    }
}];

Add target action for UIControlEventValueChanged:

[self.volumeSlider addTarget:self action:@selector(handleVolumeChanged:) forControlEvents:UIControlEventValueChanged];

And then detect volume changing (i.e. by the hardware volume controls):

- (void)handleVolumeChanged:(id)sender
{
    NSLog(@"%s - %f", __PRETTY_FUNCTION__, self.volumeSlider.value);
}

and also other way around, you can set volume by:

self.volumeSlider.value = < some value between 0.0f and 1.0f >;

Hope this helps (and that Apple doesn't remove MPVolumeSlider from MPVolumeView).

Solution 2

This (Swift) solution worked great for me: http://weimenglee.blogspot.com/2015/07/ios-tip-programmatically-adjust-device.html

import MediaPlayer

let volumeView = MPVolumeView()
if let view = volumeView.subviews.first as? UISlider{
    view.value = 0.1 //---0 t0 1.0---

}

Solution 3

Here's what I've done:

func setSystemVolume(volume: Float) {
    let volumeView = MPVolumeView()

    for view in volumeView.subviews {
        if (NSStringFromClass(view.classForCoder) == "MPVolumeSlider") {
            let slider = view as! UISlider
            slider.setValue(volume, animated: false)
        }
    }
}

As property volume in MPMusicPlayerController was deprecate in iOS 7. This is only method you can do that.

Solution 4

You have to use applicationMusicPlayer instead of iPodMusicPlayer to set the system volume:

#import <MediaPlayer/MediaPlayer.h>
musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
musicPlayer.volume = 1; // max volume
musicPlayer.volume = 0; // min volume (mute)
musicPlayer.volume = 0.0625; // 1 bar on the overlay volume display

Solution 5

Here is a little wrapper class that can set the system volume and aslo notify you on any changes (pass your own change responder to setTarget:action:).

Edit: if you hide the MPVolumeView control or don't add it as a subview, then the system will show the default volume square in the middle of the screen whenever you change the volume programmatically. If you don't like what the system does, the solution is to set view coordinates outside of the screen. I edited my code below a bit to reflect this.

@import MediaPlayer;


@interface SysVolumeControl : MPVolumeView
@property (nonatomic) float value; // from 0 to 1.0
- (void)setTarget:(id)target action:(SEL)action;
@end


@implementation SysVolumeControl
{
    UISlider* _slider;
}

- (id)init
{
    if (self = [super initWithFrame:CGRectMake(-300, 0, 200, 50)])
    {
        for (UIView* view in self.subviews)
        {
            if ([view isKindOfClass:UISlider.class])
            {
                _slider = (UISlider*)view;
                break;
            }
        }
    }
    return self;
}

- (float)value
    { return _slider.value; }

- (void)setValue:(float)value
    { _slider.value = value; }

- (void)setTarget:(id)target action:(SEL)action
    { [_slider addTarget:target action:action forControlEvents:UIControlEventValueChanged]; }

@end

Then create an instance and use it:

SysVolumeControl* sysVolumeControl = [SysVolumeControl new];
[myView addSubview:sysVolumeControl];
sysVolumeControl.value = 1.0;
[sysVolumeControl setTarget:self action:@selector(mySysVolumeResponder:)];
Share:
30,382
brush51
Author by

brush51

**

Updated on July 25, 2020

Comments

  • brush51
    brush51 almost 4 years

    I want to change the device volume on iOS (iphone).

    I know that i can change the volume of music library with this lines below:

    //implement at first MediaPlayer framework
    MPMusicPlayerController *musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
    musicPlayer.volume = 1;
    

    But thats not my aim.
    I want to change the device volume or let me say the volume of ringer.

    How can i do that? just change the DEVICE volume?

  • Diego Freniche
    Diego Freniche about 10 years
    Note: this is deprecated in iOS 7
  • iCaramba
    iCaramba almost 10 years
    did you ever test that? Did you become rejected for changing volume programatically?
  • Dvole
    Dvole over 9 years
    Doesn't work for me on ios 7.1 and 8. Value of the slider changes, but the system sound volume does not.
  • nahung89
    nahung89 over 8 years
    @msrdjan: as I check in ios 8.3, volume value won't be setted if volumeView.showsRouteButton = NO; volumeView.showsVolumeSlider = NO; should keep default as YES
  • Christian
    Christian over 8 years
    in my tests this only worked when playing a sound at the same time continously and first setting the volume to more than 0 and afterwards reducing to 0 - just for reference for somebody running into the same issue
  • solenoid
    solenoid about 8 years
    Thanks for this - saved me a few hours or more trying to figure out how to cleanly access that slider. I have to say, this is so boneheaded on Apples part - my app is all gestures, and a slider has no place. Hope they don't reject based on this. I'll leave a nice note in the code.
  • solenoid
    solenoid about 8 years
    Just a few notes: changing volume outside the app (like control center) would cause this to not work anymore. It could be where I was using it, but I put it as a global var in appDelegate and it seems to work. I was also getting a start value of 0 in many circumstances. volumeView.setNeedsLayout() at some point before get/set of values fixes that issue.
  • Brian H
    Brian H over 6 years
    I'm curious, while this works, has it gotten through App Store review?
  • Andrea Gorrieri
    Andrea Gorrieri almost 6 years
    This method is no longer working in iOS 11.4, please refer to stackoverflow.com/a/50740234/2610888
  • Andrea Gorrieri
    Andrea Gorrieri almost 6 years
    This method is no longer working in iOS 11.4, please refer to stackoverflow.com/a/50740234/2610888