8

I am working on an iPad app that connects with an accessory that plays sound. When the iPad is connected to the accessory, I would like to mute all system sounds but allow other sounds (iPod).

Part of the reason for this is that the accessory is such that it is intended to be used during a live performance. Clearly it would be annoying to have e-mail, alert, or any other system sound running through and amplified (crazy loud).

I have looked at using AVAudioSession (read Audio Sessions to learn more) and tried all of the AudioSessionCategories. None of these categories will mute the system sound, instead it will only allow you to mute application sounds (iPod) - not useful for my purposes.

I also found docs on "System Sound Services", but this only allows you to play system sounds. There is no api here to disable system sounds while your app is running.

A final note, we have made it easy to adjust the iPad level (volume) by including the MPVolumeView, but we expect the user to want to play iPod music. If while playing iPod music (or music from another app) and an e-mail comes through, you'd be amazed how LOUD / ANNOYING that e-mail suddenly becomes when going through our accessory. It's even possible it could damage equipment. :D

Sam
  • 26,946
  • 12
  • 75
  • 101
  • Looks like it is possible to do what I want, but would require using private API's, which apple will reject your app for. I found these links: [sync-volume-rocker-with-a-uislider](http://stackoverflow.com/questions/1971877/sync-volume-rocker-with-a-uislider) and [AVSystemController.h](http://hexorcist.com/private_frameworks/html/interface_a_v_system_controller.html). I wonder if the accessory can tell the app to not make sound for the ringer and alerts... – Sam Jun 09 '11 at 16:57

3 Answers3

14

It is possible to change the system sounds, which turns out to be the ringer btw, using the AVSystemController. However, AVSystemController exists in the private Celestial framework. Since this framework is referenced by UIKit, it is still possible to use this class without directly referencing it.

Apple prohibits using private API's, so that alone makes this a bad idea. Given my circumstance, I think they may make an exception, BUT I will likely abandon this course since after taking it I realized that it didn't fix my problem. It does indeed mute the sounds, but as soon as I plug in to my accessory, the system sounds come out at max volume even though the ringer volume is set to 0. This leads me to believe the answer to solving my problem is in the MFI documentation.

Anyhow, here is how to change the ringer using private framework / api (which will get your app rejected without some kind of special permission).

short answer:

[[AVSystemController sharedAVSystemController] setVolumeTo:0 forCategory:@"Ringtone"];

answer without having to directly reference Celestial frameork / AVSystemController.h:

- (void) setSystemVolumeLevelTo:(float)newVolumeLevel
{   
    Class avSystemControllerClass = NSClassFromString(@"AVSystemController");
    id avSystemControllerInstance = [avSystemControllerClass performSelector:@selector(sharedAVSystemController)];

    NSString *soundCategory = @"Ringtone";

    NSInvocation *volumeInvocation = [NSInvocation invocationWithMethodSignature:
                                      [avSystemControllerClass instanceMethodSignatureForSelector:
                                       @selector(setVolumeTo:forCategory:)]];
    [volumeInvocation setTarget:avSystemControllerInstance];
    [volumeInvocation setSelector:@selector(setVolumeTo:forCategory:)];
    [volumeInvocation setArgument:&newVolumeLevel atIndex:2];
    [volumeInvocation setArgument:&soundCategory atIndex:3];
    [volumeInvocation invoke];
}
Sam
  • 26,946
  • 12
  • 75
  • 101
  • Hi Sam, I've tried the code above and it does let me change the volume of the Ringer, but when I set it to 0, it won't completely silence the device, but rather change it to 1 bar (really quiet, but not silent). Do you know how can I completely silence the device? Thanks! – itai alter Apr 28 '12 at 20:24
  • @itai you might have to post that as a new Q. I believe SO has a site dedicated to exposing apple private APIs. I'll comment again if I find it. Sorry I can't be more helpful. It's surprising to me that apple can't see the usefulness in a feature such as muting volume. – Sam Apr 29 '12 at 13:48
  • The above Code snippet is not working for me, I'm trying on iOS6. Kindly let me know, how to mute the ringer volume. – shatthi Nov 22 '12 at 10:48
  • It actually works perfectly, but does not disable unfortunately! – Panagiotis Nov 02 '13 at 13:14
  • Hi @Sam , was the second code accepted by Apple ? Or do you think it will be accepted? – rahulg Mar 23 '14 at 12:13
  • 1
    @rahulg I ended up not using either of the code examples as it didn't help for my specific needs, but since I had figured out how to do it I thought I'd share. My guess is that Apple would reject an app that used either code. The 2nd might go unnoticed so it could slip past, but if they ever found out, I'm sure it would get rejected. – Sam Mar 23 '14 at 19:41
  • Hello Sam, Thanks for the above code. But when I run that code, it is crashing the App where it returns a nil value in id : [avSystemControllerClass performSelector:@selector(sharedAVSystemController)]; Please help. – ScarletWitch Apr 06 '14 at 12:31
  • @ScarletWitch You may want to open a new question as this one is now pretty old -- and I don't do iOS development anymore. However, trying to use Apple's private API's can be problematic as they may fail your app during a review or may remove it if they ever find out you're using it. Be cautious. Hopefully they added an API to actually allow you to do this now. – Sam Apr 06 '14 at 17:04
  • 2
    Thanks. Resolved it by adding the following code : - (void) setSystemVolumeLevelTo:(float)newVolumeLevel { NSBundle *b = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/Celestial.framework"]; [b load]; ... } – ScarletWitch Apr 07 '14 at 08:50
4

Using MediaPlayer framework, we can set the level of SYSTEM sound

[[MPMusicPlayerController applicationMusicPlayer] setVolume:0]; 
Srikar Appalaraju
  • 71,928
  • 54
  • 216
  • 264
BB.
  • 707
  • 2
  • 11
  • 22
1

Best you can do is encourage your users to go into airplane mode.

pkananen
  • 1,325
  • 1
  • 11
  • 23
  • I've seen this before. I can't remember specific examples, but some accessories do recommend utilizing Airplane Mode while using their apps. I can't imagine this being an issue save if network access was needed in some way. – esqew Jun 08 '11 at 19:58
  • That would elminate e-mail alerts, but they still might have alerts or a phone ring tone (if they get phone call on 3g ipad). These would both be horrendous when connected to the accessory, even not during a performance. – Sam Jun 08 '11 at 23:20