Play a short sound in iOS
Asked Answered
K

13

62

I guess I could use AVAudioPlayer to play a sound, however, what I need is to just play a short sound and I don't need any loops or fine-grained control over the volume etc.

Is there an easy way to do this?

Kuchen answered 26/4, 2012 at 7:52 Comment(2)
You can Play sound as this answer https://mcmap.net/q/323317/-play-audio-ios-objective-cHainaut
"I guess I could use AVAudioPlayer..." Why didn't you? Why wouldn't anyone? It's much easier to play a sound using AVAudioPlayer.Beauvoir
C
88

Every single one of the other answers leaks memory (unless ARC is enabled for one of the answers)... oddly, the answer originally marked as correct has a call to retainCount for no apparent reason.

If you alloc/init something, it needs to be released (unless you are using ARC).

If you call AudioServicesCreateSystemSoundID() you have to dispose of the resulting sound.

See the Audio UI Sounds example.

Basically:

@interface MyClass:UI*ViewController // fixed
{
     SystemSoundID mySound;
}
@implementation MyClass
- (void) viewDidLoad {
    [super viewDidLoad];
    AudioServicesCreateSystemSoundID(.... URL ...., &mySound);
}

- (void) playMySoundLikeRightNowReally {
    AudioServicesPlaySystemSound(mySound);
}

- (void) dealloc {
   AudioServicesDisposeSystemSoundID(mySound);
   [super dealloc]; // only in manual retain/release, delete for ARC
}
@end

For completeness:
add AudioToolbox.framework
#import <AudioToolbox/AudioToolbox.h>

Clapp answered 26/4, 2012 at 15:53 Comment(8)
I am using ARC but since others might not your answer seems to be justified.Kuchen
Cool -- good - ARC is the right way. :) I always make a point of noting the use of ARC because I have seen too many people screw up memory management in too many simple ways.Clapp
I do it like that and I have converted my file to an aif file but I don't hear any sound in the simulator...Kuchen
When using caf files, could it be that this does not work in the Simulator? Are there better file types to use?Kuchen
When using ARC, make sure to use __bridge: AudioServicesCreateSystemSoundID((__bridge CFURLRef)mySoundNSURL, &_mySound);Gusty
Also do not call super in dealloc if you are using ARC.Uvulitis
Since stickling is in vogue here: Your example calls [super viewDidLoad] on a subclass of NSObject. ;)Microvolt
Beware apple might reject the app because the sound will play even if the device is muted.Ulphiah
I
43

For short sound clips (less than 30 secs), there's a SystemSounds library which is really nice.

Pros: You don't need to manage volume settings separately. The sound is played in a separate thread and loading and playing of audio clip is v fast. In short, you treat this clip as another system sound.

Cons: You can't provide a separate audio control setting. It's tied to the settings of the system sounds. You can't play more than 30 seconds. You probably can't apply any sound filters to enhance audio effect.

There are certainly more pros and cons, but these are some I could think of, off the top of my head.

use this import: <AudioToolbox/AudioToolbox.h> Add the AudioToolbox Framework then call the below method like [self playSound], wherever you want to play the clip.

-(void) playSound {
    NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"changeTrack" ofType:@"aif"];
    SystemSoundID soundID;
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
    AudioServicesPlaySystemSound (soundID);
    [soundPath release];
}
Inebriate answered 26/4, 2012 at 8:9 Comment(4)
That code leaks the sound and the call to retainCount (and the commented [soundPath release]) indicates a bit of a misconception of the memory management....Clapp
@Anshu: I do it like that and I have converted my file to an aif file but I don't hear any sound in the simulator...Kuchen
@Kuchen Check your System Preferences under Sound, and make sure you have checked the "Play user interface sound effects" checkboxLely
use AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID); for release memoryFiredamp
H
24

Swift

The other answers here use Objective-C so I am providing a Swift version here. Swift uses Automatic Reference Counting (ARC), so I am not aware of any memory leak issues with this answer (as warned about in the accepted answer).

Using AudioToolbox

You can use the AudioToolbox framework to play short sounds when you do not need much control over how they are played.

Here is how you would set it up:

import UIKit
import AudioToolbox

class PlaySoundViewController: UIViewController {

    var soundURL: NSURL?
    var soundID: SystemSoundID = 0
    
    @IBAction func playSoundButtonTapped(sender: AnyObject) {
        
        let filePath = NSBundle.mainBundle().pathForResource("yourAudioFileName", ofType: "mp3")
        soundURL = NSURL(fileURLWithPath: filePath!)
        if let url = soundURL {
            AudioServicesCreateSystemSoundID(url, &soundID)
            AudioServicesPlaySystemSound(soundID)
        }
    }
}

