Objective C - Recording Audio Stream - objective-c

I'm looking for a solution to record an audio stream to a file. I can get audio to play but I'm struggling to figure out how to record/save to file what is playing.
A nudge in the right direction would be greatly appreciated.
Player code thus far:
#interface ViewControllerPlayer ()
#end
#implementation ViewControllerPlayer
#synthesize receivedStreamReferenceNumber;
- (void)convertData:(NSData *) data {
NSString *urlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString:urlString];
[self loadPlayer:url];
}
- (void) loadPlayer:(NSURL *) url {
audioPlayer = [AVPlayer playerWithURL:url];
[audioPlayer play];
}
- (void) start {
NSLog(#"%#", receivedStreamReferenceNumber);
NSString *urlHalf = #"http://getstreamurl.php?KeyRef=";
NSMutableString *mutableUrlString = [NSMutableString stringWithFormat:#"%#%#", urlHalf, receivedStreamReferenceNumber];
NSURL *url = [NSURL URLWithString: mutableUrlString];
NSData *data = [NSData dataWithContentsOfURL:url];
[self convertData:data];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self start];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
EDIT:
I've incorporated the following code... but i'm struggling to tie it all together. The following should create a file that the recorded stream audio is saved to. I suppose i've got to tell the AVRecorder to listen to the AVPlayer some how? Again -- help will be greatly appreciated:
- (void)viewDidLoad
{
[super viewDidLoad];
[stopButton setEnabled:YES];
[playButton setEnabled:YES];
// Set the audio file
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"xxx.mp3",
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:nil];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
}

Related

How to save AVAudioFile to document directory?

I want to save AVAudioFile to document directory with NSDictionary. Can anyone help me?
AVAudioFile *audiofile=[[AVAudioFile alloc] initForWriting:destinationURL settings:settings error:&error];
save this audio file to document directory...
Path to the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
Saving the audio file to the documents directory:
BOOL status = [NSDictionary writeToFile:filePath atomically:YES];
if(status){
NSLog(#"File write successfully");
}
- (NSString *) dateString
{
// return a formatted string for a file name
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"ddMMMYY_hhmmssa";
return [[formatter stringFromDate:[NSDate date]]stringByAppendingString:#".aif"];
}
It saves below as in Documents
23Aug16_044104PM.aif
Why we save above like is we can differenciate the previous one next one by time.So we can't confuse now.
ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController<AVAudioSessionDelegate,AVAudioRecorderDelegate, AVAudioPlayerDelegate>
{
NSURL *temporaryRecFile;
AVAudioRecorder *recorder;
AVAudioPlayer *player;
}
- (IBAction)actionRecordAudion:(id)sender;
- (IBAction)actionPlayAudio:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
[recorder setDelegate:self];
}
- (IBAction)actionRecordAudion:(id)sender
{
NSError *error;
// Recording settings
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue: [NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[settings setValue: [NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
[settings setValue: [NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
[settings setValue: [NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[settings setValue: [NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[settings setValue: [NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
[settings setValue: [NSNumber numberWithInt: AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
NSArray *searchPaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath_ = [searchPaths objectAtIndex: 0];
NSString *pathToSave = [documentPath_ stringByAppendingPathComponent:[self dateString]];
NSLog(#"the path is %#",pathToSave);
// File URL
NSURL *url = [NSURL fileURLWithPath:pathToSave];//FILEPATH];
//Save recording path to preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setURL:url forKey:#"Test1"];
[prefs synchronize];
// Create recorder
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
[recorder prepareToRecord];
[recorder record];
}
- (IBAction)actionPlayAudio:(id)sender
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
//Load recording path from preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
temporaryRecFile = [prefs URLForKey:#"Test1"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:temporaryRecFile error:nil];
player.delegate = self;
[player setNumberOfLoops:0];
player.volume = 1;
[player prepareToPlay];
[player play];
}
Record and Save Audio Permanently
Record Audio File and save Locally
Just now I tried the below code with iPhone 4s and it works perfectly.
AudioViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface AudioViewController : UIViewController<AVAudioSessionDelegate,AVAudioRecorderDelegate,AVAudioPlayerDelegate>
- (IBAction)actionRecordAudio:(id)sender;
- (IBAction)actionPlayAudio:(id)sender;
- (IBAction)actionStopAudio:(id)sender;
#property (strong, nonatomic) AVAudioRecorder *audioRecorder;
#property (strong, nonatomic) AVAudioPlayer *audioPlayer;
#end
AudioViewController.m
#import "AudioViewController.h"
#interface AudioViewController ()
#end
#implementation AudioViewController
#synthesize audioPlayer,audioRecorder;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:#"sound.caf"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0],
AVSampleRateKey,
nil];
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
audioRecorder = [[AVAudioRecorder alloc]initWithURL:soundFileURL settings:recordSettings error:&error];
if (error)
{
NSLog(#"error: %#", [error localizedDescription]);
}
else {
[audioRecorder prepareToRecord];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)actionRecordAudio:(id)sender
{
if (!audioRecorder.recording)
{
[audioRecorder record];
}
}
- (IBAction)actionPlayAudio:(id)sender
{
if (audioRecorder.recording)
{
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:audioRecorder.url
error:&error];
audioPlayer.delegate = self;
if (error)
NSLog(#"Error: %#",
[error localizedDescription]);
else
[audioPlayer play];
}
}
- (IBAction)actionStopAudio:(id)sender
{
if (audioRecorder.recording)
{
[audioRecorder stop];
}
else if (audioPlayer.playing) {
[audioPlayer stop];
}
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
}
-(void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
NSLog(#"Decode Error occurred");
}
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
}
-(void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error
{
NSLog(#"Encode Error occurred");
}
#end
Here is source

How do I play a video from Cloudkit on tvOS?

I have a problem i have been trying to solve for a day and i tired of beating my head aaginst the wall. Anyone know how to do this?
Number 1 Works Great
Works Great
- (void) viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://techslides.com/demos/sample-videos/small.mp4"];
AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:url];
self.player = avPlayer;
[self.player play];
}
Does not work
- (void) viewDidLoad {
[super viewDidLoad];
CKAsset *asset = record[#"VideoFile"];
AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:asset.fileURL];
self.player = avPlayer;
[self.player play];
}
Does not work
- (void) viewDidLoad {
[super viewDidLoad];
CKAsset *asset = record[#"VideoFile"];
NSString *fileName = record[#"videoFileKey"];
NSData *data = [NSData dataWithContentsOfURL:asset.fileURL];
NSString *cachesDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [cachesDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp4", fileName]];
[data writeToFile:path atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSURL *url = [NSURL URLWithString:path];
AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:url];
self.player = avPlayer;
[self.player play];
}
}

AVAudioPlayer breaking video capture

In one of the views of my app there's a button. When pressed it is supposed to begin taking a video, trigger a sound file to start, and hide itself from view while unhiding another button. The second button is supposed to stop the video recording and make it save. Here's the code I have for the video recording, which initially worked with no problems:
in viewDidLoad:
finishButton.hidden = TRUE;
session = [[AVCaptureSession alloc] init];
movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
NSError *error;
AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self cameraWithPosition:AVCaptureDevicePositionFront] error:&error];
if (videoInput)
{
[session addInput:videoInput];
}
AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *audioError = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&audioError];
if (audioInput)
{
[session addInput:audioInput];
}
Float64 TotalSeconds = 35; //Total seconds
int32_t preferredTimeScale = 30; //Frames per second
CMTime maxDuration = CMTimeMakeWithSeconds(TotalSeconds, preferredTimeScale);
movieFileOutput.maxRecordedDuration = maxDuration;
movieFileOutput.minFreeDiskSpaceLimit = 1024 * 1024;
if ([session canAddOutput:movieFileOutput])
[session addOutput:movieFileOutput];
[session setSessionPreset:AVCaptureSessionPresetMedium];
if ([session canSetSessionPreset:AVCaptureSessionPreset640x480]) //Check size based configs are supported before setting them
[session setSessionPreset:AVCaptureSessionPreset640x480];
[self cameraSetOutputProperties];
[session startRunning];
and for the button:
-(IBAction)start:(id)sender
{
startButton.hidden = TRUE;
finishButton.hidden = FALSE;
//Create temporary URL to record to
NSString *outputPath = [[NSString alloc] initWithFormat:#"%#%#", NSTemporaryDirectory(), #"output.mov"];
self.outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:outputPath])
{
NSError *error;
if ([fileManager removeItemAtPath:outputPath error:&error] == NO)
{
//Error - handle if required
}
}
//Start recording
[movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];
finally, under the last button:
[movieFileOutput stopRecording];
and here's the code to save the video:
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections
error:(NSError *)error
{
NSLog(#"didFinishRecordingToOutputFileAtURL - enter");
BOOL RecordedSuccessfully = YES;
if ([error code] != noErr)
{
// A problem occurred: Find out if the recording was successful.
id value = [[error userInfo] objectForKey:AVErrorRecordingSuccessfullyFinishedKey];
if (value)
{
RecordedSuccessfully = [value boolValue];
}
}
if (RecordedSuccessfully)
{
//----- RECORDED SUCESSFULLY -----
NSLog(#"didFinishRecordingToOutputFileAtURL - success");
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:outputURL
completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error)
{
}
}];
}
}
}
All of this was working just fine. Then I added a few lines so that a song file would play when the start button was pressed.
in viewDidLoad:
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/Song.aiff", [[NSBundle mainBundle] resourcePath]]];
NSError *audioFileError;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&audioFileError];
player.numberOfLoops = 0;
[self.player prepareToPlay];
and under the start button:
if (player == nil)
NSLog(#"Audio file could not be played");
else
[player play];
Now when the start button is pressed the song plays with no problems, but the video capture is messed up. Before adding the AVAudioPlayer stuff I would get the "didFinishRecordingToOutputFileAtURL - enter" and "didFinishRecordingToOutputFileAtURL - success" logs when I pressed the finish button, and now I get the first log as soon as I press the start button, nothing happens when I press the finish button, and no video is recorded. If I comment out the lines that make the song play then the video capture works just fine again. Any ideas what's going on here?
- (void)setupAudioSession
{
static BOOL audioSessionSetup = NO;
if (audioSessionSetup)
{
return;
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error: nil];
UInt32 doSetProperty = 1;
AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doSetProperty), &doSetProperty);
[[AVAudioSession sharedInstance] setActive: YES error: nil];
audioSessionSetup = YES;
}
- (void)playAudio
{
[self setupAudioSession];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"btnClick" ofType:#"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[fileURL release];
self.audioPlayer = newPlayer;
[newPlayer release];
[audioPlayer setDelegate:self];
[audioPlayer prepareToPlay];
audioPlayer.volume=1.0;
[audioPlayer play];
}
NOTE: Add the framework: AudioToolbox.framework.
#import <AudioToolbox/AudioServices.h>

What should I do to call audioPlayerDidFinishPlaying:

I wrote this source program . But I can't call audioPlayerDidFinishPlaying: method.
After playing the sound, which crashes by "exc_bad_access" error after a few seconds.
.h file
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface SecondViewController : UIViewController<
AVAudioPlayerDelegate>{
AVAudioPlayer *aPlayer;
}
#end
.m file
-(void)playSound{
NSString *soundName = #"red";
NSError *error = nil;
NSURL *soundUrl = [[NSBundle mainBundle] URLForResource:soundName withExtension:#"mp3"];
aPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:&error];
if (error != nil) {
NSLog(#"audio_player initialized error :(%#)",[error localizedDescription]);
[aPlayer release];
error=nil;
return;
}
NSLog(#"player Ok!");
aPlayer.delegate = self;
[aPlayer prepareToPlay];
aPlayer.volume=1.0f;
[aPlayer play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[player release];
}
This is what I use that works perfectly, it should help you.
-(void)playSound{
NSString *name = [[NSString alloc] initWithFormat:#"red"];
NSString *source = [[NSBundle mainBundle] pathForResource:name ofType:#"mp3"];
if (data) {
[data stop];
data = nil;
}
data=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: source] error:NULL];
data.delegate = self;
[data play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)data successfully:(BOOL)flag{
NSLog(#"my log");
[data release];
}

iOS 4.3 crashes when uploading video

I have an iPhone app that uploads images and video to a web service using ASIHTTPRequest. Everything works great on devices running iOS 5, but crashes on 4.3 and below devices after returning from the UIImagePickerController. The video is compressed bu=y the picker, then the app crashes. Below is the code from the -(void)imagePickerController: didFinishPickingMediaWithInfo: method, and also from the method that post the video to the server and a method that captures an image from the video to use as a thumbnail. Any ideas on what's causing the crashes in 4.3?
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([self.mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
// Get asset to use for orientation determination
AVAsset *myAsset = [AVAsset assetWithURL:videoURL];
self.videoOrientation = [self UIInterfaceOrientationToString:[self orientationForTrack:myAsset]];
UIImage *videoThumbnail = [self getVideoThumbnailFromAVAsset:myAsset];
self.photoImageView.image = videoThumbnail;
self.videoData = [[NSMutableData alloc]initWithContentsOfURL:videoURL];
}
[self dismissModalViewControllerAnimated:YES];
}
-(UIImage*)getVideoThumbnailFromAVAsset:(AVAsset *)myAsset {
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:myAsset];
Float64 durationSeconds = CMTimeGetSeconds([myAsset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
NSError *error = nil;
CMTime actualTime;
UIImage *myImage;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];
if (halfWayImage != NULL) {
myImage = [UIImage imageWithCGImage:halfWayImage];
CGImageRelease(halfWayImage);
}
return myImage;
}
- (void)postMessage:(id)sender {
self.uploadButton.enabled = NO;
[self.descriptionTextField resignFirstResponder];
[self.titleTextField resignFirstResponder];
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSString *sessionKey = [settings stringForKey: #"sessionKey"];
// build URL for request
NSString *baseURL;
NSString *endPoint;
// code here that creates the url component strings baseURL and endPoint
NSString *fullURL = [NSString stringWithFormat:#"%#%#", baseURL, endPoint];
NSURL *url = [NSURL URLWithString:fullURL];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
request.postFormat = ASIMultipartFormDataPostFormat;
NSString *teamIDStr = [NSString stringWithFormat:#"%d",[self.teamID intValue]];
[request setPostValue:sessionKey forKey:#"sessionKey"];
[request setPostValue:teamIDStr forKey:#"TeamID"];
[request setPostValue:titleTextField.text forKey:#"lessonName"];
[request setPostValue:descriptionTextField.text forKey:#"lessonDesc"];
[request setPostValue:self.videoOrientation forKey:#"videoOrientation"];
//create video file name
NSDate *date1=[NSDate date];
NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
[formatter1 setDateFormat:#"hhmm"];
NSString *valuestr = [formatter1 stringFromDate:date1];
NSString *moviename = [NSString stringWithFormat:#"video_%#.mov", valuestr];
[request setData:self.videoData withFileName:moviename andContentType:#"video/quicktime" forKey:#"file1.mov"];
[request setUploadProgressDelegate:self.progressBar];
[request setShowAccurateProgress:YES];
self.progressBar.hidden = NO;
[request setDelegate:self];
[request setTimeOutSeconds:600];
[request startAsynchronous];
}
SImple answer to this issue: The AVAsset class method
+ (id)assetWithURL:(NSURL *)URL
is not available before iOS 5.0. You must use the concrete subclass AVURLAsset to instantiate an AVAsset for iOS 4.0 and 4.3, using its class method
+ (AVURLAsset *)URLAssetWithURL:(NSURL *)URL options:(NSDictionary *)options