Audio Tutorial for iOS: Playing Audio Programatically [2014 Edition]

Audrey Tam
Screenshot from BasicSounds sample project

Screenshot from BasicSounds sample project

This article is the third in a three-part Audio Tutorial series covering audio topics of interest to the iPhone developer.

So far in this Audio Tutorial series we’ve talked about the difference between file and data formats and how to convert and record audio on your Mac. Now we’ll get to the fun part – actually playing audio on your phone!

There are many ways to play audio on the iPhone – System Sound Services, AVAudioPlayer, Audio Queue Services, and OpenAL. Without outside support libraries, the two easiest ways by far are System Sound Services and AVAudioPlayer – so let’s talk about when you would (and wouldn’t) want to use those, and how you can use them.

System Sound Services

System Sound Services provides an extremely easy way to play short audio files. This is particularly useful for audio alerts and simple game sounds (such as making a ‘click’ when moving a game piece). All you have to do is the following:

NSString *pewPewPath = [[NSBundle mainBundle] 
    pathForResource:@"pew-pew-lei" ofType:@"caf"];
NSURL *pewPewURL = [NSURL fileURLWithPath:pewPewPath];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &self.pewPewSound);
AudioServicesPlaySystemSound(self.pewPewSound);

It is important to define pewPewSound as an iVar or property, and not as a local variable so that you can dispose of it later in dealloc. It is declared as a SystemSoundID.

If you were to dispose of it immediately after AudioServicesPlaySystemSound(self.pewPewSound), then the sound would never play.

Doesn’t get much easier than that. However there are some strong drawbacks to this method:

  • It only supports audio data formats linear PCM or IMA4.
  • It only supports audio file formats CAF, AIF, or WAV.
  • The sounds must be 30 seconds or less in length
  • The sound plays at once.
  • Only one sound can play at a time
  • And more – see the Multimedia Programming Guide.

AVAudioPlayer

So what if you have an audio file encoded with AAC or MP3 that you want to play as background music? Another easy way to play music is via the AVAudioPlayer class. Since the AVAudioPlayer class is part of AVFoundation, you will need to @import AVFoundation into your project.
For the most part, it again is quite simple:

NSError *error;
self.backgroundMusicPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:backgroundMusicURL error:&error];
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];

There are many advantages of using AVAudioPlayer; it gives you a lot of bang for the buck. You can also play several sounds at once (using a different AVAudioPlayer for each sound), and you can play sounds even when your app is in the background.

However, the drawback of AVAudioPlayer is it can be extremely slow. If you tap a button and try to trigger a sound with AVAudioPlayer, there will be a noticeable small delay. But if that doesn’t matter to you (like for starting up background music), AVAudioPlayer is a fine choice. By the way, prepareToPlay is optional; if you don’t call it, it will be called implicitly when the AVAudioPlayer calls play.

And there are a couple other things to keep in mind:

  1. If you’re playing background music, you should check to see if other audio (like the iPod) is playing first, so you don’t have two layers of music going on at once!
  2. If a phone call arrives and the user chooses “Decline,” by default your AVAudioPlayer will stop. You can start it back up again by registering for the AVAudioPlayerDelegate and resuming music in the audioPlayerEndInterruption:withOptions method.

Sample Code

I put together some sample code showing how to use System Sound Services and AVAudioPlayer that you might want to check out. It also illustrates how to use AVAudioSessions, how to handle interruptions, and how to set audio to play in the background. And in addition to demonstrating those APIs, it has some mighty funky beats and a cool spaceship to boot. Pew-pew!

OpenAL

If you’re writing a game or another app where you want fine grained control of audio with low latency, you probably don’t want to use the above methods. Instead, you might want to use OpenAL, a cross-platform audio library supported by the iPhone.


OpenAL can be a beast with a steep learning curve. Luckily, Alex Restrepo has made a nice Sound Engine library using OpenAL that you can either use in your projects or use as a reference.

Another option is the Cocos2D game library, which includes an extremely easy to use sound engine that makes playing audio a snap. You can learn how to use it the tutorial on How To Make a Simple iPhone Game With Cocos2D 3.0.