Notes:

  • This example is adapted from How to play a short sound clip with AudioToolbox in Swift.
  • Remember to add yourAudioFileName.mp3 (or .wav, etc) to your project.
  • Remember to import AudioToolbox
  • This answer puts the code in an IBAction button tap, but it could just as easily be put in another function, of course.

Using AVAudioPlayer

By importing the AVFoundation framework, you can use AVAudioPlayer. It works for both short audio clips and long songs. You also have more control over the playback than you did with the AudioToolbox method.

Here is how you would set it up:

import UIKit
import AVFoundation

class PlaySoundViewController: UIViewController {
    
    var mySound: AVAudioPlayer?
    
    // a button that plays a sound
    @IBAction func playSoundButtonTapped(sender: AnyObject) {
        mySound?.play() // ignored if nil
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // initialize the sound
        if let sound = self.setupAudioPlayerWithFile("yourAudioFileName", type: "mp3") {
            self.mySound = sound
        }
    }
    
    func setupAudioPlayerWithFile(file: NSString, type: NSString) -> AVAudioPlayer? {
        
        let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
        let url = NSURL.fileURLWithPath(path!)
        var audioPlayer: AVAudioPlayer?
        do {
            try audioPlayer = AVAudioPlayer(contentsOfURL: url)
        } catch {
            print("Player not available")
        }
        
        return audioPlayer
    }
}

Notes:

Haleyhalf answered 1/10, 2015 at 4:24 Comment(2)
One problem with AudioServicesPlaySystemSound is that if the user has the mute button on then the sounds will not be played. That makes sense in some respects, but depending on your application the user may still expect to hear a sound.Haleyhalf
Perfect for what I needed to handle. Great explanation about the difference of using AudioToolbox or AVAudioPlayer. I choose the AudioToolbox in my case (be able to play music from an audio steaming service while playing my own sound fx on button tapped in my app)Lotuseater
P
17

Recently, I used this code to play short mp3 audio which worked fine:-

Declare this below the @implementation

NSString *path;

NSURL *url;

//where you are about to add sound 

path =[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"quotes_%d",soundTags] ofType:@"mp3"];

    url = [NSURL fileURLWithPath:path];
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
    [player setVolume:1.0];
    [player play];

//just add AVFoundation framework
Poet answered 26/4, 2012 at 12:19 Comment(4)
@bbum:- Yes it is enabled in my case. When ARC is not enabled, retain count of "player" has to be decreased.Poet
[player setVolume:1.0]; should come after creating the player.Truly
"I guess I could use AVAudioPlayer to play a sound, however, what I need is to just play a short sound and I don't need any loops or fine-grained control over the volume etc." After reading this thing from Question I think this answer should not be here..Cayes
setVolume:1 is not necessary. 1 is the default for a new playerBoley
U
9

I used this code to play a short aiff-sound on iOS

#import <AudioToolbox/AudioServices.h> 

SystemSoundID completeSound;
NSURL *audioPath = [[NSBundle mainBundle] URLForResource:@"downloadCompleted" withExtension:@"aiff"];
AudioServicesCreateSystemSoundID((CFURLRef)audioPath, &completeSound);
AudioServicesPlaySystemSound (completeSound);

Hope this helps.

Unshakable answered 26/4, 2012 at 8:6 Comment(3)
I converted my file from m4a to aif using iTunes and now I don't hear any sound in the simulator, can you tell me what approach you have used for the conversion?Kuchen
What do we need to import in the header file?Algonquian
Although your aif may be copied to your resources, make sure it's also listed in your Copy Bundle Resources within Build Sources > TargetBrom
R
8

SIMPLE CLEAN SWIFT 3 VERSION

I like more control over my sounds so I'm using AVFoundation.

import AVFoundation

class TodayViewController: UIViewController {

  var clink: AVAudioPlayer?
  var shatter: AVAudioPlayer?

  override func viewDidLoad() {
    super.viewDidLoad()

    // initialize the sound
    shatter = setupAudioPlayer(withFile: "shatter", type: "wav")
    clink = setupAudioPlayer(withFile: "clink", type: "wav")
  }

  func setupAudioPlayer(withFile file: String, type: String) -> AVAudioPlayer? {
    let path = Bundle.main.path(forResource: file, ofType: type)
    let url = NSURL.fileURL(withPath: path!)
    return try? AVAudioPlayer(contentsOf: url)
  }

  func onClick() {
    clink?.play()
  }
}

Make sure you sound file is added to your project and you import AVFoundation.

Ritual answered 9/5, 2017 at 8:58 Comment(0)
A
6

My answer is Bill's answer, but I use it without the class init or dealloc, loading the sound only when needed and releasing the sound directly after it's played:

- (void)playSound:(NSURL *)url
    SystemSoundID ssID = 0;
    AudioServicesCreateSystemSoundID((CFURLRef)url, &ssID);
    AudioServicesAddSystemSoundCompletion(ssID, NULL, NULL, (AudioServicesSystemSoundCompletionProc)MyAudioServicesSystemSoundCompletionProc, NULL);
    AudioServicesPlaySystemSound(ssID);
}

