Can't use volume button to mute on iOS7
Asked Answered
S

3

7

I've migrated my VoIP application to iOS7 recently, and there's an open bug still remaining which I can't understand.

When in VoIP call, in iOS6 you can push the physical volume button to lower the volume, down to Zero.

Now, in iOS7, I can lower the sound only down to the last step before zero, which means the volume cannot be muted.

I suspect this is something that's on iOS7 side, since I don't have the problem with the same IPA on an iOS6 device.

Anybody knows what's up?

Sackcloth answered 16/10, 2013 at 13:33 Comment(4)
Does the mute switch work ?Reliance
I have the same issue in my app. The mute switch has no effect. If the app allows multitasking, you can't mute while multitasking either. Wish I knew how to correct the issue.Wakeful
what is the version of ios7 used you..Frier
Confirmed the issue on all versions of iOS7 available, 7.0.0->7.0.4 and 7.1 beta..Sackcloth
H
2

Same problem with my VoIP app...

My Solution: After everything is set up, set the category to Playback,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

Then set it back to PlayAndRecord,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

This works for me, hope this helps someone who comes across the same problem.

Hankow answered 4/8, 2014 at 18:52 Comment(2)
This actually fixed the issue on my side as well. Thanks. For those interested, this is what you should do!Sackcloth
Future SO browsers be warned: this approach disables any VoiceProcessingIO (vpio) audio unit configuration in iOS 9, by switching to RemoteIO when you set the playback-only category: RemoteIO allows rocker-button muting, but vpio is where the onboard AEC lives. For VoIP apps, this workaround may have undesirable consequences.Stuckey
R
3

A bit old question, but I also needed a solution for Gui13's question/comment:

We're not using any sort of control in our app, all volume interaction is based on volume buttons.. So I could maybe implement this but I'd need a way to tie it to the volume buttons. Is this possible?

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

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

and then:

__block UISlider *volumeSlider = nil;
[[volumeView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj isKindOfClass:[UISlider class]]) {
        volumeSlider = obj;
        *stop = YES;
    }
}];
[volumeSlider addTarget:self action:@selector(handleVolumeChanged:) forControlEvents:UIControlEventValueChanged];

with:

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

The [MPVolumeView new] code above inits MPVolumeView with no frame so, it's not visible in our self.view where it has been added as a subview, but it is important that it has to be added!

You can also init the MPVolumeView with the code:

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:self.view.frame];
volumeView.showsRouteButton = NO;
volumeView.showsVolumeSlider = NO;
[self.view addSubview:volumeView];

which will also init the empty MPVolumeView (i.e. without RouteButton and VolumeSlider).

What's interesting is that UISlider subview (actually MPVolumeSlider, the subclass of UISlider) will still be found in the enumerateObjectsUsingBlock above.

This approach is also interesting because you can save the reference to volumeSlider and use it later to set volume from code, or your custom control:

Init and add to your view:

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 update your custom control when the volume has been changed (i.e. by the hardware volume controls):

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

and also:

- (IBAction)myCustomVolumeSliderViewValueChanged:(id)sender {
    NSLog(@"set volume to: %f", self.myCustomVolumeSliderView.value);
    self.volumeSlider.value = self.myCustomVolumeSliderView.value;
}

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

Receipt answered 2/3, 2014 at 15:32 Comment(0)
J
2

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

Apple is assuming that they know each and every way in which a volume will need to be administered.

There are, in fact, occasions when we want to change how the volume is controlled without forcing the user to have a volume slider on the screen, (alarm clocks and media players come to mind immediately). Yuou can take reference

https://developer.apple.com/library/ios/documentation/mediaplayer/reference/MPVolumeView_Class/Reference/Reference.html

http://ios-blog.co.uk/tutorials/controlling-system-output-volume-with-the-mpvolumeview-class-part-one/

Jericajericho answered 15/11, 2013 at 9:53 Comment(2)
We're not using any sort of control in our app, all volume interaction is based on volume buttons.. So I could maybe implement this but I'd need a way to tie it to the volume buttons. Is this possible?Sackcloth
I'll give you the bounty since this is the closest to a solution I've seen. But this isn't the solution I was looking for..Sackcloth
H
2

Same problem with my VoIP app...

My Solution: After everything is set up, set the category to Playback,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

Then set it back to PlayAndRecord,

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

This works for me, hope this helps someone who comes across the same problem.

Hankow answered 4/8, 2014 at 18:52 Comment(2)
This actually fixed the issue on my side as well. Thanks. For those interested, this is what you should do!Sackcloth
Future SO browsers be warned: this approach disables any VoiceProcessingIO (vpio) audio unit configuration in iOS 9, by switching to RemoteIO when you set the playback-only category: RemoteIO allows rocker-button muting, but vpio is where the onboard AEC lives. For VoIP apps, this workaround may have undesirable consequences.Stuckey

© 2022 - 2024 — McMap. All rights reserved.