iphone: how to buffer and play audio? - iphone

I need to implement the code for my app to buffer and play my audio file which is I am streaming.
I got one of the option AudioQueue but didn't find much code to understand the things to implement.
I have tried with Simply creating streamer and destroying streamer.
-(void)destroyStreamer
{
if(streamer)
[streamer stop];
}
-(void)createStreamer
{
if(streamer)
return;
[self destroyStreamer];
NSString *escapedValue = (__bridge_transfer NSString * )CFURLCreateStringByAddingPercentEscapes(nil, (__bridge CFStringRef)txtField.text, NULL, NULL, kCFStringEncodingUTF8);
NSURL *url = [NSURL URLWithString:escapedValue];
streamer = [[AudioStreamer alloc] initWithURL:url];
}

You may need to use the AudioToolBox framework.
There are multiple ways of playing sounds (long/short/format support etc...). checkout this presentation which covers it from start to end.

Related

iphone Play different alert sounds for correct or wrong multiple choice quiz answer

I want to play a different alert sound if the multiple choice option answer is correct or wrong. I have code for the correct and wrong answer as follows
if (questionNumber == 1) {
[self correctAnswer];
}
if (questionNumber == 2) {
[self wrongAnswer];
}
I have created the correct IBAction Alert code. can I create a simple play.alert statement under either the correct or wrong answer?
If you want to use default Apple sounds, use the code in this question, and click on the link he has there to try out different sounds.
If you would like to play custom sounds, the easiest way is with AVAudioPlayer:
First of all, you will need to add the AVFoundation framework to your project. It is very easy from there:
NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];
AVAudioPlayer *sound = audioPlayers[url];
NSError *error = nil;
sound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[sound play];

Playing sound effect with no latency in Objective-C

