how to create AVAudioPCMBuffer from NSData - ios

I receive mp3 from stream and convert pcm data. I try to use AVAudioEngine but can not create AVAudioPCMBuffer without file.
- (void)playAudio:(NSNotification *)notification {
self.runAudioThread = YES;
dispatch_queue_t globalDispatchDefaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
[_player play];
dispatch_async(globalDispatchDefaultQueue, ^{
while (_runAudioThread) {
if (_rawDataArray.count > BUFFER_COUNT) {
NSMutableData *rawData = [[NSMutableData alloc] init];
NSArray *rawDataArray = _rawDataArray.copy;
#synchronized(_rawDataArray) {
[self.rawDataArray removeAllObjects];
}
for (AudioPacketInfo *audioPacketInfo in rawDataArray) {
[rawData appendData:audioPacketInfo.data];
}
NSData *mp3Data = [AudioUtil makeMP3Data:rawData];
if (mp3Data) {
NSData *pcmData = [AudioUtil convertToPCMWithData:mp3Data];
if (pcmData.length > 0) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = paths[0];
NSString *filePath = [documentsDirectory stringByAppendingString:#"/temp.mp3"];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:mp3Data attributes:nil];
AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:[NSURL URLWithString:filePath] error:nil];
AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFile.processingFormat frameCapacity:(AVAudioFrameCount)audioFile.length];
[audioFile readIntoBuffer:buffer error:nil];
[_player scheduleBuffer:buffer completionHandler:nil];
}
}
}
}
});
}
how would i do that?
Convert mp3 to pcm

Related

VOIP Call recording for PJSIP Library not working

