Is it OK to mix AudioServicesPlaySystemSound and AVAudioPlayer? - iphone

We have a game that is very close to being released, but we have one extremely annoying problem. One on of our Beta testers phones, he can't hear any of the in game sound effects. He can, however, hear the background music and the title screen music just fine.
The background and title music are both being played via AVAudioPlayer (they are longer, we need looping and volume control, etc). The sound effects are simply being played with AudioServicesPlaySystemSound (they are very short, we don't need precise control or to know when they end, etc). This works on most iPhones, but not on this one. All of this is being played with an audio session of AVAudioSessionCategorySoloAmbient.
So I have two questions:
- First, is this an acceptable implementation? i.e. is there something I missed that says you can't mix these two frameworks, or a reason why its a bad idea to mix them?
- Second, has anyone seen something like this before? If so, did you find a way around it?
Additional background note: I can pretty conclusively say that on his phone, it is the mixing of the two frameworks. He was able to hear sounds until roughly the same build where we added the title screen music. Also, if I change one of the sounds to work through an AVAudioPlayer, he's able to hear it. Unfortunately, I can't simply move the sounds into AVAudioPlayers because it just doesn't perform well at all, and I need better synchronization.

EDIT 2:
I've determined the cause of the error. The two different audio frameworks play on two different volume settings. There is the main volume (that's what shows up once you are in the app, and has no title on it) and the ringer volume (that's what shows up when you're on the home screen without any app loaded). The AVAudioPlayer calls play with the main volume setting. As I have set the category to AVAudioSessionCategorySoloAmbient (see code below), this is the volume control that will be adjusted if you use the volume rocker inside the app. The SystemSounds, however, are played at the Ringer Volume. This will NOT come up inside the app, and as such does not allow the user to adjust their settings during the game.
It's easy to see the possible confusion for the user: Let's say they have their ringer set to low, or even off. They start playing the game. They hear the title screen music (AVAudioPlayer) and are able to turn the volume up or down and it responds normally. Then they start the game and the sound effects play (SystemSounds), and they hear nothing because the ringer volume is low/off. In an effort to hear the sound effects, they bump up the volume and the background music responds accordingly. So from this point of view, it definitely looks like the sound effects just aren't playing.
If you have this similar situation, have your user make sure that their ringer volume is up before playing the game and their mute switch is on (i.e. not muted). You can also verify all of this by doing the test yourself - drop your ringer volume and bump your in-app volume up. Your SystemSounds should drop out of the mix.
Original answer:
In re-digging through all of the docs, I found the answer. I wasn't properly activating the audio session. Previously I only had this code to set the category:
NSError *setCategoryError = nil;
BOOL categoryWasSet = [[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategorySoloAmbient
error: &setCategoryError];
But I needed to also add the following code to explicitly activate the audio session:
NSError *activationError = nil;
BOOL activationSuccess = [[AVAudioSession sharedInstance]
setActive: YES
error: &activationError];
I've re-tested with this user, and it has completely fixed the issue. Hope that helps anyone who might have a similar problem.
EDIT: This doesn't seem to have resolved the issue after all. I got a false positive from my tester, and when examined more in detail it seems that he didn't actually hear the SystemSound generated sounds.

I have two apps on the app store that mix those two frameworks. AVAudioPlayer for sounds that require start and stop and volume control and AudioServices toolbox for short little beeps and clicks. The only think I can think of, off the top of my head, is that the volume of AVAudioPlayer seems to be controlled separately from the AudioServices sounds. So check to make sure that the tester doesn't have sounds turned off (with the vibrate mode switch) or the volume turned way down.
If this doesn't help, tell me more about your sounds/code and I can add some code to my app to see if I can get the same behavior. Of course, sounds like most your testers don't have this problem, and I probably won't see it either.

Related

iOS determine if VoiceOver is still talking

Is there a way to determine whether VoiceOver is currently announcing and when it stops. I've tried UIAccessibilityVoiceOverStatusChanged but my understanding is that this is only if you switch VoiceOver on or off. Any help would be greatly appreciated. thanks.
We use otherAudioIsPlaying, the problem is some app's running in the background like some pedometer monitors etc. turn on the audio it seems and never release it so even though nothing is actually being spoken or played otherAudioIsPlaying always returns 1 until you remove the other application from the background. So now not only can you not play music but you have no idea that another application in the background will mess up this test. Apple really needs to put in an API to determine if Voice Over is currently speaking or not.
These are all the Accessibility booleans that I found in the documentation:
UIAccessibilityPostNotification
UIAccessibilityIsVoiceOverRunning
UIAccessibilityIsMonoAudioEnabled
UIAccessibilityIsClosedCaptioningEnabled
UIAccessibilityRegisterGestureConflictWithZoom
I don't think that there are any booleans to do what you are talking about.
You could use the audio session's "OtherAudioIsPlaying" property to check if another system process is using the audio hardware at the moment. It should be "true" if VoiceOver is speaking and "false" if not.
Actually this might not work properly if the user is playing music in the background. But most users running VoiceOver will usually not have any other audio enabled permanently, since it makes it harder to understand what VoiceOver is saying.
Here is an example for usage:
UInt32 otherAudioIsPlaying;
UInt32 propertySize = sizeof(otherAudioIsPlaying);
AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying,&propertySize, &otherAudioIsPlaying);
if(otherAudioIsPlaying) {
// other application is generating sound output (including VoiceOver)
// but might also be any other app (like iPod App)
}

