Start playing SoundCloud audio stream in iOS by using a pre-buffer - ios

Using the following code example from SoundCloud Developers page, the AVAudioPlayer will start playing after the SCRequest response has been received. Depending on the size of the requested file, this might take some time.Does the iOS SoundCloud API offer a pre-buffer solution, so that it would be possible to start playing audio before all data has been received or do I need to implement a own solution with help of NSURLConnection in order to achieve this?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *track = [self.tracks objectAtIndex:indexPath.row];
NSString *streamURL = [track objectForKey:#"stream_url"];
SCAccount *account = [SCSoundCloud account];
[SCRequest performMethod:SCRequestMethodGET
onResource:[NSURL URLWithString:streamURL]
usingParameters:nil
withAccount:account
sendingProgressHandler:nil
responseHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSError *playerError;
player = [[AVAudioPlayer alloc] initWithData:data error:&playerError];
[player prepareToPlay];
[player play];
}];
}

To stream tracks from SoundCloud, all you need to do is pass the URL to AVPlayer with the client id:
NSString *urlString = [NSString stringWithFormat:#"%#?client_id=%#", track.streamURL, self.clientId];
player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:urlString]];
[player play];
It will take a bit of extra work to make it a progressive download. Hope that helps.

afaik there is no pre-buffer solution at the moment. If you want to contribute to our SoundCloud API we'd love to review a Pull Request from you regarding this feature.
This will probably affect CocoaSoundCloudAPI and OAuth2Client.
Happy Coding!

Related

AudioKit AKTimePitch does not work for the recoded file example.m4a

I am building up a APP on iOS by AudioKit(version 4.5.3), and I find out the AKTimePitch class does not work for me, here is my code(objective-c xcode 10):
(IBAction)startButton:(id)sender {
NSURL *url = [[NSBundle mainBundle] URLForResource:#"burncalory" withExtension:#"m4a"];
AKAudioFile *file = [[AKAudioFile alloc] initForReading:url error:nil];
AKAudioPlayer *player = [[AKAudioPlayer alloc] initWithFile:file looping:NO lazyBuffering:YES error:nil completionHandler:^{
NSLog(#"Finished!");
}];
AKTimePitch *akTimePitch = [[AKTimePitch alloc] init:player rate:2.0 pitch:1600 overlap:8];
AudioKit.output = akTimePitch;
[akTimePitch start];
[AudioKit startAndReturnError:nil];
[player playFrom:0.0];
}
I check out the playground(4.5.3), and the sample of "Time Stretching and Pitch Shifting" works well.
Is there something wrong in my code to use AKTimePitch or something wrong with my audio file example.m4a? By the way, this audio file can be loaded and play well by AKAudioPlayer.
After some testing I found that the parameter in the init method does not work, but after I add akTimePitch.pitch=1600 before [player playFrom:0.0], then the AKTimePitch effects works!! I don't know why the AKTimePitch *akTimePitch = [[AKTimePitch alloc] init:player rate:2.0 pitch:1600 overlap:8]; just does not work...

AVAudioPlayer Freezes the UI when new sound is played

I am new to iOS and I was searching fix for this issue since morning and didn't find the solution yet, I have more than 6000 sound files online which i want to play using AVAudioPlayer when user click on the cell, so i implemented it in didSelectRowAtIndexPath:
like this :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#", [soundsArray objectAtIndex:(int)indexPath.row]];
NSData *soundData = [NSData dataWithContentsOfURL:url];
_audioPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:NULL];
[_audioPlayer play];
}
the problem is, whenever i click on any row, the whole UI freezes till the time it takes to load the complete sound file from internet,
for larger files , it takes longer.
I tried with AVPlayer and it is working fine, but I need AVAudioPlayer becouse it seems easy to me to work with
-(void)AVAudioPlayerDidFinishPlaying:(AVAudioPlayer *)Player successfully:(BOOL)flag
thats why I want to implement it with AVAudioPlayer
I hope you understood my problem,
Sorry for my bad English.
Never use
NSData *soundData = [NSData dataWithContentsOfURL:url];
this will block your UI.
You need to use NSURLSession to download data asynchronously.

Stream .m4a audio file from rtsp url objective-c ios

Sorry for bad Engilsh.
I am new to iOS development.And I am trying to create a client application which stream .m4a audio file from stream url
rtsp://192.168.1.50:1935/TestServer/abc.m4a
and play it on button click.
I have tried almost every thing which I can find but I was not able to get and play stream.
There is my code which play audio from http url
- (IBAction)btn:(id)sender {
NSString *str = #"http://download.wavetlan.com/SVV/Media/HTTP/AAC/Nero_Soundtrax/NeroSoundTrax_test1_AAC-LC_v4_Stereo_CBR_96kbps_44100Hz.m4a";
NSString *urlStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSURL * mediaURL = [NSURL URLWithString:urlStr];
player = [AVPlayer playerWithURL:mediaURL];
[player play];
}
but I want to play audio file from this type of url. rtsp://192.168.1.50:1935/TestServer/abc.m4a
i tested my streaming url on VLC to verify. It works perfect but when I put that url on button click code it didn't work.
I try to use ffmpeg library but did not find luck in that.
Try register audio session category before playing.
- (IBAction)btn:(id)sender {
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:NULL];
NSString *str = #"http://download.wavetlan.com/SVV/Media/HTTP/AAC/Nero_Soundtrax/NeroSoundTrax_test1_AAC-LC_v4_Stereo_CBR_96kbps_44100Hz.m4a";
NSString *urlStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSURL * mediaURL = [NSURL URLWithString:urlStr];
player = [AVPlayer playerWithURL:mediaURL];
[player play];
}
Hope this helps.
Standard iOS frameworks do not support RTSP playback, so you will have to use some third-party solution.
Hope this post helps:
https://gist.github.com/oc2pcoj/e55795550984d205d109

