I am playing sound effects in my game using the SystemSoundID class, with some odd results. A few of my sounds, including landed1 below, change volume according to the volume buttons, but others, like deathsound always play at full volume. Below is all code related to the two sounds.
SystemSoundID deathsound;
SystemSoundID landed1;
...
NSURL *soundURL;
soundURL = [[NSBundle mainBundle] URLForResource:#"SMPKLanded1" withExtension:#"mp3"];
AudioServicesCreateSystemSoundID ((__bridge CFURLRef) soundURL, &landed1);
soundURL = [[NSBundle mainBundle] URLForResource:#"SMPKDeathSound" withExtension:#"mp3"];
AudioServicesCreateSystemSoundID ((__bridge CFURLRef) soundURL, &deathsound);
...
AudioServicesPlaySystemSound(landed1);
...
AudioServicesPlaySystemSound(deathsound);
Why would the two act so differently, if the code and filetype are essentially the same? It makes no sense!
Well, I finally figured it out, after inordinate amounts of time driving myself crazy. Some of them are being played at the same time as an AVAudioPlayer, which for some reason made them conform to the volume buttons, and some weren't. My obvious next step would be to make a silent AVAudioPlayer, which I have now done, and the program works as I would expect.
As a follow up question, does anybody have any clue why having an AVAudioPlayer affects SystemSoundIDs?
Related
Have already tried that out and failed
I put a .wav file into my app and it was fine. So I tried to put a .wav song file into the app. When runs, there's no sound coming out. ( the song is converted from .mp3 using iTunes)
Any ideas how can I fix this? Thanks in advance
one possible reason the sound file is too large. You have different kinds of audio player in iOS some of them can only play files that are really short (something like 1-3 sec). To fix that you have to choose another player like CoreAudio.
The second possible failure is the simulator. The simulator is not always doing the same, the device do. Try running on real device and check if it's working.
// EDIT: sample code:
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"mySound" ofType:#"mp3"];
NSURL *soundFileURL = [NSURL URLForString:soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:soundFileURL];
[player play];
[player pause];
I can't seem to get the AudioServices sounds to play, either on the device or in the simulator. Here is my code:
NSString *sndPath = [[NSBundle mainBundle] pathForResource:#"click" ofType:#"aiff"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:sndPath], &soundID);
AudioServicesPlaySystemSound(soundID);
AudioServicesDisposeSystemSoundID(soundID);
I have checked my system prefs, and yes I do have "Play user interface sound effects" ticked on... What might I be doing wrong?
Thanks!
EDIT: I'm attempting to create an audio click as the user moves touches across the device, so I need it to rapidly play the same sound. Should I use AVAudioPlayer instead?
Don't dispose the sound until after it finishes playing. You can do something like this:
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, (AudioServicesSystemSoundCompletionProc)AudioServicesDisposeSystemSoundID, NULL);
Slightly icky, since we're assuming that it doesn't use the Pascal calling convention (i.e. AudioServicesDisposeSystemSoundID() can handle the extra NULL argument).
I'm using the following to play an m4a file:
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: fileName];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
It works fine on the simulator but I hear nothing on the device. Sounds files I'm using all stay in the bundle. Here is what filePath looks like from the device:
file://localhost/var/mobile/Applications/418945F3-3711-4B4D-BC65-0D78993C77FB/African%20Adventure.app/Switch%201.m4a
Is there an issue with the file path or any thing different I need to do for the device?
Just as a sidenote - I was having the exact same problem and spent probably close to an hour on converting files to the correct format, etc.. Yet the problem was the "mute" switch on the iPad. So even though the volume was up, and I could hear other sounds on the iPad, because the mute switch was turned on, it wasn't playing system sounds.
To add to the confusion, this app uses text-to-speech and the volume coming from the dictation was perfectly fine, it was only the sounds coming from AudioServicesPlaySystemSound() that weren't being played.
I had trouble with this too. Finally I realised it was because AudioServices can only play audio with the following constratints.
Sound files that you play using this
function must be:
- No longer than 30 seconds in duration
- In linear PCM or IMA4 (IMA/ADPCM) format
- Packaged in a .caf, .aif, or .wav file
From Apple docs: http://developer.apple.com/library/ios/#documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference.html
You might want to use the AVAudioPlayer instead of AudioServices.
The following code will take an audio file (.m4a) and play the audio file 1 time. Don't forget to release "audioPlayer" when you're done with it.
NSString *urlAddress = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"m4a"];
NSURL *url = [NSURL fileURLWithPath:urlAddress];
NSError *error;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
if (audioPlayer == nil)
{
NSLog([error description]);
}
else
{
[audioPlayer play];
}
Hope this example helps you with playing audio on the actual device. It might also be a good idea to increase the device audio when the file is playing.
Note: You will need to add the AVFoundation framework to your project if you have not already done so. As well as import the header file.
#import <AVFoundation/AVFoundation.h>
Update:
From Apple's Core Audio Overview Document
Audio Session Services
Audio Session Services lets you manage audio sessions in your application—coordinating the audio behavior in your application with background applications on an iPhone or iPod touch. Audio Session Services consists of a subset of the functions, data types, and constants declared in the AudioServices.h header file in AudioToolbox.framework.
The AVAudioPlayer Class
The AVAudioPlayer class provides a simple Objective-C interface for playing sounds. If your application does not require stereo positioning or precise synchronization, and if you are not playing audio captured from a network stream, Apple recommends that you use this class for playback. This class is declared in the AVAudioPlayer.h header file in AVFoundation.framework.
Start by error-checking your returns. Is filePath nil? Do either of the AudioServices functions return an error? The most likely cause is case-sensitivity. The iPhone filesystem is case sensitive while the Mac is not. But the first step in debugging is to look at the errors the system is providing.
The simulator uses regular QuickTime for playback, so it's easy to have media assets which work in the sim, but fail on the device due to missing / unsupported codecs. The test is if you can play the file at all on the device, eg through Safari or the iPod app.
SystemSoundID soundID;
NSString *path = [[NSBundle mainBundle] pathForResource:#"static" ofType:#"caf"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesPlaySystemSound(soundID);
I have implemented above code in my application.
It works perfectly, but the problem is I don't know how to stop it.
i.e Sound is of 10 sec.
Before 10 sec. if user taps button, sound should be stopped? How can I do so?
Try AudioServicesDisposeSystemSoundID, it stops sounds immediately. You'll need to recreate the sound if you intend to use it again.
Use the following instruction for disposes of a system sound object and associated resources:
AudioServicesDisposeSystemSoundID(soundID);
I would suggest using the AVFoundation framework. Here is an amazing tutorial on how to play, pause, and stop sound using the AVAudioPlayer.
In my app I have a timer that counts down, and when it stops an image is displayed and a sound is played.
The sound is loaded like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"scream" ofType:#"wav"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
And Played like this on timer end:
AudioServicesPlaySystemSound(soundID);
My problem is that the sound doesn't get played on time. Even though the sound instance is called before the image, the image appears before the sound. This only occurs the first time the sound is played. The sound is loaded in the viewDidLoad method.
Is there a better way to do it, or what am I doing wrong?
Thanks...
Maybe the sound is delayed while the speaker is powered up (for the first sound). If so, maybe you can work around it by playing a different, unnoticeable sound earlier so that the speaker is ready to go when you request the "real" sound.