Streaming with an AVAudioplayer - iphone

In order to load a sound file, I have the following code in my application :
- (id) init:(NSString*)a_filename ext:(NSString*)a_ext
{
...
NSString *t_soundFilePath = [CFileLoader getPathForResource:filename WithExtension:ext];
NSURL *t_fileURL = [[[NSURL alloc] initFileURLWithPath: t_soundFilePath] autorelease];
player = [[AVAudioPlayer alloc] initWithContentsOfURL: t_fileURL error: nil];
[player prepareToPlay];
...
}
All the sounds that I load are in my bundle, so I would like to know if the method "initwithcontentsofurl" stream the sound file or if all the file is cached.
I have a lot of sprites in my app so I want to minimize memory space used for sounds.
thx for your help

I used AVPlayer (not AVAudioPlayer) to stream background audio.

Sounds that are played using the AVAudioPlayer are streamed real time from storage. The drawback being that you can occasionally notice a small lag when it is due to start up. If you use OpenAL the sounds are loaded entirely into memory.
There's a good discussion of this sort of thing in the ObjectAL documentation - a library that is meant to simplify the playing of sounds and effects on the iPhone.

If you want to stream audio in your app you can use the following player instead of using AVAudioPlayer
https://github.com/mattgallagher/AudioStreamer
For this player you don't need to put sound files in your bundle, you can put them at server and use url to stream audio.
Hope, this wil help you.

" The AVAudioPlayer class does not provide support for streaming audio
based on HTTP URL's. The URL used with initWithContentsOfURL: must be
a File URL (file://). That is, a local path".
https://developer.apple.com/library/ios/qa/qa1634/_index.html
But you can work around - for example write asynchronously to local file, and init AVAudioPlayer with this file URL, it will work.

Related

Play remote mp3 using iOS

I have a remote mp3 (small file, just a few seconds) which I have the URL.
I need to play it on an App that uses iOS 4.
The URL is not exactly a .mp3 file, but it is a dynamic .php url that requests the .mp3 file. If I put that php route in the browser it downloads the mp3 file.
I am trying to use this project (https://github.com/mattgallagher/AudioStreamer) but it isn't working. The audio starts but it only plays a part of it.
How can I do it?
If it's truly just a small (and static, non-streaming) mp3 file, why not consider doing something like:
NSError * error = nil;
AVAudioPlayer * avPlayerObject =
[[AVAudioPlayer alloc] initWithContentsOfURL: yourRemoteURL error:&error];
if(avPlayerObject)
{
[avPlayerObject play];
}
Check out Apple's AVAudioPlayer class (documentation linked for you).

During http live streaming audio continues but video cuts out after 30 seconds

I have edited my videos in final cut pro and used their export to http live streaming, which includes an audio, cell low and hi video, wifi low and hi, .m3u8 and index files. I have put all the files onto my web server and am using this to call the videos
-(IBAction)introVideo:(id)sender
{
NSLog(#"intro button pressed");
NSString *url = #"http://www.andalee.com/iPhoneVideos/intro/Intro.m3u8";
MPMoviePlayerViewController* moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:url]];
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
}
(Side note: how should this be released?)
Here is the Index.m3u8
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=225416,CODECS="mp4a.40.2, avc1.42e015"
Intro%20-%20Cellular%20Low.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=480386,CODECS="mp4a.40.2, avc1.42e015"
Intro%20-%20Cellular%20High.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=751434,CODECS="mp4a.40.2, avc1.42e01e"
Intro%20-%20Wi-Fi%20Low.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1250210,CODECS="mp4a.40.2, avc1.4d401e"
Intro%20-%20Wi-Fi%20High.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2545049,CODECS="mp4a.40.2, avc1.4d401e"
Intro%20-%20Broadband%20Low.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5056100,CODECS="mp4a.40.2, avc1.4d401f"
Intro%20-%20Broadband%20High.segments/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=33290,CODECS="mp4a.40.2"
Intro%20-%20Audio%20for%20HTTP%20Live%20Streaming.segments/prog_index.m3u8
When I test my app I initially get video and sound, but after 30 seconds I lose video while the audio continues to play. Any ideas what would be causing this?
This could simply be caused by a low bandwidth condition, which will trigger a bitrate change (in this case to the audio only version). If you try it in the emulator with a local server it might work correctly.
Most likely the file which is used next after the intro has wrong codec or the path is not right. Make sure all of the paths in Intro.m3u8 are correct and reachable from outside.

How do you implement seeking using the AudioStreamer sample application as a base?

I need to play some audio streaming contents on iPhone, but there are some options and problems I can't solve:
1. http://cocoawithlove.com/2009/06/revisiting-old-post-streaming-and.html
It is a library provided by Matt Gallagher, but I saw the Limited scope, and I would play
a single song, not a radio station.
2. Suggestion from zonble
NSURL *URL = [NSURL URLWithString:#"http://zonble.net/MIDI/orz.mp3"];
NSData *data = [NSData dataWithContentsOfURL:URL];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:nil];
But I need streaming for each "single song".
3. Using MPMoviePlayerController to wrapper.
Since the Class update new method, and
#interface MyAudioStreamer : UIViewController {
MPMoviePlayerController *mp ;
}
instead of [self addSubview:mp.view] I use my own xib file to implement play and
stop methods, but in this case, I have no idea to implement seekForward or seekBackward.
Is there any good idea to do AudioStreamer?
==== Update ====
after google 'AVPlayer' ,i used 3. Using MPMoviePlayerController to wrapper. to implement a auidoStreamer-like player ,there is something to share :
1.'playbackDidFinished' state
there're 2 conditions : a song did finished and play next song or a song interrupt by user press stop or exception, i used enum to filter my state.
2 multi-task playing your song in background
reference from https:// devforums.apple.com/message/264397
and if iOS SDK update, the solution might be changed because method would be diplicated. so i suggest to read library provided by Matt Gallagher.
anyone who konws when the library have no codec match download item (for example, my item encode by .AAC 128-bit and the library not support or at most .AAC 64-bit), what happen would the player be ?
You can either parse the icy meta data yourself, or if you're using iOS 4.0 you can playback using an AVPlayer and observe the timed metadata to discover the song boundaries and titles.