Using NSURLSession to play remote audio, code critique

First, to avoid posting a great deal of code on here, I have created a very basic example of what I am after - https://github.com/opheliadesign/AudioTest.
I am brand new to iOS development and I'm having a little trouble understanding the best way to load and play a static MP3 file on a remote server. The audio is not streaming live, is less than a megabyte - about 30 seconds long in average (they are radio dispatches).
It has been suggested that I use NSURLSession to load the MP3 file and then play it within the completion block. This seems to be working but I have a feeling that I could be handling it better, just do not know how. Here is the block where I grab the audio and begin playing:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
NSLog(#"View loaded");
// Register to receive notification from AppDelegate when entering background
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(stopPlayingAudio) name:#"stopPlayingAudio" object:nil];
// Assign timer to update progress
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateSeekBar) userInfo:nil repeats:YES];
// Demo recording URL
NSString *recordingUrl = #"https://s3.amazonaws.com/tevfd-recording/All_Fire_and_EMS_2015-02-0214_48_33_630819.mp3";
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:recordingUrl] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSLog(#"No error..");
self.player = [[AVAudioPlayer alloc]initWithData:data error:nil];
// Setup slider for track position
self.slider.minimumValue = 0;
self.slider.maximumValue = self.player.duration;
[self.player prepareToPlay];
[self.player play];
}
}]resume];
}
For example, have a slider that updates the player's position when it is moved. I initialize the AVAudioPlayer in the completion block but create a property for it in the header. If the player has not been initialized, could moving the slider cause a crash? If so, how should I handle this better?
Also, I have a timer that updates the slider position as the AVAudioPlayer plays. When the track reaches its end, the timer continues - clearly this is a potential memory issue. Not sure of the best way to handle this and I would also like for the user to be able to start playing the recording again after it is completed, for example if they moved the slider to the right.
I have searched and searched, cannot seem to find anything related to specifically what I am doing. Any help would be greatly appreciated.
UPDATE
This is what I first began with but I experienced some lag between clicking on a UITableView cell and presenting the view that loaded/played the audio. Several suggested NSURLSession.
- (void)viewDidLoad {
[super viewDidLoad];
// Get the URL
NSURL *callAudioURL = [NSURL URLWithString:[self.call objectForKey:#"url"]];
NSData *callAudioData = [NSData dataWithContentsOfURL:callAudioURL];
AVAudioPlayer *audio = [[AVAudioPlayer alloc] initWithData: callAudioData error:nil];
self.player = audio;
self.slider.minimumValue = 0;
self.slider.maximumValue = self.player.duration;
[[self player] play];
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateSeekBar) userInfo:nil repeats:YES];
}
If you're concerned about a small delay, then downloading and caching it is the best solution. You need to download the audio file and then play it locally. Typically playing -- or streaming -- from the network is useful only when the audio is so unique that you cannot store it locally.
To implement something like this (code untested):
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSFileHandle *hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
//did we succeed in opening the existing file?
if (!hFile) { //nope->create that file!
[[NSFileManager defaultManager] createFileAtPath:self.localPath contents:nil attributes:nil];
//try to open it again...
hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
}
//did we finally get an accessable file?
if (!hFile) {
NSLog("could not write to file %#", self.localPath);
return;
}
#try {
//seek to the end of the file
[hFile seekToEndOfFile];
//finally write our data to it
[hFile writeData:data];
} #catch (NSException * e) {
NSLog("exception when writing to file %#", self.localPath);
result = NO;
}
[hFile closeFile];
}
When all of the data has been received, start your audio:
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:self.localPath error:nil];

iOS Streaming mp3

I've been searching for a good tutorial for playing and streaming audio finally I found this which seems to offer an offline audio playing.
in the YMCAudioPlayer class I've commented loading a resource and provided NSURL* generated by a direct link instead like so.
- (void)initPlayer:(NSString*) audioFile fileExtension:(NSString*)fileExtension
{
//NSURL *audioFileLocationURL = [[NSBundle mainBundle] URLForResource:audioFile withExtension:fileExtension];
NSURL *audioFileLocationURL = [NSURL URLWithString:#"http://188.95.64.47/AghaninaDownload/Content/per_singer/JFire/Audios/J-FirE_and_Omar_khalid_wlaKelmeh-sample.mp3"];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileLocationURL error:&error];
}
And I've ensured that it's a valid link, but seems not to play on emulator. what have I missed there?
EDIT
It generates the following error
Error Domain=NSOSStatusErrorDomain Code=-43 "The operation couldn’t be completed. (OSStatus error -43.)
Might be a stupid question, but did you make it play ?
[self.audioPlayer play];
Then I would try this, to ensure your settings are correct :
[self.audioPlayer prepareToPlay];
[self.audioPlayer setCurrentTime:0.0];
[self.audioPlayer setVolume:1.0];
[self.audioPlayer play];
You can also use the delegate of AVAudioPlayer to check if something happens when you play.
Else it might be an URL of format issue.
I think you cannot play audio on EMULATOR, you have to test it on device.
Here mentioned on apple developer guid -
https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/TestingontheiOSSimulator/TestingontheiOSSimulator.html#//apple_ref/doc/uid/TP40012848-CH4-SW1
I've found the answer in the accepted answer here
"I was able to fix the issue by loading the file first into an NSData element and then using that to initialize the AVAudioPlayer instead, like so:"
NSData *songFile = [[NSData alloc] initWithContentsOfURL:songCacheURL options:NSDataReadingMappedIfSafe error:&error1 ];
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:songFile error:&error2];

Resources