Controlling the Sound of Audio

I am playing the sound in my App and sound still continue play even when App enter into background i want to control the Volume of that audio when it enter into background . Like in this APP example.I want audio volume remain maximum even user try to turn off the volume. I am unable to splve it can any one out there help me out.
if you are using AVAudioPlayer the just use AVAudioPlayer instance say player like this:
player.volume=1; //for maximum volume
This is AVAudioPlayer's volume, and in reply to your question that even if user minimizes volume of Iphone it should remain in full, then you should know that according to apple policies, there are things which have control for user only, this is what they call user privilege, your app can not control iphone volume,
and for controlling player volume (you don't need any effort if you talk about iphone volume) , i am little doubtful how you want to do this, i mean you must have some button or horizontal slider to achieve this, anyhow proceed with your logic with the delegate method
- (void)applicationDidEnterBackground:(UIApplication *)application
in your appdelegate class

Mute is overridden when using the mic for recording

My initial issue was as described in the title there. When I was recording from the mic, sound effects were playing at the same time even if the device was in mute mode (i.e., had the mute button physically switched on).
I since found this thread, which totally worked. the mute button now works correctly, and no sounds are played in the app while the mic is recording...
Unfortunately, the mic has now stopped recording!
It seems like I can have one or the other, but not both. Can anyone confirm if I can have the device on mute and record from the mic at the same time? And if so, how?
Thank you so much in advance,
Stew
UPDATE : I'm fairly certain that this isn't possible, and I'm basing this on the fact that the mute switch also doesn't work in Garage Band (Another app which requires simultanious playback and recording).
To try it yourself, simply load up Garage Band, play some music, and then note that the mute switch doesn't work.
I'm leaving this open in case anyone does come up with a solution, but I won't be offended if it's closed or deleted.

How to disable iOS System Sounds

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
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];
}
Using MediaPlayer framework, we can set the level of SYSTEM sound
[[MPMusicPlayerController applicationMusicPlayer] setVolume:0];
Best you can do is encourage your users to go into airplane mode.

AudioServices (Easy), AVAudioPlayer (Medium), OpenAL (Hard & Overkill?)

I need to play sounds (~5 seconds each) throughout my iphone application. When they're triggered, they need to play immediately.
For the moment I'm using AudioServices and (as you probably know) the first time you play a sound it lags, then every time there after it's perfect. Is there some code available that's clever enough to preload an AudioServices sound (by playing it silently maybe?). I've read adjusting the system volume programmatically will get your app rejected, so that's not an option. Seems AudioServices isn't made for volume correction from what I can see.
I've looked into OpenAL and while feasible seems a little over kill. AVAudioPlayer seems like a little bit of a better option, I'm using that for background music at present. Extending my music player to handle a 'sound board' might be my last resort.
On the topic of OpenAL, does anyone know of a place with a decent (app store friendly) OpenAL wrapper for the iPhone?
Thanks in advance
Finch could be perfect for you. It’s a tiny wrapper around OpenAL with very low latency and simple API. See also all SO questions tagged ‘Finch’.
If you use an AVAudioPlayer, you can call prepareToPlay when you initialize the object to reduce the delay between calling play and having the audio start.