facebook youtube pinterest twitter reddit whatsapp instagram

Playing Audio in your iOS App

Due to the fact that the iPhone and iTouch are all about playing music, one would think that playing audio in iOS would be an easy task. Well, I hate to break it to you, but playing sound effects in iOS is not as easy as it might seem. There are several ways to play audio in iOS, and in this tutorial, I will show you 2 of them.

System Sound Services

This is the easiest way to play sounds on iOS devices, but it has some limitations. System Sound Services provide a C API for playing short sounds in iOS. You can only play one sound at a time, the maximum duration of the sound is 30 seconds, and the API does not provide level, positioning, timing control, or looping.

Furthermore, the sound is played in a different thread and you can’t know exactly when it will be played. It can only be used to play .aif, .wav and .caf files.

You need to add the AudioToolbox framework to your project to use System Sound Services and import it wherever you want to use it.

#import <AudioToolbox/AudioToolbox.h>

Now you need a SystemSoundID variable, and get the URL of the file you wish to play. Once you have done these two things, you need to call AudioServicesCreateSystemSoundID passing those two arguments. This function is written in C, and you need to send the memory address of the SystemSoundID variable you defined, so use the ampersand character. This way, the function does not need to return the value, since it is stored directly in the SSID variable.

Finally, play the sound by calling AudioServicesPlaySystemSound:

NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"file" withExtension:@"wav"];

SystemSoundID sound = 0;
AudioServicesCreateSystemSoundID((CFURLRef) fileURL,&sound);

AudioServicesPlaySystemSound(sound);

Playing sounds with System Sound Services is quite easy, but as I said, it has some limitations. If you only need it to play short sounds, then use this one.

AV Foundation

This framework provides an Objective-C API to work with audiovisual data. With AVAudioPlayer, you can reproduce any audio file. You can control the volume, the number of loops, play multiple sounds simultaneously… A very useful feature is that you can set a delegate for an AVAudioPlayer to handle interruptions or to update the UI once the sound has finished playing.

In this tutorial we will make a very simple MP3 player. This player will have a UISlider to control the volume, and a button to play the sound or to pause it.

Step 1: Creating the project

First of all, create a new Single-View Application project, and you will need to add two frameworks to your project: AudioToolbox and AVFoundation.

Step 2: Setting up the UI

In the storyboard, you will need to add to the view controller a UISlider and a UIButton. Add also a UILabel above the slider to make it look a little bit better.

Step 3: PlayerViewController header file

You are going to need one instance variable for the AVAudioPlayer in your view controller, and two methods to control when the user presses the button and when he changes the value of the slider. Also, import the frameworks you added in step 1.

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

@interface PlayerViewController : UIViewController 
{
AVAudioPlayer *player;
}

- (IBAction)playFile:(id)sender;
- (IBAction)changeVolume:(id)sender;

@end

This view controller will be the delegate for the AVAudioPlayer, so it needs to adopt the AVAudioPlayerDelegate protocol. You don’t really need to set a delegate in this tutorial, since we will not use it, but I am doing it to show you how to do it. One of the most useful methods is

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Do whatever you need to do
}

since it will be called once the sound has finished playing, so that you can update the UI or play a different sound.

Step 4: Connecting the code to the UI

Again, go to the storyboard to connect the two methods you have just created to the UISlider and the UIButton. To do this, Control-drag the UISlider onto Player View Controller and select changeVolume. Repeat the same operation with the UIButton, but choose playFile instead.

Step 5: Configuring the Audio Session

In the viewDidLoad method, after the call to [super viewDidLoad], the first thing you need to do is to configure the Audio Session. First, set PlayerViewController as its delegate, and set the category to AVAudioSessionCategoryPlayback. You can see a list with all the possible categories here.

Sometimes the sound will come out of the ear speaker, so you also need to add two lines of code to redirect the sound to the loudspeaker.

[[AVAudioSession sharedInstance] setDelegate: self];
[[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error: nil];

UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);

Step 6: Creating the AVAudioPlayer instance

Once the Audio Session is configured, you need to get the URL of the file you wish to play. Then, create the AVAudioPlayer and set its initial attributes. Since the UISlider we created has a default value of 0.5, we will set the player’s volume to 0.5 as well.

The numberOfLoops property controls how many times the file is played. A value of 0 will make the sound play once, and if you set it to a negative value it will loop indefinitely.

NSString *fileName = [NSString stringWithFormat:@"monalisa"];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"mp3"];
NSURL *soundFileURL =  [NSURL fileURLWithPath:soundFilePath];

player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.volume = 0.5;
player.numberOfLoops = 0;
player.delegate = self;

Step 7: Final Touch

The last thing you need to do is to implement the two methods you declared in the header file. Its implementation is very simple and you should have no problem understanding it:

- (IBAction)playFile:(id)sender
{ 
UIButton *button = (UIButton *)sender;

if (([button.titleLabel.text isEqualToString:@"Play"]) {
[button setTitle:@"Pause" forState:UIControlStateNormal];
[player play];
} else if ([button.titleLabel.text isEqualToString:@"Pause"]) {
[button setTitle:@"Play" forState:UIControlStateNormal];
[player pause];
}

}

- (IBAction)changeVolume:(id)sender
{
UISlider *slider = (UISlider *)sender;
[player setVolume:slider.value];
}

IMPORTANT NOTE

The first time I used AVAudioPlayer and tested it with my device instead of the simulator, no sound was emitted by my iPhone. After lots of research, I couldn’t find any answers, until I discovered that the volume of the file being played depends on the volume you have on the Music app of the iPhone. Since I always set its volume to zero when I disconnect my headphones, I couldn’t hear a sound and did not know the reason.

Hence, check that the volume is not set to zero in the Music app before testing your app. If you don’t want to change the volume from the Music app, you can always change the volume programmatically. Add the MediaPlayer framework to your project, and import it in AppDelegate.h:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

@interface AppDelegate : UIResponder 

@property (strong, nonatomic) UIWindow *window;

@end
Then, go to the implementation file and write this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
MPMusicPlayerController *musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setVolume:1.0f];

return YES;
}

Now your app will set the Music app’s volume to 1.0 every time you launch your app!

Conclusion

This tutorial has been quite a long one, but playing sounds in iOS can be really cumbersome, so I wanted to explain everything to the last detail. I hope you enjoyed it, and thank you for reading it!

Related Post(s)

  • Custom Camera App | Part 2: Taking Pictures

    Second part of the Custom Camera App series. Custom Camera App – Part 1: Custom Overlay Custom Camera App – Part 2: Taking Pictures Custom Camera App – Part 3: Assets Library In the first par

  • Blocks and Multithreading in iOS

    When developing for iOS, there are several ways to deal with multithreading. You can create your own threads and do whatever you please, but there are various alternatives that will make your life mu

  • Displaying Images in iOS

    Creating images from code is really easy, and although you can draw them in any UIView, they are almost always displayed using UIImageView, a UIView subclass. In this tutorial, I will show you how to

  • Simple Paint App

    In this tutorial you will learn how to handle touch events and the basics of Quartz 2D. I will show you how to create a simple Paint app to draw with your finger. There are four different functions c

  • Custom Camera App | Part 3: Assets Library

    Third part of the Custom Camera App series. Custom Camera App – Part 1: Custom Overlay Custom Camera App – Part 2: Taking Pictures Custom Camera App – Part 3: Assets Library Welcome to the la

  • Custom Camera App | Part 1: Custom Overlay

    First part of the Custom Camera App series. Custom Camera App – Part 1: Custom Overlay Custom Camera App – Part 2: Taking Pictures Custom Camera App – Part 3: Assets Library In this series, I