void MyAudioServicesSystemSoundCompletionProc (SystemSoundID  ssID, void *clientData) {
    AudioServicesDisposeSystemSoundID(ssID);
}
Alboran answered 28/2, 2014 at 16:16 Comment(0)
P
4

Using Swift 4

import AudioToolbox

func playSoundEasy(note : String) {
    var soundURL: NSURL?
    var soundID: SystemSoundID = 0

    let filePath = Bundle.main.path(forResource: note, ofType: "wav")
    soundURL = NSURL(fileURLWithPath: filePath!)
    if let url = soundURL {
        AudioServicesCreateSystemSoundID(url, &soundID)
        AudioServicesPlaySystemSound(soundID)
    }
}
Peonage answered 9/1, 2018 at 16:25 Comment(0)
N
2

Heres a quick clean method you can copy in and use in your app:

-(BOOL) playSoundFXnamed: (NSString*) vSFXName Loop: (BOOL) vLoop
{
    NSError *error;

    NSBundle* bundle = [NSBundle mainBundle];

    NSString* bundleDirectory = (NSString*)[bundle bundlePath];

    NSURL *url = [NSURL fileURLWithPath:[bundleDirectory stringByAppendingPathComponent:vSFXName]];

    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];

    if(vLoop)
        audioPlayer.numberOfLoops = -1;
    else
        audioPlayer.numberOfLoops = 0;

    BOOL success = YES;

    if (audioPlayer == nil)
    {
        success = NO;
    }
    else
    {
        success = [audioPlayer play];
    }
    return success;
}

Then to use just:

[self playSoundFXnamed:@"someAudio.mp3" Loop: NO];

If you're gonna loop then you need to take your AVAudioPlayer *audioPlayer out into your class to be able to stop the sound.. Which you dont if you just want a short sound.

Use ARC... and I never did do anything with the NSError, so use it if ya like...

Nedranedrah answered 17/1, 2013 at 0:16 Comment(0)
D
1

A lot of answers are confusing, and some are using the AudioToolbox framework, different from the AVAudioFoundation framework... here's what I did. In the .h file, I put this code in:

@property (nonatomic, retain) AVAudioPlayer *player;

This code declares an audio player named "player." In the .m file, under your @implementation declaration, add @synthesize player. This synthesizes that player property.

In whatever function you want, tie your sound in to the player by adding this line of code, where yourSound is the name of the sound file, and aif is your file extension:

player = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"yourSound" withExtension:@"aif"] error:nil]

I know the Apple Documentation says to declare a string and a NSURL, but if you combine it into one line, then you won't have to dispose of it afterwards. Also, since this is a property in your ViewController.m file, then you won't have to keep setting that player object to tie in with your sound.

Other answers also included using a SystemSoundID, but that also imposes restrictions like, "the file can't be over 30 seconds long," "it has to be in a specific format," and the works. With that, it can play several sounds at a time (in case you're developing a soundboard), and it's easier to create the sounds.

To actually play your sound, insert this line (and yes, it's really this easy):

[player play]

If you use ARC, you can't manually dispose of the player, as the system will do it for you. If you're new to developing and you're using the latest version of Xcode, then you have ARC enabled. If, for some strange reason, you don't, then the code for disposing of the resources being used by player is:

[player release]

Danuloff answered 11/1, 2015 at 1:35 Comment(0)
K
0

From Sound does only work on Device but not in Simulator

Nick created a library which can be used for playing sounds in iOS and Mac Apps.

See nicklockwood/SoundManager

Kuchen answered 9/9, 2013 at 12:29 Comment(0)
M
0

Please refer to Simple iOS audio playback

- (void)playSound
{
    SystemSoundID soundId;

//    NSURL *soundURL = [[NSBundle mainBundle] URLForResource:@"sample"
//                                              withExtension:@"caf"];
//    AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundURL, &soundId);

    NSString *path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"mp3"];
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundId);
    AudioServicesAddSystemSoundCompletion(soundId,
                                      NULL,
                                      NULL,
                                      systemAudioCallback,
                                      NULL);
    AudioServicesPlaySystemSound(soundId);
    //AudioServicesPlayAlertSound(soundId);
}

- (void) systemAudioCallback(SystemSoundID soundId, void *clientData)
{
    AudioServicesRemoveSystemSoundCompletion(soundId);
    AudioServicesDisposeSystemSoundID(soundId);
}
Mateusz answered 14/7, 2015 at 6:35 Comment(0)
H
-1

Check out systemsound to play short audio file

include audiotoolbox framework

and create

systemsoundid object

NSString *soundPath =  [[NSBundle mainBundle] pathForResource:file ofType:@"aiff"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
Headstall answered 26/4, 2012 at 8:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.