Where to go from here?

That’s about all I’m going to cover about audio topics in iPhone programming for now – but keep in mind I’ve barely scratched the surface. If you’re interested in more, I’d recommend reading Apple’s docs, especially the Core Audio Overview and the Audio Session Programming Guide, and possibly digging into OpenAL a bit more. You might also like to look at the tutorial How To Make a Music Visualizer that contains some additional examples of iPhone audio.

I hope this Audio Tutorial series has been useful to other developers who may be new to audio concepts. Feel free to share any additional info you’re aware of regarding audio programming that may be useful to others!

Audrey Tam

Audrey Tam retired at the end of 2012 from a 25-year career as a computer science academic. Her teaching included Pascal, C/C++, Java, Java web services, web app development in php and mysql, user interface design and evaluation, and iOS programming. Before moving to Australia, she worked on Fortran and PL/1 simulation software at IBM's development lab in Silicon Valley. Audrey now teaches short courses in iOS app development to non-programmers, and organizes venues for Melbourne Cocoaheads monthly meetings.

User Comments

30 Comments

[ 1 , 2 ]
  • Hi Ray,
    I have a question
    Can we access iphone's default sounds programatically?
    Please provide sample code.........
    srinivas
  • Hey, if I change some of the stuff, do you mind if I submit it to the app store as a free app?
    theappdude
  • @Ray : I want to play a part of complete audio file. For example 30 milliseconds out of 1 second . how can i achieve that?
    jackal13
  • I know this is quite old but I would like to know if you can use SystemSounds to play (very short - about 15 seconds) sounds that are in a NSArray?

    I am using a UIPickerView and in the didSelectRow

    SystemSoundID soundID;
    NSString *chirp = [chirpSounds objectAtIndex:row];
    NSString *soundFile = [[NSBundle mainBundle] pathForResource:chirp ofType:@"wav"];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef) [NSURL fileURLWithPath:soundFile], &soundID);
    AudioServicesPlaySystemSound(soundID);


    But it crashes at the AudioServicesCreateSystemSoundID line, is there a better way to do this or should I be using AVAudioPlayer?

    Thanks
    Mercdes1a1 :?
    Mercdes1a1
  • hi
    I need some sound effects to use in an app... I can find a lot of site offering free sound effects but mostly they are of poor quality.
    Someone could please suggest to me from where buy good sound effects?

    thanks in advance!
    ste72
  • Hello Ray,
    Thanks for your great website! I was just recently made aware of your website by a friend of mine.
    I'm new to iOS programming so, I'm in a major learning mode.

    I'm trying to write a Morse code learning app. I want to create the "dit" and "dah" sounds, which are the basis of all the
    Morse code characters, as simple as possible. I want to know how to create these sounds possibly through system sound services.

    Since the "dah" is 3X longer than a "dit" than all I would have to do is manipulate the length of the "dit" sound or should say duration. Also, I need to create a time interval spacing between the "dit" and "dah", between characters, and between words. How would I generate this timed spacing?
    Thanks for your help, in advance.
    Gary W.
    eLearner
  • bobmoff
  • Hello Ray,

    Is there a way to have an audio file be swapped out programmatically with a ringtone when the user selects a certain action and when they select another action their original ringtone is reset?

    Thanks,

    Dean
    carydean7
  • Hey Guys,

    I had some problems using the method for the System Sound Services because it doesn't seem to be ARC friendly. Here is what I ended up doing:

    // You need to include the file and the AudioToolbox framework
    #import

    // Set up an instance variable like so:
    SystemSoundID sound1;

    NSURL *SoundURL = [[NSBundle mainBundle] URLForResource:@"Sample"
    withExtension:@"wav"];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)SoundURL, &sound1);

    //Here is the code to start playing the sound:
    AudioServicesPlaySystemSound(sound1);

    Thanks for all your help Ray:)
    Cdava
  • oops -- editing crossed-wires!

    System Sound Services code block:
    Using self.pewPewSound here produces the error "Address of property expression requested":
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &self.pewPewSound);

    Using the ivar name directly is ok with Xcode but goes against the Objective C Style Guide:
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &_pewPewSound);

    However, this function call is initializing the SystemSoundID for the audio file, and initializers always access ivars directly.
    Audrey
  • hello frds... i have to record mp3 file in my ios device using xcode, i tried code like given below...but the sound effect is low , the volume is very much low, i dont know why, but i need good quality soung in my client app, so any suggestion, plzzzz
    //---recording functions---//

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:NO];

    // Set the audio file
    NSArray *pathComponents = [NSArray arrayWithObjects:
    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
    @"sound.wav",
    nil];
    NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];

    player = [[AVAudioPlayer alloc]initWithContentsOfURL:outputFileURL error:NULL];

    [player setNumberOfLoops:0];
    //[player prepareToPlay];
    [player setVolume:10];
    //[player play];
    // NSLog(@"URL je: %@", outputFileURL);

    // Setup audio session
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

    // Define the recorder setting
    NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];

    [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
    [recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
    [recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];

    // Initiate and prepare the recorder
    recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
    recorder.delegate = self;
    recorder.meteringEnabled = YES;
    [recorder prepareToRecord];
    //-end --recording function--//

    //--recording mehods--//

    - (IBAction)recordPauseTapped:(id)sender {
    // Stop the audio player before recording
    if (player.playing) {
    [player stop];
    }

    if (!recorder.recording) {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setActive:YES error:nil];

    // Start recording
    [recorder record];
    [BTN_Pause setTitle:@"Pause" forState:UIControlStateNormal];

    } else {

    // Pause recording
    [recorder pause];
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];
    }

    is_audio_file = YES;
    NSLog(@"is_audio_file = %hhd",is_audio_file);
    [BTN_Stop setEnabled:YES];
    [BTN_Play setEnabled:NO];
    }
    - (IBAction)stopTapped:(id)sender {
    [recorder stop];

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setActive:NO error:nil];
    }
    - (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)avrecorder successfully:(BOOL)flag{
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:YES];
    }
    - (IBAction)playTapped:(id)sender {

    //--slider--//



    //--//


    if (!recorder.recording){
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
    [player setDelegate:self];
    [player play];


    }
    }

    - (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Done"
    message: @"Finish playing the recording!"
    delegate: nil
    cancelButtonTitle:@"OK"
    otherButtonTitles:nil];
    [alert show];
    }
    //--end--//
    mehulparmar4ever
  • hello frds... i have to record mp3 file in my ios device using xcode, i tried code like given below...but the sound effect is low , the volume is very much low, i dont know why, but i need good quality soung in my client app, so any suggestion, plzzzz
    //---recording functions---//

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:NO];

    // Set the audio file
    NSArray *pathComponents = [NSArray arrayWithObjects:
    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
    @"sound.wav",
    nil];
    NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];

    player = [[AVAudioPlayer alloc]initWithContentsOfURL:outputFileURL error:NULL];

    [player setNumberOfLoops:0];
    //[player prepareToPlay];
    [player setVolume:10];
    //[player play];
    // NSLog(@"URL je: %@", outputFileURL);

    // Setup audio session
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

    // Define the recorder setting
    NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];

    [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
    [recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
    [recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];

    // Initiate and prepare the recorder
    recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
    recorder.delegate = self;
    recorder.meteringEnabled = YES;
    [recorder prepareToRecord];
    //-end --recording function--//

    //--recording mehods--//

    - (IBAction)recordPauseTapped:(id)sender {
    // Stop the audio player before recording
    if (player.playing) {
    [player stop];
    }

    if (!recorder.recording) {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setActive:YES error:nil];

    // Start recording
    [recorder record];
    [BTN_Pause setTitle:@"Pause" forState:UIControlStateNormal];

    } else {

    // Pause recording
    [recorder pause];
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];
    }

    is_audio_file = YES;
    NSLog(@"is_audio_file = %hhd",is_audio_file);
    [BTN_Stop setEnabled:YES];
    [BTN_Play setEnabled:NO];
    }
    - (IBAction)stopTapped:(id)sender {
    [recorder stop];

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setActive:NO error:nil];
    }
    - (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)avrecorder successfully:(BOOL)flag{
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:YES];
    }
    - (IBAction)playTapped:(id)sender {

    //--slider--//



    //--//


    if (!recorder.recording){
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
    [player setDelegate:self];
    [player play];


    }
    }

    - (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Done"
    message: @"Finish playing the recording!"
    delegate: nil
    cancelButtonTitle:@"OK"
    otherButtonTitles:nil];
    [alert show];
    }
    //--end--//
    mehulparmar4ever
  • I am getting an "The operation couldnít be completed. (OSStatus error 1685348671.)" when i try to initialize the player, although NSLog says the file exists:
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *filePath = [documentsPath stringByAppendingPathComponent:_audioFileName];
    NSLog(@"[fileManager fileExistsAtPath:filePath]: %hhd", [fileManager fileExistsAtPath:filePath]);
    _player = [[AVAudioPlayer alloc] initWithContentsOfURL:_outputFileURL error:&error2];
    if (error2) {
    NSLog(@"error initialising player - %@", [error2 localizedDescription]);
    }
    mrad
  • mehulparmar4ever wrote:hello frds... i have to record mp3 file in my ios device using xcode, i tried code like given below...but the sound effect is low , the volume is very much low, i dont know why, but i need good quality soung in my client app, so any suggestion, plzzzz
    //---recording functions---//

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:NO];

    // Set the audio file
    NSArray *pathComponents = [NSArray arrayWithObjects:
    [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
    @"sound.wav",
    nil];
    NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];

    player = [[AVAudioPlayer alloc]initWithContentsOfURL:outputFileURL error:NULL];

    [player setNumberOfLoops:0];
    //[player prepareToPlay];
    [player setVolume:10];
    //[player play];
    // NSLog(@"URL je: %@", outputFileURL);

    // Setup audio session
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

    // Define the recorder setting
    NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];

    [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
    [recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
    [recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];

    // Initiate and prepare the recorder
    recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
    recorder.delegate = self;
    recorder.meteringEnabled = YES;
    [recorder prepareToRecord];
    //-end --recording function--//

    //--recording mehods--//

    - (IBAction)recordPauseTapped:(id)sender {
    // Stop the audio player before recording
    if (player.playing) {
    [player stop];
    }

    if (!recorder.recording) {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setActive:YES error:nil];

    // Start recording
    [recorder record];
    [BTN_Pause setTitle:@"Pause" forState:UIControlStateNormal];

    } else {

    // Pause recording
    [recorder pause];
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];
    }

    is_audio_file = YES;
    NSLog(@"is_audio_file = %hhd",is_audio_file);
    [BTN_Stop setEnabled:YES];
    [BTN_Play setEnabled:NO];
    }
    - (IBAction)stopTapped:(id)sender {
    [recorder stop];

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setActive:NO error:nil];
    }
    - (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)avrecorder successfully:(BOOL)flag{
    [BTN_Pause setTitle:@"Record" forState:UIControlStateNormal];

    [BTN_Stop setEnabled:NO];
    [BTN_Play setEnabled:YES];
    }
    - (IBAction)playTapped:(id)sender {

    //--slider--//



    //--//


    if (!recorder.recording){
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
    [player setDelegate:self];
    [player play];


    }
    }

    - (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Done"
    message: @"Finish playing the recording!"
    delegate: nil
    cancelButtonTitle:@"OK"
    otherButtonTitles:nil];
    [alert show];
    }
    //--end--//



    Add this where you setup the session:
    NSError *error;
    BOOL success = [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
    if(!success)
    {
    NSLog(@"error doing outputaudioportoverride - %@", [error localizedDescription]);
    }
    mrad
[ 1 , 2 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Gaming!

    Loading ... Loading ...

Last week's winner: Apple TestFlight Tutorial.

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in January: WatchKit.

Sign Up - January

Our Books

Our Team

Tutorial Team

... 60 total!

Update Team

... 12 total!

Editorial Team

  • Matt Galloway
  • John Clem

... 17 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

  • Richard Casey

... 4 total!