App's audio not working through speakers - objective-c

There's a weird bug in my app. I'm using AVAudioPlayer to play sounds (multiple instances of it), the sound works perfectly through headphones, but using the app without headphones produces no sound from the speaker. All of the audio clips are AAC encoded.
I have tried setting the AVAudioSession properties both through the Objective-C API ([AVAudioSession sharedInstance]) and the C API, but none of the the options seem to work.

accepted answer (in ios7) did not work for me, the following code did work. (i do not have enough points to comment, posting this as separate answer)
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
error:nil];

ISSUE on iPhone - when sound was very low - seemed it was coming out the phone ear piece (not
headphone jack) instead of bottom speaker - change to DEFAULT TO SPEAKER
//http://stackoverflow.com/questions/3104562/avaudiorecorder-avaudioplayer-sound-output-on-internal-speaker-how-to-chang
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof (doChangeDefaultRoute),
&doChangeDefaultRoute
);

For those of you using Swift Syntax...
Below worked for me.
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: AVAudioSessionCategoryOptions.DefaultToSpeaker)
}
catch {
print("can't default to speaker ")
}

Related

AVAudioSessionCategoryPlayAndRecord makes AirPlay invisible

I am encountering the following problem: AirPlay becomes not available whenever I set play-and-record category to the audio session in my application:
[[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryPlayAndRecord
error: &setCategoryError];
This call makes the AirPlay disappear and reroutes the audio to the speaker immediately.
The problem can be easily reproduced e.g. on the sample project avTouch from Xcode documentation by replacing AVAudioSessionCategoryPlayback category with AVAudioSessionCategoryPlayAndRecord: in the original example AirPlay picker is visible and allows to change output source, whereas with the AVAudioSessionCategoryPlayAndRecord category the picker disappears.
Is there a proper way to switch to AVAudioSessionCategoryPlayAndRecord category so that the AirPlay is still available?
(A question like this has been already asked, but didn't get any answer.)
What AirPlay device are you trying to use? Does it have a microphone?
If not, iOS won't present it as an option when using the PlayAndRecord category, because that device can't play and record. It would show up when using the Play category though.
Also, if the device you are using is a Bluetooth device, have you set AVAudioSessionCategoryOptionAllowBluetooth to YES?
I think you should add the code below above AVAudioSession. I hope it works.
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError) {
// Handle error
}
Well, AirPlay and the PlayAndRecord category are just incompatible.
That's what I learned from the Apple forums.
Why do you need audio input on the device when audio output happens somewhere else?

NSUserNotification with custom soundName

Did anyone manage to make a NSUserNotification soundName to work with a custom sound?
I tried with aif and caf format 44100KHz 16bit 2 second of duration. The notification is displayed at the proper time, with the right title and text, but the default sound gets played instead of my custom sound.
The sound files are correctly copied in the application bundle.
If I try this the sounds work ok:
NSSound* sound = [NSSound soundNamed:#"morse.aif"];
[sound play];
But when I use the same sound in my notification, the default notification sound gets played:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSUserNotification* notification = [[NSUserNotification alloc]init];
notification.title = #"Titolo";
notification.deliveryDate = [NSDate dateWithTimeIntervalSinceNow:10];
notification.soundName = #"morse.aif";
[[NSUserNotificationCenter defaultUserNotificationCenter]scheduleNotification:notification];
}
I tried with and without extension, but with no success.
notification.soundName = #"morse.aif";
notification.soundName = #"morse2.caf";
notification.soundName = #"morse";
none of these work.
My application is not signed and not sandboxed, but I don't think that's necessary for user notifications, and apart from the sound problem the notifications work great.
It seems to me like this issue is case-sensitivity. Using notification.soundName = #"Morse"; works perfectly for me. As you can see in the NSSound documentation for soundNamed The search folders for sounds are, in order:
~/Library/Sounds
/Library/Sounds
/Network/Library/Sounds
/System/Library/Sounds
If you look in the last one, which is probably where you're trying to pull from since they're the sounds in System Preferences, you can see their names
So keep the case of the file, and omit the extension and it should work as expected.
If you have multiple versions of your App binary notification center may be searching the wrong binary for your sound files.
If you make sure to delete any old copies of the binary it should fix the issue.
From the Apple Dev Forums: https://devforums.apple.com/message/708511
This can happen if you have multiple version of your app binary floating around. NotificationCenter only fines one of them. If it is the one without the sound then it will not work.

Sound does only work on Device but not in Simulator

I am playing some short sounds on my iPad like so: Play a short sound in iOS
I am using a caf file which I can successfully play from the Finder. Now I went through quite a bit of a hassle trying to achieve the playback of the sound and I am curious what might be the problems which I don't seem to understand:
Option 1: When I create the SystemSoundID and then play it right away I don't hear anything on the device and the simulator.
Option 2: When I create an instance variable for the SystemSoundID and initialize it in viewDidLoad I manage to play sound but only on the iPad, not the Simulator.
Option 3: Instead of using SystemSoundID I can also use AVAudioPlayer to playback a .wav file which then works on both the iPad and the Simulator but here I need to create the AVAudioPlayer in viewDidLoad otherwise I won't get any sound if I do everything in one go.
The best option currently seems to be Option 3 because it works on both the Simulator and the iPad, but because I need to pre-initialize the Player I would need an AVAudioPlayer instance for every different sound that I want to play, which does not seem to be very memory-wise...
Is there something that I am missing and is it possible to play sounds on both platforms using the AudioToolbox framework (Option 1 & Option 2)
I wrote a library to simplify all this. It wraps AVAudioPlayer, and works fine on both the device and simulator.
https://github.com/nicklockwood/SoundManager
The code is fairly straightforward, although I do some semi-clever stuff to initialise the audio player. If you don't want to use the library you can just copy the code.
A word of warning though - the simulator throws some odd exceptions internally whenever you use AVAudioPlayer. They don't affect the app at all, but if you have enabled break-on-exceptions in Xcode then the app will drop into the debugger a few times during startup and you'll have to manually resume, which may freak you out if you're not expecting it.

Stop iTunes/Spotify Music when returning to App

Im having some trouble finding information on this. I would like to know how to stop the itunes/spotify or any other music players music upon returning to my application. They currently both play the same time.
Can anyone point me in the right direction?
Thanks
You can try this in your application: didFinishLaunchingWithOptions: method:
if ([[MPMusicPlayerController iPodMusicPlayer] playbackState] == MPMusicPlaybackStatePlaying) {
[[MPMusicPlayerController iPodMusicPlayer] stop];
}
Don't forget: You need to add MediaPlayer.framework to your target and in your AppDelegate.m import MediaPlayer/MediaPlayer.h.
Also take a look at the documentation.
EDIT
I found a better solution than mine in Apples Audio Session Programming Guide: Checking if Other Audio is Playing During App Launch
EDIT 2
Code sample …

AVQueuePlayer playing items simultaneously rather than in sequence

I am trying to put together a simple app to play a pre-roll video followed by some content video.
Currently, I'm trying to use the AVQueuePlayer class to get this done. Unfortunately, it seems to want to play the videos properly in sequence.
For example, the pre-roll plays by itself for a few seconds, then (prior to the pre-roll being complete) it starts to try and play the content video. For a few seconds, the player seems to be at war with itself and switches back and forth between the two videos (neither playing very well at all). Finally, when the pre-roll is finished, the content video then plays the rest of the way normally.
I've looked through the documentation for the AVQueuePlayer and I don't see anything obvious that I'm missing.
My code is pretty basic:
AVPlayerItem *preRollItem = [AVPlayerItem playerItemWithURL: preRollUrl];
AVPlayerItem *contentItem = [AVPlayerItem playerItemWithURL: contentUrl];
self.player = [AVQueuePlayer queuePlayerWithItems:[NSArray arrayWithObjects:preRollItem, contentItem, nil]];
[self.player play];
What is the trick to getting the videos to play in sequence.
Make sure you are actually testing on the device. From my experience the iOS5 simulator has big problems with AVQueuePlayer and does bizarre things.
I found the iOS4.3 simulator is doing a much better job when it comes to testing AVFoundation.