Unable to record PJSIP Call in ios code. I am using PJSIP 2.2 version.
Following is my code
pjsua_recorder_id recorder_id;
pj_status_t status;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *strPath = [NSString stringWithFormat:#"%#/mysong.wav", documentsDirectory];
pj_str_t fileName = pj_str([strPath UTF8String]);
status = pjsua_recorder_create(&fileName, 0, NULL, 0, 0, &recorder_id);
NSLog(#"status is = %i", status);
int way = 1 << 0;
static int BITMASK_IN = 1 << 0;
static int BITMASK_OUT = 1 << 1;
if(status == PJ_SUCCESS)
{
pjsua_recorder_id recorder_id;
pj_status_t status;
int wavPort = pjsua_recorder_get_conf_port(0);
if ((way & BITMASK_IN) == BITMASK_IN) {
int wavConfPort = -1;//callInfo.getConfPort();
pjsua_conf_connect(0, wavPort);
}
if ((way & BITMASK_OUT) == BITMASK_OUT) {
pjsua_conf_connect(0, wavPort);
}
wavPort = pjsua_call_get_conf_port(0);
pjsua_conf_connect(0, wavPort);
status = pjsua_recorder_create(&fileName, 0, NULL, 0, 0, &recorder_id);
NSLog(#"final status is = %i", status);
}
Value of Status is 0(PJ_SUCCESS), but still unable to play .wav file. To play .wav file,
// get files list
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSLog(#"Array of files = %#", directoryContents);
//Play audio file
NSString *soundFilePath = [NSString stringWithFormat:#"%#/mysong.wav",documentsDirectory];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:soundFileURL options:nil];
AVAudioPlayer *theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:NULL];
theAudio.volume = 1.0;
theAudio.delegate = self;
[theAudio prepareToPlay];
[theAudio play];
In array of file I am able to get recorded .wav file.

I'm unable to save or download video in document directory and play from document directory

I want to download or save youtube video in document directory and then play that video using MPMoviePlayerViewController. But I don't know why my code is not working.
I'm using this below code :
prgrma mark- download Or save
-(IBAction)onclick_download:(id)sender
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Downloading Started");
NSString *urlToDownload = #"youtubeurl";
NSURL *url = [NSURL URLWithString:urlToDownload];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"thefile.mp4"];
//saving is done on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[urlData writeToFile:filePath atomically:YES];
NSLog(#"File Saved !");
});
}
});
}
pragma mark- Play video from document directory
-(IBAction)onclick_playvideolocally:(id)sender
{
[self playvideolocally];
}
-(void)playvideolocally
{
NSURL *videoUrl;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
NSLog(#"files array %#", filePathsArray);
NSString *fullpath;
for ( NSString *apath in filePathsArray )
{
fullpath = [documentsDirectory stringByAppendingPathComponent:apath];
videoUrl =[NSURL fileURLWithPath:fullpath];
}
MPMoviePlayerViewController *videoPlayerView = [[MPMoviePlayerViewController alloc] initWithContentURL:videoUrl];
[self presentMoviePlayerViewControllerAnimated:videoPlayerView];
[videoPlayerView.moviePlayer play];
}
As your link you provided in url is for youtube so it is not downloaded or saved in local
Use this for youtube
Ive used classes from this project: https://github.com/larcus94/LBYouTubeView It works fine for me. I can download youtube videos.
LBYouTubeExtractor *extractor = [[[LBYouTubeExtractor alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:(#"http://www.youtube.com/watch?v=%#"), self.videoID ]] quality:LBYouTubeVideoQualityLarge] autorelease];
[extractor extractVideoURLWithCompletionBlock:^(NSURL *videoURL, NSError *error) {
if(!error) {
NSLog(#"Did extract video URL using completion block: %#", videoURL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL: videoURL];
NSString *pathToDocs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [NSString stringWithFormat:(#"video_%#.mp4"), self.videoID ];
[data writeToFile:[pathTODocs stringByAppendingPathComponent:filename] atomically:YES];
NSLog(#"File %# successfully saved", filename);
});
} else {
NSLog(#"Failed extracting video URL using block due to error:%#", error);
}
}];

How can download audio? objective-c

I have audio player. I download audio in this way
- (void) song{
if (_index == 0) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"1.mp3"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:NO];
if (!fileExists) {
NSString *stringURL = #"https://drive.google.com/uc?export=download&id=0B6zMam2kAK39VHZ1cUZsM3BhQXM";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
}
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:filePath] error:nil];
}
}
But when audio downloading I can’t do anything. User interface stop.
How can download audio and do anything in user interface simultaneously?
Give your method a block to execute when finished, then run the download code in the background. Lets say, for your case the output is a local file with the downloaded content:
- (void)songWithCompletion:(void (^)(NSString *))completion {
NSString *filePath = [self song];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(filePath);
});
}
Change the song method to return filePath. Don't ever call it directly, only via songWithCompletion.
- (void)song {
// ... your code from the OP
// don't allocate the audio player here, just return the local file
return filePath;
}
Call it like this...
[self songWithCompletion:^(NSString *filePath) {
if (filePath) {
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:filePath] error:nil];
// you should really handle audio player error here, too
} else {
// handle error
}
}];
You are downloading the file in the main thread. you need to make an asynchronous call in order to avoid stopping UI.
-(void)downloadAudio
{
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://drive.google.com/uc?export=download&id=0B6zMam2kAK39VHZ1cUZsM3BhQXM"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [NSMutableData data] ;
} else {NSLog(#"no connection!");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"Succeed! Received %d bytes of data",[receivedData length]);
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//NSLog(#"%#", [documentPaths objectAtIndex:0]);
NSString *documentDirectoryPath = [documentPaths objectAtIndex:0];
NSString *folderPath = [documentDirectoryPath stringByAppendingPathComponent:#"audioFile.mp3"];
[receivedData writeToFile:folderPath atomically:YES];
NSURL *soundURL = [NSURL fileURLWithPath:folderPath];
NSError *error;
if ([[NSFileManager defaultManager] fileExistsAtPath:folderPath]) {
player = [[AVAudioPlayer alloc]initWithContentsOfURL:soundURL error:&error];
player.volume=0.5;
NSError *error = nil;
if (!error) {
[player play];
NSLog(#"File is playing!");
}
else{
NSLog(#"Error in creating audio player:%#",[error description]);
}
}
else{
NSLog(#"File doesn't exist");
}
}

how to play an audio from directory file in xcode?

i'm trying to design audio streaming app everything is working, but i don't know how to download audio file to the device and read it afterword.
Download audio to document directory.
play it back from document directory.
Added code:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path firstObject];
NSString *filePath = [documentDirectory stringByAppendingPathComponent:#"evet.mp3"];
// UIImage *cellImage = [[UIImage alloc] initWithContentsOfFile:filePath];
NSLog(#"%#",filePath);
NSError *error;
NSData *_objectData = [NSData dataWithContentsOfURL:[NSURL URLWithString:filePath]];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:_objectData error:&error];
[audioPlayer play];
Based on the code you posted try this.
Change
NSData *_objectData = [NSData dataWithContentsOfURL:[NSURL URLWithString:filePath]];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:_objectData error:&error];
to this:
NSURL *fileURL = [NSURL fileURLWithPath:filePath isDirectory:NO];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
AVAudioPlayer wants a URL object (which needs to be a local URL not a remote web address, hence fileURLWithPath:) not the data itself.
You were trying to give the NSData itself to the audio player.
Fetch your audio file in document directory
- (NSString *)getCacheDirectoryPathForAudio:(NSString *)filePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it
NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3", filePath]]; //add
return fullPath;
}
Initiate player with file path
NSString *pathToSaveAudioString = [self getCacheDirectoryPathForAudio:#“filename”];
NSURL* url = [NSURL fileURLWithPath:pathToSaveAudioString];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:pathToSaveAudioString];
if (fileExists) {
NSError* error = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[self.player setDelegate:self];
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}
}
else
{
NSLog(#“File Not Exist: %#");
}
and play it using
[self.player play];
Use Delegate methods to check status
#pragma mark - AVAudioPlayerDelegate
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
}
For more details follow
http://iosdeveloperzone.com/2012/10/01/tutorial-playing-audio-with-avaudioplayer/
I have simple code
NSData *D = [self FindDatafromDocument:#"ASDF"];
player = [[AVAudioPlayer alloc] initWithData:D error:nil];
[player setDelegate:self];
[player play];
Method
- (NSData *)FindDatafromDocument:(NSString *)Name {
NSData *IMG;
NSError *error;
NSArray *directoryContents = [[NSArray alloc] init];
directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[Utility getDocumentDirectory] error:&error];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",Name];
NSArray *ArrImages = [directoryContents filteredArrayUsingPredicate:predicate];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *Doc = [paths objectAtIndex:0];
for (NSString *imageName in ArrImages) {
if ([imageName rangeOfString:#".caf"].location != NSNotFound) {
IMG = [[NSFileManager defaultManager] contentsAtPath:[NSString stringWithFormat:#"%#/%#",Doc,imageName]];
}
}
return IMG;
}

Load audio in DOCUMENTS when UITableView "cell" is pressed

I have a UITableView displaying a llist f files in the Documents Directory... and I want it to play the audio file in the Documents directory when pressed...
It runs with no errores but doesn't play the audio when pressed...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.caf",indexPath.row+1]];
NSURL *audioURL = [NSURL URLWithString:fileName];
NSData *audioData = [NSData dataWithContentsOfURL:audioURL];
NSError *error;
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
_audioPlayer.delegate = self;
[_audioPlayer play];
}
Change this line:
NSURL *audioURL = [NSURL URLWithString:fileName];
to this:
NSURL *audioURL = [NSURL fileURLWithPath:fileName isDirectory:NO];
And then just do:
if(_audioPlayer == nil)
{
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
}
else
{
_audioPlayer = [self.audioAlert initWithContentsOfURL:audioURL error:nil];
}
To start out, the best way to declare a files path is this
- (NSString *)docsdir {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
}
in your header, declareNSString *Path;
then, declare the path like this when the view loads
Path = [[self docsdir]stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.caf",indexPath.row+1]];
if (![[NSFileManager defaultManager]fileExistsAtPath:Path]) {
[[NSFileManager defaultManager]copyItemAtPath:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:#"%d",indexPath.row+1] ofType:#"caf"] toPath:Path error:nil];
}
now to play it, do this
AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:Path] error:&error];
player.delegate = self;
[player play];

Resources