playing music by url - objective-c

I want to play the music from internet by url.
I create a simply project that has one button with the following code:
NSURL *url = [[NSURL alloc] initWithString:#"http://someURL.mp3"];
NSError **err;
QTMovie *movie = [[QTMovie alloc] initWithURL:url error:err];
[movie play];
It works but with some delay (I think because it waits while file has been fully downloaded).
So what I need to do that the music starts to play immediately (when, for example, 10% of file has been downloaded)?

Use -[QTMovie autoplay] to automatically play the music once enough data has been downloaded.
In your case:
NSURL *url = [[NSURL alloc] initWithString:#"http://someURL.mp3"];
NSError **err;
QTMovie *movie = [[QTMovie alloc] initWithURL:url error:err];
[movie autoplay];
From the QTMovie class reference:
The autoplay method configures a QTMovie object to begin playing as soon as enough data is available that the playback can continue uninterrupted to the end of the movie.

If you can consider displaying a Quicktime window over your app, you can use this code :
NSString *url = #"http://someURL.mp3";
UIWebView* tempAudioPlayer = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[tempAudioPlayer loadHTMLString:[NSString stringWithFormat:#"<iframe frameborder=\"0\" width=\"0\" height=\"0\" src=\"%#\"></iframe>", url] baseURL:nil];
[self addSubview:tempAudioPlayer];
I first create a UIWebView which will not be displayed. Then I loadHTMLString a <iframe> in it, with the URL of my file as the src value. And I add it to my view. Quicktime appears immediately.

Related

Streaming Audio only from a link

I have went through many youtube tutorials and looked everywhere. I want to create a live streaming app, I want to click the button play and it plays the streaming audio, and when i click the Stop button it stops. here is my code. Although on my device no sound actually plays. I don't know what Im doing wrong.
I have imported #import <AVFoundation/AVFoundation.h> in both .m and .h
-(IBAction)LiveStream3:(id)sender {
NSString *stream = #"http://audio2.radioreference.com/il_chicago_police2.mp3";
NSURL *url = [NSURL URLWithString: stream];
myAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:url fileTypeHint:stream error:nil];
myAudio.numberOfLoops = 0;
[myAudio play];
[streamTitle setText:#"Chicago"];
NSLog(#"Playing");
}
-(IBAction)stopAudio:(id)sender {
[myAudio stop];
[streamTitle setText:#""];
NSLog(#"Stop");
}

ios8 AVAudioEngine: proper way to play multiple (long) audio files

I'm attempting to play several fairly long files at once in sync using AVAudioEngine in iOS 8.
I can do this with the following:
- (void)startAudio {
AVAudioMixerNode *mainMixer = [self.engine mainMixerNode];
AVAudioPlayerNode *player = [[AVAudioPlayerNode alloc] init];
AVAudioPlayerNode *player2 = [[AVAudioPlayerNode alloc] init];
AVAudioPlayerNode *player3 = [[AVAudioPlayerNode alloc] init];
[self.engine attachNode:player];
[self.engine attachNode:player2];
[self.engine attachNode:player3];
NSString *fileName = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] bundlePath], #"file1.caf"];
NSURL *fileUrl = [NSURL fileURLWithPath:fileName];
AVAudioFile *file = [[AVAudioFile alloc] initForReading:fileUrl error:nil];
NSString *fileName2 = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] bundlePath], #"file2.caf"];
NSURL *fileUrl2 = [NSURL fileURLWithPath:fileName2];
AVAudioFile *file2 = [[AVAudioFile alloc] initForReading:fileUrl2 error:nil];
NSString *fileName3 = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] bundlePath], #"file3.caf"];
NSURL *fileUrl3 = [NSURL fileURLWithPath:fileName3];
AVAudioFile *file3 = [[AVAudioFile alloc] initForReading:fileUrl3 error:nil];
[self.engine connect:player to:mainMixer format:file.processingFormat];
[self.engine connect:player2 to:mainMixer format:file2.processingFormat];
[self.engine connect:player3 to:mainMixer format:file3.processingFormat];
[player scheduleFile:file atTime:nil completionHandler:nil];
[player2 scheduleFile:file2 atTime:nil completionHandler:nil];
[player3 scheduleFile:file3 atTime:nil completionHandler:nil];
NSError *error;
[self.engine startAndReturnError:&error];
[player play];
[player2 play];
[player3 play];
}
But that seems cumbersome. I thought there is a way to chain nodes together, but I can't find any examples and wasn't quite clear how to do this from watching the WWDC session on AVAudioEngine.
Any ideas?
You should not atTime:nil, but choose a time in the near future. Like now + 0.1 seconds and schedule it all players to play at that time.
Look at my question an answer at: Scheduling an audio file for playback in the future with AVAudioTime
to find out how.
scheduleSegment or scheduleFile work about the same way, but with scheduleSegment you can start playing at any point in the file.
ATTENTION - Note the difference between synchronized STARTING and synchronized PLAYING!!!
If you only want to start several player ONCE and at the same start time you definitely have to use the playAtTime: method with all of them referring to the same now time that you can freely choose. You can choose nil as a value and the system will schedule them on the next render frame 1024 samples later. Just in case you don't have your playAtTime: calls in a row (which you do have with play: in your code above) but rather interrupted by some other calls or NSLog-s it is generally safer to assign a start time instead of just putting nil. But mind you this only gives you a sync'ed FIRST start but no further guaranty for synching additional new players to the block of players recently started.
There are some design flaws on Apple's side (I would call them bugs) that make sync'ed playing with AVAudioEngine almost impossible. e.g.
if your start time is playAtTime:playerLastRender you are already screwed. Your player DO start in-sync to each other but you are already out-of-sync in regards to your engine's node time because...
in some cases your submitted start time gets overruled and changed by the system, so all subsequent calculations - you have to do for e.g. synching an additional player - that are based on your own requested (but silently changed under the hood) start time will be out-of-sync...
the system even goofs itself up!!! playerTimeForNodeTime: and nodeTimeForPlayerTime: do report wrong values - so you can't make any decisions based on these values either etc.
For the subtleties have a look at my answer in
AVAudioEngine multiple AVAudioInputNodes do not play in perfect sync
I've covered a lot of stuff of AVAudioEngine that one should know!
Have fun!

iOS not playing my sound?

I've went to COUNTLESS links and tutorials for this, but I either get no errors but no sound plays, or I get an error.
Using the code
NSString *toneFilename = [[NSBundle mainBundle] pathForResource:#"spoken" ofType:#"mp3"];
NSURL *toneURLRef = [NSURL fileURLWithPath:toneFilename];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL: toneURLRef error: nil];
player.currentTime = 0;
player.volume = 1.0f;
[player play];
My application runs, but doesn't play the sound on load. I was listening to music and tried the app, and it stopped my music as if it were going to play something in-app, but it never did.
Why is this happening?
If you're using ARC, and you declare an AVAudioPlayer as a local variable, the player will be dealloc'ed by ARC before it has a chance to play the sound. To fix the problem, declare the player as a property.

iOS AVAudioPlayer double sound playing issue with Xcode 4.2 and ARC

Ive been beating my head up against the all trying to figure out a weird sound issue in my program. I will post the code below. As a brief description I have a function that gets passed a variable and it takes that and decides which category of sound it should play, within that function I have multiple sounds of reach category so I use an arc4random statement then run that through a switch statement. What keeps happening is that it will play two sounds from the case statement instead of just one, most times if I call it twice with my button push the second time it will play the sound from the first time and a new sound, other times it plays the same same over the top of each other but with a slight delay. I put in a breakpoint in the switch and when it double plays it only goes through the switch once which is really confusing. One thing to note is right before this I do play another sound but it uses a separate AVAudioplayer and path variable so that shouldn't be an issue as it never plays the second sound as the other sound I'm playing. I'm only calling the function once when I press the button so I'm not sure why it does this. I have tried putting the *path and *avaudioplayer variables inside the function but it won't play at all. Searching here it seems as though arc deallocs it before it gets a chance to play it. I ended up trying to put it at the top of my .m file as a global variable then just set the actual path and play the sound within the switch. The sound will play but it plays twice.. Hopefully someone can help me out. I tried putting the avaudioplayer definition as a property as well and it does the same thing. Here is my code snippet. And thanks in advance ...
in the .m file
// Just below my synthesize statements
NSString *path;
AVAudioPlayer *theSound
// My code that I call when the button is pressed
[self playVoice:#"buyVoice"];
// The playVoice function
- (void)playVoice:(NSString*)voiceNum;
if ([voiceNum isEqualToString:#"buyVoice"]) // Bought an Item Time for a voice
{
// play coin sound
[self coinSound];
// play random buy phrase and coin sound
int phraseNumber = 0;
phraseNumber = arc4random() %(3);
switch (phraseNumber)
{
case 0:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy1" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 1:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy2" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 2:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy3" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 3:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy4" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
}
}
set this code before u play the Audio sound
This will reset the player to the beginning:
[theSound setCurrentTime:0.0];
[theSound play];
try this

Help on Objective C? My app keeps crashing?

I am creating an app for the Iphone/Itouch, but I keep on running into a couple of major leaks that just crash the app. In my game, right when I press play (from the home screen)It goes to another page that has the game on it. But, right after it appears, ind the console I get a Warning: Memory level=1. What could be happening? Here is my ViewDidLoad Method:
-(void)viewDidLoad {
[super viewDidLoad];
array = [[NSMutableArray alloc] initWithCapacity:100];
bulletArray = [[NSMutableArray alloc] initWithCapacity:100];
pos = CGPointMake(0.0,-5.0);
NSString *path = [[NSBundle mainBundle] pathForResource:#"GloriousMorning" ofType:#"mp3"];
AVAudioPlayer *theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
//float effects_Volume = [[NSUserDefaults standardUserDefaults] floatForKey:#"effectsVolume"];
//theAudio.volume = effects_Volume;
[theAudio play];
}
And also, a second question, since my game is a shooting game, the user presses a button titled "Fire". But, every time I test my app on a device, It crashes when I press the fire button. Here is my code for the fire button.
-(IBAction)Fire {
NSString *path = [[NSBundle mainBundle] pathForResource:#"gunShot" ofType:#"mp3"];
AVAudioPlayer *theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
//float effects_Volume = [[NSUserDefaults standardUserDefaults] floatForKey:#"effectsVolume"];
//theAudio.volume = effects_Volume;
[theAudio play];
//IBOutlet UIImageView *newBullet = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Bullet.png"]];
UIImageView *newBullet = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Bullet.png"]];
newBullet.frame = CGRectMake(0, 0, 10.0, 10.0);
newBullet.center = CGPointMake(239.0, 236.0);
[bulletArray addObject:newBullet];
[self.view addSubview:newBullet];
}
First, I create a sound. Then, I place a bullet right where the gun is currently located, and add it to an array so that every .01 of a second, in another bit of code, I can run through the array and check every bullet to detect collision.
Please tell me what I am doing wrong. Thanks!!!
The error when I click the Fire Button that makes the app crash is this:
GDB: Data Formatters temporarily unavailable, will retry after a 'continue'(unknown error loading shared library "
And Also I think I am making a huge leak when I try to play the audio, at least that's what someone told me. (If that is the case, please tell me how to fix it)
You alloc'd theAudio so you need to release it when you are done. Might be better to make that a ivar so you don't have to set up and tear down the audio every time they press the fire button.