I want to play some simple sound effects when people press certain buttons in my app and I've tried several things, but I always get a latency that makes the sound seem out of sync.
I've followed the tutorials here, so I've tried the build in Audio Services, but that had a latency and I've tried the AVAudioPlayer, but that had a latency as well, even though I used "prepareToPlay".
Do I really have to install a big and messy library like Finch to get a simple sound effect with no latency in my simple app?
Hope you can clarify things for me!
UPDATE
Code for Audio Services:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &sound1);
AudioServicesPlaySystemSound(sound1);
Code for AVAudioPlayer in viewDidLoad:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
self.avSound = [[AVAudioPlayer alloc]
initWithContentsOfURL:soundURL error:nil];
[self.avSound prepareToPlay]
Code for AVAudioPlayer in method where I want to play the file:
[self.avSound play];
The way I got this to work (and I think I got the idea from another post on SO) was to create an empty 1 second .wav file and "play" it at initialization. After that, there was no delay when I called the other sound effects.
Something like this in my sound player object
SystemSoundID blID;
SystemSoundID cID;
+(void)doInit
{
if (spinitialized){
AudioServicesPlaySystemSound (blID);
return;
}
NSString *str = [[NSBundle mainBundle] pathForResource:#"ding.wav" ofType:#""];
NSURL *uref = [NSURL fileURLWithPath:str];
OSStatus error = AudioServicesCreateSystemSoundID ((CFURLRef)uref, &cID);
if (error) NSLog(#"SoundPlayer doInit Error is %ld",error);
str = [[NSBundle mainBundle] pathForResource:#"blank.wav" ofType:#""];
uref = [NSURL fileURLWithPath:str];
error = AudioServicesCreateSystemSoundID ((CFURLRef)uref, &blID);
if (error) NSLog(#"SoundPlayer doInit Error is %ld",error);
AudioServicesPlaySystemSound (blID);
spinitialized = YES;
}
Then I could just play the "ding" without any delay using:
AudioServicesPlaySystemSound (cid);
SOLUTION
I ended up doing something similar as Mike above. I ended up playing the sound with the sound volume down in viewDidLoad:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
self.plops = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[self.plops setVolume:0.0];
[self.plops play];
And then in the function where I play it I do:
[self.plops setVolume:1.0];
[self.plops play];
One thing I found that seems to help is, upon entry to the screen where the sound MIGHT be played, to play a fraction of a second of a sound. This seems to "prime" the sound mechanism -- allocating internal objects, paging in stuff, etc.
(I observe that this is similar to Mike M's approach.)

MPMoviePlayerController playing YouTube video

How can I play a YouTube video in an MPMoviePlayerController on the iPhone while avoiding going into fullscreen mode?
This question has been raised here: MPMoviePlayerController is playing YouTube video? and here: Play Youtube video in MPMoviePlayerController or play RTSP - 3GP link with answers claiming such functionality was impossible.
Yet this app, Deja, has exactly the functionality I would like: a seamless MPMoviePlayerController whose frame I have explicit control over. http://itunes.apple.com/app/deja/id417625158
How is this done!?
add this sample into you project
instantiate YoutubeStreamPathExtractorTest
invoke test method of YoutubeStreamPathExtractorTest instance.
Follow logs and be happy
#import "AFHTTPRequestOperationManager.h"
#import <MediaPlayer/MediaPlayer.h>
typedef void (^CallbackBlock)(NSArray* result, NSError* error);
static NSString* const kYouTubeStreamPathPattern = #"\\\"url_encoded_fmt_stream_map\\\\\":.*?url=(.*?)\\\\u0026";
#interface YoutubeStreamPathExtractorTest : NSObject
- (void)test;
- (void)youtubeURLPath:(NSString*)youtubeURLPath extractStreamURLPathsWithCallback:(CallbackBlock)callback;
#end
#implementation YoutubeStreamPathExtractorTest
- (void) test {
NSString* path = #"http://www.youtube.com/watch?v=TEV5DZpAXSw";
[self youtubeURLPath:path extractStreamURLPathsWithCallback:^(NSArray *result, NSError *error) {
if (error){
NSLog(#"extracting error:%#",[error localizedDescription]);
}
for(NSString* streamURLPath in result) {
NSLog(#"streamURLPath:%#",streamURLPath);
/*
NSURL* url = [NSURL URLWithString:streamURLPath];
MPMoviePlayerController* mpMoviePlayerController_ = [[MPMoviePlayerController alloc] initWithContentURL:url];
mpMoviePlayerController_.controlStyle = MPMovieControlStyleDefault;
[mpMoviePlayerController_ play];
*/
}
}];
}
- (void)youtubeURLPath:(NSString*)youtubeURLPath extractStreamURLPathsWithCallback:(CallbackBlock)callback {
__block NSMutableArray* resultArray = [NSMutableArray new];
AFHTTPRequestOperationManager* manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:nil];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"text/html", nil];
[manager GET:youtubeURLPath
parameters:nil
success:^(AFHTTPRequestOperation* operation, id responseObject) {
NSData* data = (NSData*)responseObject;
NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSError* error = nil;
NSRegularExpression* expression = [NSRegularExpression regularExpressionWithPattern:kYouTubeStreamPathPattern
options:NSRegularExpressionCaseInsensitive
error:&error];
NSRange range = NSMakeRange(0,[string length]);
NSArray* matches = [expression matchesInString:string options:0 range:range];
for(NSTextCheckingResult* checkingResult in matches) {
if ([checkingResult numberOfRanges]>1){
NSString* resultStr = [string substringWithRange:[checkingResult rangeAtIndex:1]];
//remove extra slashes
[resultArray addObject:[resultStr stringByReplacingOccurrencesOfString:#"\\" withString:#""]];
}
}
if (callback) {
callback(resultArray,error);
}
} failure:^(AFHTTPRequestOperation* operation, NSError* error) {
if (callback) {
callback(resultArray, error);
}
}];
}
#end
MPMoviePlayerController does not support the playback of YouTube SWF (Flash) video, period.
That app you are mentioning actually plays progressively downloaded files in MP4 format which YouTube also offers for some of its content. This actually is a violation of Apple's guidelines as it will (and does) exceed the maximum amount of progressive download per app per timeframe. I am surprised it got through the iTunes approval.
Warning: iOS apps submitted for distribution in the App Store must
conform to these requirements. If your app delivers video over
cellular networks, and the video exceeds either 10 minutes duration or
5 MB of data in a five minute period, you are required to use HTTP
Live Streaming. (Progressive download may be used for smaller clips.)
If your app uses HTTP Live Streaming over cellular networks, you are
required to provide at least one stream at 64 Kbps or lower bandwidth
(the low-bandwidth stream may be audio-only or audio with a still
image).
These requirements apply to iOS apps submitted for distribution in the
App Store for use on Apple products. Non-compliant apps may be
rejected or removed, at the discretion of Apple.
So your task boils down to the question on how to get the MP4 URL of a video offered through YouTube. That part is really tricky and nicely solved by Deja. Just use a packet sniffer and you will see that it actually creates a local server that feeds MPMoviePlayerController.
try this code:
NSString *urlStr=[Your url is here];
NSURL *url = [NSURL fileURLWithPath:urlStr];
MPMoviePlayerController* moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:url];
[self.view addSubview:moviePlayer.view];
moviePlayer.view.frame = CGRectMake(set frame is here);
[moviePlayer play];
[moviePlayer setFullscreen:NO animated:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
I guess it is against Youtube ToS but you can use this code here:
https://github.com/larcus94/LBYouTubeView
It is simple to use and works like a charm!
Use UIWebView. Copy HtML code video in youtube.
UIWevView* movie = [UIWebView alloc] initWithFrame:CGRectMake(0,0,320,460)];
NSString* urlString = #"past HTML code";
[self.webView loadHTMLString:urlString baseURL:nil];
[self.view addSubview:movie];

iPhone, AVAudioPlayer and multiplesounds

im new developer and making my firt iPhone app ,and i want to make button to on/off multiplesounds , example when i press button for multiple sounds after when i play sounds it plays all sound at same time and if its off can play only one sounds, what code is to make ON/OFF multiple sounds play?
sorry for my bad english, Tanks!
Sania,
In order to play multiple sounds at once, Apple recommends using the .caf format which is hardware decoded. Also, you basically just create a new AVAudioPlayer object for each sound file instead of re-using the same object in the case where you only want one sound to play at a time.
I won't go into much of the code since there is already a LOT out there if you just search for it... but here are some helpful links to get you started:
http://developer.apple.com/iphone/library/documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html
http://www.mobileorchard.com/easy-audio-playback-with-avaudioplayer/
// a function I use to play multiple sounds at once
- (void)playOnce:(NSString *)aSound {
// Gets the file system path to the sound to play.
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
// Converts the sound's file path to an NSURL object
NSURL *soundURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
self.soundFileURL = soundURL;
[soundURL release];
AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error:nil];
self.theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
[newAudio release]; // release the audio safely
// buffers data and primes to play
[theAudio prepareToPlay];
// set it up and play
[theAudio setNumberOfLoops:0];
[theAudio setVolume: volumeLevel];
[theAudio setDelegate: self];
[theAudio play];
}

Using system Sound to play sounds

Here is the code:
-(void)stop
{
NSLog(#"Disposing Sounds");
AudioServicesDisposeSystemSoundID (soundID);
//AudioServicesRemoveSystemSoundCompletion (soundID);
}
static void completionCallback (SystemSoundID mySSID, void* myself) {
NSLog(#"completion Callback");
}
- (void) playall: (id) sender {
[self stop];
AudioServicesAddSystemSoundCompletion (soundID,NULL,NULL,
completionCallback,
(void*) self);
OSStatus err = kAudioServicesNoError;
NSString *aiffPath = [[NSBundle mainBundle] pathForResource:#"slide1" ofType:#"m4a"];
NSURL *aiffURL = [NSURL fileURLWithPath:aiffPath];
err = AudioServicesCreateSystemSoundID((CFURLRef) aiffURL, &soundID);
AudioServicesPlaySystemSound (soundID);
NSLog(#"Done Playing");
}
Output:
Disposing Sounds
Done Playing
In actual no sound gets play at all and completion call back isn't called as well. Any idea what could be wrong here?
I want to stop any previous sound before playing current.
AFAIK, the only supported files are .caf, .aif, or .wav:
To play your own sounds, add the sound
file to your application bundle; the
sound file must adhere to the
following requirements:
Must be .caf, .aif, or .wav files.
The audio data in the file must be in PCM or IMA/ADPCM (IMA4) format.
The file's audio duration must be less than 30 seconds.
Audio & Video Coding How-To's
What does err contain? From that you should be able to infer the problem.
You can use AudioToolBox framework for this:
CFBundleRef mainbundle = CFBundleGetMainBundle();
CFURLRef soundFileURLRef = CFBundleCopyResourceURL(mainbundle, CFSTR("tap"), CFSTR("aif"), NULL);
AudioServicesCreateSystemSoundID(soundFileURLRef, &soundFileObject);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(1100);