Sound on simulator but not device

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.

Multiple audio sounds in iPhone app?

I've gotten to play a single sound in the iPhone app I've started, but I now desire to play multiple sounds based on a button. To create a separate set of .m and .h files for each audio sounds, and then including them all, doesn't seem the most efficient way to tackle this in terms of coding...then again, I'm just starting out with Cocoa and only just completed my first app ever.
Any help is appreciated. The key here is multiple sounds, each triggered by its own button or image. Thanks.
If the files are MP3 or AAC format, then you can only play one at a time. This is a limitation of core audio on the iPhone.
In terms of playing multiple sounds at once, that's easy, just create a new player instance for every one that you want to play (and remember to release them when you're done)
NSString *path = [[NSBundle mainBundle] pathForResource:#"dream" ofType:#"m4a"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
To convert an MP3 into something like IMA4 (which you can play more than one at once) you would run the following (in terminal, in leopard):
/usr/bin/afconvert -f caff -d ima4 sound.mp3 sound.caf
The above code is firmware 2.2 only, but you can do the same with the AudioQueue files if you want to support older firmwares (it's just a lot more complex, so I haven't listed the code here).
If you have access to the iPhone developer network, then there are a bunch of code samples that show you how to play audio.
All you need to do is make one class that has a function called
-(void)Play:(NSString*)sSoundFile {
// play sound file here
}
I don't have any direct experience with iPhone development, but in theory could you create a single large sound file with all your sounds in it? Each sound could be separated by just enough silence to be individually accessed by a time index. Of course, the downside is that you'd have to load the entire file into memory, unless you could figure out a way to load chunks in a random-access fashion...
#rustyshelf - does this work in the simulator? I'm using that code, and using #import but neither audioPlayerDidFinishPlaying nor audioPlayerDecodeErrorDidOccur ever get called. Very annoying to try to debug.
http://www.icodeblog.com/2009/05/04/iphone-game-programming-tutorial-part-4-basic-game-audio/
in this example in ios5 you have to put
CFURLRef soundurl=(__bridge CFURLRef)[NSURL fileURLWithPath:objstring];
in place of
CFURLRef soundurl=(CFURLRef)[NSURL fileURLWithPath:objstring];
Hardik Mamtora