0

Whenever i play an audio file like below, it is taking few seconds to start playing the audio. I have seen from some forums and understand that, AVAudioPlayer will take few seconds to start playing if we allocate the object there itself. I am thinking to allocate this object much earlier (may be Appdelegate itself), before when i want to play, so that when i want to play it, it will play immediately.

NSURL *audioPathURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:audioName ofType:@"wav"]];

audioP = [[AVAudioPlayer alloc]initWithContentsOfURL:audioPathURL error:NULL];
[appDelegate.audioP play];

but, i am passing audio url dynamically at run time, so i would like to know how can i allocate the object earlier and then be able to pass dynamic audio url path later?

Please note, my question is different from this question Slow start for AVAudioPlayer the first time a sound is played In the existing question, they are telling about one audio file and play it when required. But, i am having many different audio file and url path is generated randomly and at run time to play, so i do not know what the actual url path to set and play. So, the answer mentioned here->Slow start for AVAudioPlayer the first time a sound is played won't help for my question. I can't use prepareToPlay, because audio path url is set at run time and not just one audio is being used for all the times to play, there will more than 20 audio file randomly chosen and set to play one at a time. So, i need the right answer for it, it is not a duplicate question.

Thank you!

Community
  • 1
  • 1
Getsy
  • 4,887
  • 16
  • 78
  • 139
  • See this : http://stackoverflow.com/questions/9710679/avaudioplayer-changing-current-url – Baby Groot Aug 02 '13 at 11:50
  • If you know you're about to play something you can use prepareToPlay: to minimize the lag. This will preload the buffers and grab the sound hardware. – Krumelur Aug 02 '13 at 11:53
  • Hi, How would i use prepareToPlay for my case(audio url path will be passed only at the run time) ? – Getsy Aug 02 '13 at 11:57
  • That's why I said that it'll help you only if you know (slightly) in advance that your're going to play something. But you should really read into the thread linked by @HinataHyuga – Krumelur Aug 02 '13 at 12:04

2 Answers2

0

For a single file here the solution:

in your file.h

#import <AVFoundation/AVFoundation.h>

@interface AudioPlayer : UIViewController <AVAudioPlayerDelegate> {


}

To use with button add - (IBAction)Sound:(id)sender; in your file.h

Now in your file.m

//this is a action but you can use inside a void to start auto

@implementation AudioPlayer {

    SystemSoundID soundID;
}

- (IBAction)Sound:(id)sender {

    AudioServicesDisposeSystemSoundID(soundID);
    CFBundleRef mainBundle = CFBundleGetMainBundle();
    CFURLRef soundFileURLRef;

//you can use here extension .mp3 / .wav / .aif / .ogg / .caf / and more

    soundFileURLRef =  CFBundleCopyResourceURL(mainBundle, (CFStringRef) @"sound" ,CFSTR ("mp3") , NULL);
    AudioServicesCreateSystemSoundID(soundFileURLRef, &soundID);
    AudioServicesPlaySystemSound(soundID);

}

If you want use your code to play audio from URL you can use this:

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

@interface AudioPlayer : UIViewController <AVAudioPlayerDelegate> {

AVPlayer *mySound;

}

@property (strong, nonatomic) AVPlayer *mySound;
@end

And file.m

- (IBAction)playPause:(id)sender {

 if (mySound.rate == 0){

    NSURL *url = [NSURL URLWithString:@"http://link.mp3"];
    mySound = [[AVPlayer alloc] initWithURL:url];
    [mySound setAllowsExternalPlayback:YES];
    [mySound setUsesExternalPlaybackWhileExternalScreenIsActive: YES];
    [mySound play];

} else {

[mySound pause];

}

}

Hope this can help you!

BlackSheep
  • 1,087
  • 12
  • 29
0

One thing you can do to reduce the latency of the first load+play is to "spin up" the underlying audio system before you need it by loading and playing a dummy file. For example, in application:didFinishLaunchingWithOptions: add some code like this:

// this won't effect the problem you're seeing, but it's good practice to explicitly
// set your app's audio session category
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
NSURL *audioURL = [[NSBundle mainBundle] URLForResource:@"dummy.wav" withExtension:nil];
AVAudioPlayer *dplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
// we don't want to hear it (alternatively, the audiofile you use for this purpose can be silence.)
dplayer.volume = 0.f;
[dplayer prepareToPlay];
[dplayer play];
[dplayer stop];

Once this code completes, subsequent instantiations and playback of AVAudioPlayer instances should have pretty low latency (certainly well under 1 second)

Art Gillespie
  • 8,747
  • 1
  • 37
  • 34
  • Hi, Thank you for your suggestion. But, my question is how can i set different audio file path at run time, since we need to use again '[[AVAudioPlayer alloc] initWithContentsOfURL' part at run time, which is nothing but we are creating fresh object again, which will not cause the delay? – Getsy Aug 05 '13 at 05:14
  • I tried this solution, but i have observed the same delay issue. – Getsy Aug 05 '13 at 19:03
  • Subsequent instantiations after the initial one play *much* faster in my tests here -- I can play drum samples with acceptable latency on an iPhone 5. I suspect your problem is elsewhere (e.g., are the audio files trimmed correctly?) But you can also look at `AVPlayer` instead of `AVAudioPlayer` -- [`replaceCurrentItemWithPlayerItem:`](http://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVPlayer_Class/Reference/Reference.html#//apple_ref/occ/instm/AVPlayer/replaceCurrentItemWithPlayerItem:) lets you change items without re-instantiating. – Art Gillespie Aug 05 '13 at 19:08