Take a picture in iOS without UIImagePicker and without preview it - objective-c

Do you know any way / method to take a photo in iOS and saving it to camera Roll only with a simple button pressure without showing any preview?
I already know how to show the camera view but it show the preview of the image and the user need to click the take photo button to take the photo.
In few Words: the user click the button, the picture is taken, without previews nor double checks to take / save the photo.
I already found the takePicture method of UIIMagePickerController Class http://developer.apple.com/library/ios/documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html#//apple_ref/occ/instm/UIImagePickerController/takePicture

Set the showsCameraControls-Property to NO.
poc = [[UIImagePickerController alloc] init];
[poc setTitle:#"Take a photo."];
[poc setDelegate:self];
[poc setSourceType:UIImagePickerControllerSourceTypeCamera];
poc.showsCameraControls = NO;
You also have to add your own Controls as a custom view on the top of poc.view. But that is very simple and you can add your own UI-style by that way.
You receive the image-data as usually within the imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:
To take the photo, you call
[poc takePicture];
from your custom button.
Hope, that works for you.

Assuming you want a point-and-shoot method, you can create an AVSession and just call the UIImageWriteToSavedPhotosAlbum method.
Here is a link that goes into that exact process: http://www.musicalgeometry.com/?p=1297
It's also worth noting that your users need to have given the app access to their camera roll or you may experience issues saving the images.

You need to design your own custom preview according to your size, on capture button pressed and call buttonPressed method and do stuff what you want
(void)buttonPressed:(UIButton *)sender {
NSLog(#" Capture Clicked");
[self.imagePicker takePicture];
//[NSTimer scheduledTimerWithTimeInterval:3.0f target:self
selector:#selector(timerFired:) userInfo:nil repeats:NO];
}

following is code that will take photo without showing preview screen. when i tried the accepted answer, which uses UIImagePickerController, the preview screen showed, then auto disappeared. with the code below, user taps 'takePhoto' button, and the devices takes photo with zero change to UI (in my app, i add a green check mark next to take photo button). the code below is from apple https://developer.apple.com/LIBRARY/IOS/samplecode/AVCam/Introduction/Intro.html with the 'extra functions' (that do not relate to taking still photo) commented out. thank you incmiko for suggesting this code in your answer iOS take photo from camera without modalViewController.
updating code, 26 mar 2015:
to trigger snap photo:
[self snapStillImage:sender];
in .h file:
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
// include code below in header file, after #import and before #interface
// avfoundation copy paste code
static void * CapturingStillImageContext = &CapturingStillImageContext;
static void * RecordingContext = &RecordingContext;
static void * SessionRunningAndDeviceAuthorizedContext = &SessionRunningAndDeviceAuthorizedContext;
// avfoundation, include code below after #interface
// avf - Session management.
#property (nonatomic) dispatch_queue_t sessionQueue; // Communicate with the session and other session objects on this queue.
#property (nonatomic) AVCaptureSession *session;
#property (nonatomic) AVCaptureDeviceInput *videoDeviceInput;
#property (nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
#property (nonatomic) AVCaptureStillImageOutput *stillImageOutput;
// avf - Utilities.
#property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
#property (nonatomic, getter = isDeviceAuthorized) BOOL deviceAuthorized;
#property (nonatomic, readonly, getter = isSessionRunningAndDeviceAuthorized) BOOL sessionRunningAndDeviceAuthorized;
#property (nonatomic) BOOL lockInterfaceRotation;
#property (nonatomic) id runtimeErrorHandlingObserver;
in .m file:
#pragma mark - AV Foundation
- (BOOL)isSessionRunningAndDeviceAuthorized
{
return [[self session] isRunning] && [self isDeviceAuthorized];
}
+ (NSSet *)keyPathsForValuesAffectingSessionRunningAndDeviceAuthorized
{
return [NSSet setWithObjects:#"session.running", #"deviceAuthorized", nil];
}
// call following method from viewDidLoad
- (void)CreateAVCaptureSession
{
// Create the AVCaptureSession
AVCaptureSession *session = [[AVCaptureSession alloc] init];
[self setSession:session];
// Check for device authorization
[self checkDeviceAuthorizationStatus];
// In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
// Why not do all of this on the main queue?
// -[AVCaptureSession startRunning] is a blocking call which can take a long time. We dispatch session setup to the sessionQueue so that the main queue isn't blocked (which keeps the UI responsive).
dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
[self setSessionQueue:sessionQueue];
dispatch_async(sessionQueue, ^{
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
NSError *error = nil;
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:videoDeviceInput])
{
[session addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
dispatch_async(dispatch_get_main_queue(), ^{
// Why are we dispatching this to the main queue?
// Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread.
// Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayer’s connection with other session manipulation.
});
}
/* AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:audioDeviceInput])
{
[session addInput:audioDeviceInput];
}
*/
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieFileOutput])
{
[session addOutput:movieFileOutput];
AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
if ([connection isVideoStabilizationSupported])
[connection setEnablesVideoStabilizationWhenAvailable:YES];
[self setMovieFileOutput:movieFileOutput];
}
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([session canAddOutput:stillImageOutput])
{
[stillImageOutput setOutputSettings:#{AVVideoCodecKey : AVVideoCodecJPEG}];
[session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
});
}
// call method below from viewWilAppear
- (void)AVFoundationStartSession
{
dispatch_async([self sessionQueue], ^{
[self addObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext];
[self addObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
[self addObserver:self forKeyPath:#"movieFileOutput.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
__weak ViewController *weakSelf = self;
[self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock:^(NSNotification *note) {
ViewController *strongSelf = weakSelf;
dispatch_async([strongSelf sessionQueue], ^{
// Manually restarting the session since it must have been stopped due to an error.
[[strongSelf session] startRunning];
});
}]];
[[self session] startRunning];
});
}
// call method below from viewDidDisappear
- (void)AVFoundationStopSession
{
dispatch_async([self sessionQueue], ^{
[[self session] stopRunning];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
[[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]];
[self removeObserver:self forKeyPath:#"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext];
[self removeObserver:self forKeyPath:#"stillImageOutput.capturingStillImage" context:CapturingStillImageContext];
[self removeObserver:self forKeyPath:#"movieFileOutput.recording" context:RecordingContext];
});
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (BOOL)shouldAutorotate
{
// Disable autorotation of the interface when recording is in progress.
return ![self lockInterfaceRotation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// [[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == CapturingStillImageContext)
{
BOOL isCapturingStillImage = [change[NSKeyValueChangeNewKey] boolValue];
if (isCapturingStillImage)
{
[self runStillImageCaptureAnimation];
}
}
else if (context == RecordingContext)
{
BOOL isRecording = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRecording)
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setTitle:NSLocalizedString(#"Stop", #"Recording button stop title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setTitle:NSLocalizedString(#"Record", #"Recording button record title") forState:UIControlStateNormal];
// [[self recordButton] setEnabled:YES];
}
});
}
else if (context == SessionRunningAndDeviceAuthorizedContext)
{
BOOL isRunning = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRunning)
{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
}
else
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
}
});
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark Actions
- (IBAction)toggleMovieRecording:(id)sender
{
// [[self recordButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
if (![[self movieFileOutput] isRecording])
{
[self setLockInterfaceRotation:YES];
if ([[UIDevice currentDevice] isMultitaskingSupported])
{
// Setup background task. This is needed because the captureOutput:didFinishRecordingToOutputFileAtURL: callback is not received until AVCam returns to the foreground unless you request background execution time. This also ensures that there will be time to write the file to the assets library when AVCam is backgrounded. To conclude this background execution, -endBackgroundTask is called in -recorder:recordingDidFinishToOutputFileURL:error: after the recorded file has been saved.
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]];
}
// Update the orientation on the movie file output video connection before starting recording.
// [[[self movieFileOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Turning OFF flash for video recording
[ViewController setFlashMode:AVCaptureFlashModeOff forDevice:[[self videoDeviceInput] device]];
// Start recording to a temporary file.
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[#"movie" stringByAppendingPathExtension:#"mov"]];
[[self movieFileOutput] startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
}
else
{
[[self movieFileOutput] stopRecording];
}
});
}
- (IBAction)changeCamera:(id)sender
{
// [[self cameraButton] setEnabled:NO];
// [[self recordButton] setEnabled:NO];
// [[self stillButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *currentVideoDevice = [[self videoDeviceInput] device];
AVCaptureDevicePosition preferredPosition = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = [currentVideoDevice position];
switch (currentPosition)
{
case AVCaptureDevicePositionUnspecified:
preferredPosition = AVCaptureDevicePositionBack;
break;
case AVCaptureDevicePositionBack:
preferredPosition = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosition = AVCaptureDevicePositionBack;
break;
}
AVCaptureDevice *videoDevice = [ViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:preferredPosition];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
[[self session] beginConfiguration];
[[self session] removeInput:[self videoDeviceInput]];
if ([[self session] canAddInput:videoDeviceInput])
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:videoDevice];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:videoDevice];
[[self session] addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
}
else
{
[[self session] addInput:[self videoDeviceInput]];
}
[[self session] commitConfiguration];
dispatch_async(dispatch_get_main_queue(), ^{
// [[self cameraButton] setEnabled:YES];
// [[self recordButton] setEnabled:YES];
// [[self stillButton] setEnabled:YES];
});
});
}
- (IBAction)snapStillImage:(id)sender
{
dispatch_async([self sessionQueue], ^{
// Update the orientation on the still image output video connection before capturing.
// [[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Flash set to Auto for Still Capture
[ViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[[self videoDeviceInput] device]];
// Capture a still image.
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
// do someting good with saved image
[self saveImageToParse:image];
}
}];
});
}
- (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer
{
// CGPoint devicePoint = [(AVCaptureVideoPreviewLayer *)[[self previewView] layer] captureDevicePointOfInterestForPoint:[gestureRecognizer locationInView:[gestureRecognizer view]]];
// [self focusWithMode:AVCaptureFocusModeAutoFocus exposeWithMode:AVCaptureExposureModeAutoExpose atDevicePoint:devicePoint monitorSubjectAreaChange:YES];
}
- (void)subjectAreaDidChange:(NSNotification *)notification
{
CGPoint devicePoint = CGPointMake(.5, .5);
[self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
}
#pragma mark File Output Delegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
if (error)
NSLog(#"%#", error);
[self setLockInterfaceRotation:NO];
// Note the backgroundRecordingID for use in the ALAssetsLibrary completion handler to end the background task associated with this recording. This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's -isRecording is back to NO — which happens sometime after this method returns.
UIBackgroundTaskIdentifier backgroundRecordingID = [self backgroundRecordingID];
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
if (error)
NSLog(#"%#", error);
[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];
if (backgroundRecordingID != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:backgroundRecordingID];
}];
}
#pragma mark Device Configuration
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
{
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *device = [[self videoDeviceInput] device];
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:focusMode])
{
[device setFocusMode:focusMode];
[device setFocusPointOfInterest:point];
}
if ([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:exposureMode])
{
[device setExposureMode:exposureMode];
[device setExposurePointOfInterest:point];
}
[device setSubjectAreaChangeMonitoringEnabled:monitorSubjectAreaChange];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
});
}
+ (void)setFlashMode:(AVCaptureFlashMode)flashMode forDevice:(AVCaptureDevice *)device
{
if ([device hasFlash] && [device isFlashModeSupported:flashMode])
{
NSError *error = nil;
if ([device lockForConfiguration:&error])
{
[device setFlashMode:flashMode];
[device unlockForConfiguration];
}
else
{
NSLog(#"%#", error);
}
}
}
+ (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = [devices firstObject];
for (AVCaptureDevice *device in devices)
{
if ([device position] == position)
{
captureDevice = device;
break;
}
}
return captureDevice;
}
#pragma mark UI
- (void)runStillImageCaptureAnimation
{
/*
dispatch_async(dispatch_get_main_queue(), ^{
[[[self previewView] layer] setOpacity:0.0];
[UIView animateWithDuration:.25 animations:^{
[[[self previewView] layer] setOpacity:1.0];
}];
});
*/
}
- (void)checkDeviceAuthorizationStatus
{
NSString *mediaType = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if (granted)
{
//Granted access to mediaType
[self setDeviceAuthorized:YES];
}
else
{
//Not granted access to mediaType
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:#"AVCam!"
message:#"AVCam doesn't have permission to use Camera, please change privacy settings"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
[self setDeviceAuthorized:NO];
});
}
}];
}

Related

Unable to call up my video files using AVFoundation

I'm having difficulty playing back video that I've recently recorded in a hybrid image/video camera akin to Snapchat (e.g. tap to take a photo, press and hold to record a video, playback on button release).
I'm currently saving the video file to NSFileManager. When I log it out I do verify that something is being saved but can't inspect the file because it has to be tested on the phone.
The file path when I log it out:
file:///var/mobile/Containers/Data/Application/7D86B14D-ACFF-4494-AD61-CBBD32DCA7A5/Documents/test.mov
When I go to load the asset from the file manager I log out an error that it can't open the files. I've only just started working with AVFoundation so not sure what some of the issues/considerations are when debugging. Any insight would be greatly appreciated, thank you!
Referenced tutorial
Referenced github repository
Referenced code:
PlayerView.h (reference)
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface PlayerView : UIView
#property (nonatomic) AVPlayer *player;
- (void)setPlayer:(AVPlayer *)player;
#end
PlayerView.m (reference)
#import "PlayerView.h"
#implementation PlayerView
+ (Class)layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer *)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *)player {
[(AVPlayerLayer *)[self layer] setPlayer:player];
}
#end
HybridCameraViewController.h (reference)
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "PlayerView.h"
#interface HybridCameraViewController : UIViewController
#property UIButton *button;
#property UIButton *saveButton;
#property UIImageView *previewView;
#define VIDEO_FILE #"test.mov"
#end
HybridCameraViewController.m (reference)
#import "HybridCameraViewController.h"
static const NSString *ItemStatusContext;
#class PlayerView;
#interface HybridCameraViewController () <AVCaptureFileOutputRecordingDelegate>
#end
#implementation HybridCameraViewController
AVCaptureSession *session;
AVCaptureStillImageOutput *imageOutput;
AVCaptureMovieFileOutput *movieOutput;
AVCaptureConnection *videoConnection;
AVPlayer *player;
AVPlayerItem *playerItem;
PlayerView *playerView;
- (void)viewDidLoad {
[super viewDidLoad];
[self testDevices];
self.view.backgroundColor = [UIColor blackColor];
//Image preview
self.previewView = [[UIImageView alloc]initWithFrame:self.view.frame];
self.previewView.backgroundColor = [UIColor whiteColor];
self.previewView.contentMode = UIViewContentModeScaleAspectFill;
self.previewView.hidden = YES;
[self.view addSubview:self.previewView];
//Playerback setup
playerView = [[PlayerView alloc]initWithFrame:self.view.frame];
playerView.backgroundColor = [UIColor redColor];
[self syncUI];
//Buttons
self.button = [self createButtonWithTitle:#"REC" chooseColor:[UIColor redColor]];
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPressGesture:)];
[self.button addGestureRecognizer:longPressRecognizer];
[self.button addTarget:self action:#selector(captureImage) forControlEvents:UIControlEventTouchUpInside];
self.saveButton = [self createSaveButton];
[self.saveButton addTarget:self action:#selector(saveActions) forControlEvents:UIControlEventTouchUpInside];
}
- (void)viewWillAppear:(BOOL)animated {
//Tests
[self initializeAVItems];
NSLog(#"%#", videoConnection);
NSLog(#"%#", imageOutput.connections);
NSLog(#"%#", imageOutput.description.debugDescription);
}
#pragma mark - AV initialization
- (void)initializeAVItems {
//Start session, input
session = [AVCaptureSession new];
if ([session canSetSessionPreset:AVCaptureSessionPresetHigh]) {
session.sessionPreset = AVCaptureSessionPresetHigh;
}
AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
if ([session canAddInput:deviceInput]) {
[session addInput:deviceInput];
} else {
NSLog(#"%#", error);
}
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:session];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//Layer preview
CALayer *viewLayer = [[self view] layer];
[viewLayer setMasksToBounds:YES];
CGRect frame = self.view.frame;
[previewLayer setFrame:frame];
[viewLayer insertSublayer:previewLayer atIndex:0];
//Image Output
imageOutput = [AVCaptureStillImageOutput new];
NSDictionary *imageOutputSettings = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
imageOutput.outputSettings = imageOutputSettings;
//Video Output
movieOutput = [AVCaptureMovieFileOutput new];
[session addOutput:movieOutput];
[session addOutput:imageOutput];
[session startRunning];
}
- (void)testDevices {
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice *device in devices) {
NSLog(#"Device name: %#", [device localizedName]);
if ([device hasMediaType:AVMediaTypeVideo]) {
if ([device position] == AVCaptureDevicePositionBack) {
NSLog(#"Device position : back");
}
else {
NSLog(#"Device position : front");
}
}
}
}
#pragma mark - Image capture
- (void)captureImage {
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in imageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"Requesting capture from: %#", imageOutput);
[imageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:imageData];
self.previewView.image = image;
self.previewView.hidden = NO;
}
}];
[self saveButtonFlyIn:self.saveButton];
}
#pragma mark - Video capture
- (void)captureVideo {
NSLog(#"%#", movieOutput.connections);
[[NSFileManager defaultManager] removeItemAtURL:[self outputURL] error:nil];
videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:movieOutput.connections];
[movieOutput startRecordingToOutputFileURL:[self outputURL] recordingDelegate:self];
}
- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections {
for (AVCaptureConnection *connection in connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:mediaType]) {
return connection;
}
}
}
return nil;
}
#pragma mark - Show Last Recording
- (void)presentRecording {
NSLog(#"unplaying");
NSLog(#"%#",[self outputURL]);
}
- (IBAction)loadAssetFromFile {
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[self outputURL] options:nil];
NSString *tracksKey = #"tracks";
[asset loadValuesAsynchronouslyForKeys:#[tracksKey] completionHandler:^{
dispatch_async(dispatch_get_main_queue(),^{
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey
error:&error];
if (status == AVKeyValueStatusLoaded) {
playerItem = [AVPlayerItem playerItemWithAsset:asset];
[playerItem addObserver:self forKeyPath:#"status"
options:NSKeyValueObservingOptionInitial
context:&ItemStatusContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:playerItem];
player = [AVPlayer playerWithPlayerItem:playerItem];
[playerView setPlayer:player];
}
else {
NSLog(#"The asset's tracks were not loaded:\n%#", [error localizedDescription]);
}
});
}];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == &ItemStatusContext) {
dispatch_async(dispatch_get_main_queue(),^{
[self syncUI];
});
return;
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[player seekToTime:kCMTimeZero];
}
- (void)syncUI {
if ((player.currentItem != nil) &&
([player.currentItem status] == AVPlayerItemStatusReadyToPlay)) {
self.button.enabled = YES;
}
else {
self.button.enabled = NO;
}
}
#pragma mark - AVCaptureFileOutputRecordingDelegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
if (!error) {
NSLog(#"Success!!!!");
} else {
NSLog(#"Error: %#", [error localizedDescription]);
}
}
#pragma mark - Recoding Destination URL
- (NSURL *)outputURL {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:VIDEO_FILE];
return [NSURL fileURLWithPath:filePath];
}
#pragma mark - Buttons
- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSLog(#"Press");
self.button.backgroundColor = [UIColor greenColor];
[self captureVideo];
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
NSLog(#"Unpress");
self.button.backgroundColor = [UIColor redColor];
[movieOutput stopRecording];
[self performSelector:#selector(loadAssetFromFile)];
[player play];
}
}
- (UIButton *)createButtonWithTitle:(NSString *)title chooseColor:(UIColor *)color {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(self.view.center.x, self.view.frame.size.height - 100, 85, 85)];
button.layer.cornerRadius = button.bounds.size.width / 2;
button.backgroundColor = color;
button.tintColor = [UIColor whiteColor];
[self.view addSubview:button];
return button;
}
- (UIButton *)createSaveButton {
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(self.view.frame.size.width, self.view.frame.size.height - 100, 85, 85)];
button.layer.cornerRadius = button.bounds.size.width / 2;
button.backgroundColor = [UIColor greenColor];
button.tintColor = [UIColor whiteColor];
button.userInteractionEnabled = YES;
[button setTitle:#"save" forState:UIControlStateNormal];
[self.view addSubview:button];
return button;
}
- (void)saveButtonFlyIn:(UIButton *)button {
CGRect movement = button.frame;
movement.origin.x = self.view.frame.size.width - 100;
[UIView animateWithDuration:0.2 animations:^{
button.frame = movement;
}];
}
- (void)saveButtonFlyOut:(UIButton *)button {
CGRect movement = button.frame;
movement.origin.x = self.view.frame.size.width;
[UIView animateWithDuration:0.2 animations:^{
button.frame = movement;
}];
}
#pragma mark - Save actions
- (void)saveActions {
[self saveButtonFlyOut:self.saveButton];
self.previewView.image = nil;
self.previewView.hidden = YES;
}
#end
The approach was overly complex. Where you went wrong was 1) not loading the url properly and 2) not adding the 'player layer' sublayer to the main view.
Here is an example of successful playback:
//TestURL
self.videoURL = [NSURL URLWithString:(NSString *)[self.selectedVideo objectForKey:#"source"]];
//Video
self.player = [AVPlayer playerWithPlayerItem:[[AVPlayerItem alloc]initWithAsset:[AVAsset assetWithURL:self.videoURL]]];
//Player layer
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height / 3);
[self.view.layer addSublayer:self.playerLayer];
[self.player play];
All you would need to do is redirect the url to the one you just saved:
self.videoURL = [self outputURL];

MPMoviePlayerController doesn't work with remoteControlReceivedWithEvent

I want to allow the controls from my keyboard to work in my app. The controls use Apple's Remote Control events (beginReceivingRemoteControlEvents, endReceivingRemoteControlEvents, and remoteControlReceivedWithEvent); however I cannot seem to get this to work with MPMoviePlayerController.
I do not see any events at the start of the program, even though beginReceivingRemoteControlEvents is called at the start.
I do not see any events during the playback of a video.
I do see events after I close the video.
From the above, it seems that the audio stream of MPMoviePlayerController disables the controls. However I do not know how to change this. I tried using [moviePlayer setUseApplicationAudioSession:NO]; to change the audio to use the system session, yet it does nothing.
Here is my setup. My app delegate is a UIViewController. I set the main window's root view controller to the app delegate, add views to the view controller and in the view controller for the parts which has to do with video.
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)theIndexPath {
NSString *file = [[MGMFilesPath stringByExpandingTildeInPath] stringByAppendingPathComponent:[files objectAtIndex:[theIndexPath indexAtPosition:1]]];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
NSLog(#"%d", [self isFirstResponder]);
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:file]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
if ([moviePlayer respondsToSelector:#selector(setFullscreen:animated:)]) {
[[self view] addSubview:[moviePlayer view]];
[moviePlayer setFullscreen:YES animated:YES];
[moviePlayer play];
} else {
[moviePlayer play];
}
[fileView deselectRowAtIndexPath:theIndexPath animated:NO];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
NSLog(#"remoteControlReceivedWithEvent: %#", event);
if (event.type==UIEventTypeRemoteControl) {
if (event.subtype==UIEventSubtypeRemoteControlPlay) {
NSLog(#"Play");
} else if (event.subtype==UIEventSubtypeRemoteControlPause) {
NSLog(#"Pause");
} else if (event.subtype==UIEventSubtypeRemoteControlTogglePlayPause) {
NSLog(#"Play Pause");
}
}
}
- (void)exitedFullscreen:(NSNotification*)notification {
[[moviePlayer view] removeFromSuperview];
[moviePlayer stop];
[moviePlayer release];
moviePlayer = nil;
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)playbackFinished:(NSNotification*)theNotification {
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
NSNumber *reason = [[theNotification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
if ([reason intValue]!=MPMovieFinishReasonUserExited) {
[moviePlayer setFullscreen:NO animated:YES];
[[moviePlayer view] removeFromSuperview];
[moviePlayer stop];
[moviePlayer release];
moviePlayer = nil;
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
NSLog(#"%d", [self isFirstResponder]);
}
As you can see in the code above, I verified that it was first responder and it was, so I know it's not a first responder issue.
Can someone help me get this working?
Thanks
Apparently, MPMoviePlayerController isn't the way to go for this. What I ended up doing was using MPMoviePlayerViewController and override the remoteControlReceivedWithEvent to customize the controls. Below is my current code which I am using.
#interface MGMMoviePlayerViewController : MPMoviePlayerViewController
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
#end
#implementation MGMMoviePlayerViewController
- (void)remoteControlReceivedWithEvent:(UIEvent *)theEvent {
if (theEvent.type==UIEventTypeRemoteControl) {
if (theEvent.subtype==UIEventSubtypeRemoteControlPlay) {
[[self moviePlayer] play];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlPause) {
[[self moviePlayer] pause];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlTogglePlayPause) {
if ([[self moviePlayer] playbackState]==MPMoviePlaybackStatePlaying) {
[[self moviePlayer] pause];
} else {
[[self moviePlayer] play];
}
} else if (theEvent.subtype==UIEventSubtypeRemoteControlStop) {
[[self moviePlayer] stop];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlNextTrack) {
NSTimeInterval currentTime = [[self moviePlayer] currentPlaybackTime];
currentTime += 10;
if (currentTime>[[self moviePlayer] duration])
currentTime = [[self moviePlayer] duration];
[[self moviePlayer] setCurrentPlaybackTime:currentTime];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlPreviousTrack) {
NSTimeInterval currentTime = [[self moviePlayer] currentPlaybackTime];
currentTime -= 10;
if (currentTime<0)
currentTime = 0;
[[self moviePlayer] setCurrentPlaybackTime:currentTime];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlBeginSeekingBackward) {
[[self moviePlayer] beginSeekingBackward];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlBeginSeekingForward) {
[[self moviePlayer] beginSeekingForward];
} else if (theEvent.subtype==UIEventSubtypeRemoteControlEndSeekingBackward || theEvent.subtype==UIEventSubtypeRemoteControlEndSeekingForward) {
[[self moviePlayer] endSeeking];
}
}
}
#end
- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)theIndexPath {
NSString *file = [[MGMFilesPath stringByExpandingTildeInPath] stringByAppendingPathComponent:[files objectAtIndex:[theIndexPath indexAtPosition:1]]];
moviePlayerView = [[MGMMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:file]];
[self presentMoviePlayerViewControllerAnimated:moviePlayerView];
[[moviePlayerView moviePlayer] play];
[fileView deselectRowAtIndexPath:theIndexPath animated:NO];
}

Correctly Stoping AVAudioPlayer. Currently runs in Background

I've been strugling with this problem for quite a while.
I'm trying to make a player that contains a playlist and plays only the music files stored inside the application.
Now, i'm using AVAudioPlayer to play the mp3 files. My problem is that when i load the playlist i can't stop the previous mp3 from playing and therefor i get a mixture of sounds between the first audio and all the other audio files that i load from the playlist.
so, here is my code:
#import "MainViewController.h"
#import <Foundation/Foundation.h>
#pragma mark Audio session callbacks_______________________
#implementation MainViewController
#synthesize artworkItem;
#synthesize userMediaItemCollection;
#synthesize playBarButton;
#synthesize pauseBarButton;
#synthesize musicPlayer;
#synthesize navigationBar;
#synthesize noArtworkImage;
#synthesize backgroundColorTimer;
#synthesize nowPlayingLabel, AudFile;
#synthesize appSoundButton;
#synthesize addOrShowMusicButton;
#synthesize appSoundPlayer;
#synthesize soundFileURL;
#synthesize interruptedOnPlayback;
#synthesize playedMusicOnce;
#synthesize playing;
#pragma mark Music control________________________________
- (IBAction) playOrPauseMusic: (id)sender {
}
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
#pragma mark Application playback control_________________
- (IBAction) playAppSound: (id) sender {
// [appSoundPlayer play];
// playing = YES;
// [appSoundButton setEnabled: NO];
}
// delegate method for the audio route change alert view; follows the protocol specified
// in the UIAlertViewDelegate protocol.
- (void) alertView: routeChangeAlertView clickedButtonAtIndex: buttonIndex {
if ((NSInteger) buttonIndex == 1) {
[appSoundPlayer play];
} else {
[appSoundPlayer setCurrentTime: 0];
[appSoundButton setEnabled: YES];
}
[routeChangeAlertView release];
}
#pragma mark AV Foundation delegate methods____________
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) appSoundPlayer successfully: (BOOL) flag {
}
- (void) audioPlayerBeginInterruption: player {
}
- (void) audioPlayerEndInterruption: player {
}
#pragma mark Table view delegate methods________________
// Invoked when the user taps the Done button in the table view.
- (void) musicTableViewControllerDidFinish: (MusicTableViewController *) controller {
[self dismissModalViewControllerAnimated: YES];
}
#pragma mark Application setup____________________________
#if TARGET_IPHONE_SIMULATOR
#warning *** Simulator mode: iPod library access works only when running on a device.
#endif
//play audio 2
- (void)playAudio2:(NSString*) name type:(NSString*)type
{
[self stopAudio];
[audioPlayer stop];
[audioPlayer release];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:name
ofType:type]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
[audioPlayer play];
}
-(void)playAudio
{
[appSoundPlayer play];
}
- (void)stopAudio
{
[appSoundPlayer stop];
}
// Configure the application.
- (void) viewDidLoad {
[super viewDidLoad];
[self setPlayedMusicOnce: NO];
[self setNoArtworkImage: [UIImage imageNamed: #"no_artwork.png"]];
[self setPlayBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay
target: self
action: #selector (playOrPauseMusic:)]];
[self setPauseBarButton: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPause
target: self
action: #selector (playOrPauseMusic:)]];
[addOrShowMusicButton setTitle: NSLocalizedString (#"Add Music", #"Title for 'Add Music' button, before user has chosen some music")
forState: UIControlStateNormal];
[appSoundButton setTitle: NSLocalizedString (#"Play App Sound", #"Title for 'Play App Sound' button")
forState: UIControlStateNormal];
[nowPlayingLabel setText: NSLocalizedString (#"Instructions", #"Brief instructions to user, shown at launch")];
// Configure a timer to change the background color. The changing color represents an
// application that is doing something else while iPod music is playing.
[self setBackgroundColorTimer: [NSTimer scheduledTimerWithTimeInterval: 3.5
target: self
selector: #selector (updateBackgroundColor)
userInfo: nil
repeats: YES]];
[self setupAudioSession];
}
// Invoked by the backgroundColorTimer.
- (void) updateBackgroundColor {
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration: 3.0];
CGFloat redLevel = rand() / (float) RAND_MAX;
CGFloat greenLevel = rand() / (float) RAND_MAX;
CGFloat blueLevel = rand() / (float) RAND_MAX;
self.view.backgroundColor = [UIColor colorWithRed: redLevel
green: greenLevel
blue: blueLevel
alpha: 1.0];
[UIView commitAnimations];
}
#pragma mark Application state management_____________
- (void) didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void) viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(void) setupAudioSession
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError){/* Handle Error COndition*/}
NSError *activationError = nil;
[audioSession setActive:YES error:&activationError];
if (activationError){
/*handle error*/
}
}
// just for test , delete after
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
+(void) myClassMethod{
NSLog(#"Class Called ok");
}
- (void)dealloc {
/*
// This sample doesn't use libray change notifications; this code is here to show how
// it's done if you need it.
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] endGeneratingLibraryChangeNotifications];
*/
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer endGeneratingPlaybackNotifications];
[musicPlayer release];
[artworkItem release];
[backgroundColorTimer invalidate];
[backgroundColorTimer release];
[navigationBar release];
[noArtworkImage release];
[nowPlayingLabel release];
[pauseBarButton release];
[playBarButton release];
[soundFileURL release];
[userMediaItemCollection release];
[super dealloc];
}
I am sending the file name from my playlist to my player through
-(void) myInstanceMethod: (id)sender{
[self setupAudioSession];
[audioPlayer stop];
[audioPlayer release];
AudFile = sender;
NSLog(#"My Instance metthod called ok with item : %#", sender);
[self playAudio2:[NSString stringWithFormat:#"%#",AudFile] type:#"mp3"];
//[self setupApplicationAudio: sender];
NSLog(#"New Audfile is: %#", AudFile);
// [self setupApplicationAudio];
}
and i load my playlist from my mainviewcontroller using the UIModalTransition in the method
- (IBAction) AddMusicOrShowMusic: (id) sender {
[audioPlayer stop];
// Load the Playlist direcly
MusicTableViewController *controller = [[MusicTableViewController alloc] initWithNibName: #"MusicTableView" bundle: nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController: controller animated: YES];
[controller release];
}
As you can see when i load my playlist i tell the player to stop playing through
[audioPlayer stop];
but for some reason it failes to stop playing, therefore creating an overlap of sounds.
This is my problem which i'm trying to figure out.
Thank you
and best regards!

Can't play system sounds after capturing audio / video

I'm recoding audio/video using AVfoudnation. and I need to play a sounds, using system sounds, before I start capturing video/audio. This is working correctly the first time, but when I try to do it the second time, the system audi doesn't play. My guess is that something in the AVfoundation is not been released correctly.
In my application deletage, I have this code in the applicationDidFinishLaunching method:
VKRSAppSoundPlayer *aPlayer = [[VKRSAppSoundPlayer alloc] init];
[aPlayer addSoundWithFilename:#"sound1" andExtension:#"caf"];
self.appSoundPlayer = aPlayer;
[aPlayer release];
and also this method
- (void)playSound:(NSString *)sound
{
[appSoundPlayer playSound:sound];
}
As you can see I'm using VKRSAppSoundPlayer, which works great!
In a view, I have this code:
- (void) startSession
{
self.session = [[AVCaptureSession alloc] init];
[session beginConfiguration];
if([session canSetSessionPreset:AVCaptureSessionPreset640x480])
session.sessionPreset = AVCaptureSessionPresetMedium;
[session commitConfiguration];
CALayer *viewLayer = [videoPreviewView layer];
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
captureVideoPreviewLayer.frame = viewLayer.bounds;
[viewLayer addSublayer:captureVideoPreviewLayer];
self.videoInput = [AVCaptureDeviceInput deviceInputWithDevice:[self frontFacingCameraIfAvailable] error:nil];
self.audioInput = [AVCaptureDeviceInput deviceInputWithDevice:[self audioDevice] error:nil];
if(videoInput){
self.videoOutput = [[AVCaptureMovieFileOutput alloc] init];
[session addOutput:videoOutput];
//[videoOutput release];
if([session canAddInput:videoInput]){
//[session beginConfiguration];
[session addInput:videoInput];
}
//[videoInput release];
[session removeInput:[self audioInput]];
if([session canAddInput:audioInput]){
[session addInput:audioInput];
}
//[audioInput release];
if([session canAddInput:audioInput])
[session addInput:audioInput];
NSLog(#"startRunning!");
[session startRunning];
[self startRecording];
if(![self recordsVideo])
[self showAlertWithTitle:#"Video Recording Unavailable" msg:#"This device can't record video."];
}
}
- (void) stopSession
{
[session stopRunning];
[session release];
}
- (AVCaptureDevice *)frontFacingCameraIfAvailable
{
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
Boolean cameraFound = false;
for (AVCaptureDevice *device in videoDevices)
{
NSLog(#"1 frontFacingCameraIfAvailable %d", device.position);
if (device.position == AVCaptureDevicePositionBack){
NSLog(#"1 frontFacingCameraIfAvailable FOUND");
captureDevice = device;
cameraFound = true;
break;
}
}
if(cameraFound == false){
for (AVCaptureDevice *device in videoDevices)
{
NSLog(#"2 frontFacingCameraIfAvailable %d", device.position);
if (device.position == AVCaptureDevicePositionFront){
NSLog(#"2 frontFacingCameraIfAvailable FOUND");
captureDevice = device;
break;
}
}
}
return captureDevice;
}
- (AVCaptureDevice *) audioDevice
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
if ([devices count] > 0) {
return [devices objectAtIndex:0];
}
return nil;
}
- (void) startRecording
{
#if _Multitasking_
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{}]];
}
#endif
[videoOutput startRecordingToOutputFileURL:[self generatenewVideoPath]
recordingDelegate:self];
}
- (void) stopRecording
{
[videoOutput stopRecording];
}
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput
didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
fromConnections:(NSArray *)connections error:(NSError *)error
{
NSFileManager *man = [[NSFileManager alloc] init];
NSDictionary *attrs = [man attributesOfItemAtPath: [outputFileURL path] error: NULL];
NSString *fileSize = [NSString stringWithFormat:#"%llu", [attrs fileSize]];
// close this screen
[self exitScreen];
}
-(BOOL)recordsVideo
{
AVCaptureConnection *videoConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo
fromConnections:[videoOutput connections]];
return [videoConnection isActive];
}
-(BOOL)recordsAudio
{
AVCaptureConnection *audioConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeAudio
fromConnections:[videoOutput connections]];
return [audioConnection isActive];
}
If I do [videoInput release]; and [audioInput release]; I got a bad access error. that's why they are commented out. This may be part of the issue.
If I try to play the system sound n times, it work, but if I go first to the recording script, it wont work after that.
Any ideas?
The proper way to release AVCaptureSession is the following:
- (void) destroySession {
// Notify the view that the session will end
if ([delegate respondsToSelector:#selector(captureManagerSessionWillEnd:)]) {
[delegate captureManagerSessionWillEnd:self];
}
// remove the device inputs
[session removeInput:[self videoInput]];
[session removeInput:[self audioInput]];
// release
[session release];
// remove AVCamRecorder
[recorder release];
// Notify the view that the session has ended
if ([delegate respondsToSelector:#selector(captureManagerSessionEnded:)]) {
[delegate captureManagerSessionEnded:self];
}
}
If you're having some sort of release problems (bad access), I can recommend taking your code out of your current "messy" project to some other new project and debug the problem over there.
When I had similar problem, I just did that. I shared it on Github, you might find this project useful: AVCam-CameraReleaseTest

NSOperationQueue becomes suspended at random?

I have an app that uses NSOperationQueue intensively.
Sometimes I've noticed that some of the NSOperationQueues would "lock up" or enter a "isSuspended" state randomly even though my code never calls the setSuspended: method.
It's impossible to replicate and very hard to debug because whenever I hook the device up to Xcode to debug it, the app would reload and the bug would go away.
I added a lot of NSLogs at all possible points that might have a problem and just had to use the app for a few days until the bug reemerged.
Looking at the device system logs, I've discovered that [myOperationQueue operationCount] would increment but the opeations in queue will not execute.
I haven't tried manually setting "setSuspended:NO" yet but is that really necessary?
What could be causing this?
Here is a little bit of my code
The view controller that calls operations
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.operationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.operationQueue setMaxConcurrentOperationCount:2];
self.sendOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.sendOperationQueue setMaxConcurrentOperationCount:2];
self.receiveOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.receiveOperationQueue setMaxConcurrentOperationCount:1];
}
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[operationQueue cancelAllOperations];
[sendOperationQueue cancelAllOperations];
[receiveOperationQueue cancelAllOperations];
[operationQueue release];
[sendOperationQueue release];
[receiveOperationQueue release];
}
- (IBAction)sendMessage
{
if(![chatInput.text isEqualToString:#""])
{
NSString *message = self.chatInput.text;
SendMessageOperation *sendMessageOperation = [[SendMessageOperation alloc] initWithMatchData:matchData andMessage:message resendWithKey:nil];
[self.sendOperationQueue addOperation:sendMessageOperation];
[sendMessageOperation release];
}
}
NSOperation subclass SendMessageOperation
- (id)initWithMatchData:(MatchData*)data andMessage:(NSString*)messageString resendWithKey:(NSString*)resendKey
{
self = [super init];
if(self != nil)
{
if(data == nil || messageString == nil)
{
[self release];
return nil;
}
appDelegate = (YongoPalAppDelegate *) [[UIApplication sharedApplication] delegate];
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(mergeContextChanges:) name:NSManagedObjectContextDidSaveNotification object:context];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(mergeMainContextChanges:) name:NSManagedObjectContextDidSaveNotification object:appDelegate.managedObjectContext];
self.matchData = (MatchData*)[context objectWithID:[data objectID]];
matchNo = [[matchData valueForKey:#"matchNo"] intValue];
partnerNo = [[matchData valueForKey:#"partnerNo"] intValue];
self.message = messageString;
self.key = resendKey;
apiRequest = [[APIRequest alloc] init];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.matchData = nil;
self.message = nil;
self.key = nil;
[context release];
[apiRequest release];
[super dealloc];
}
- (void)start
{
if([self isCancelled] == YES)
{
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
else
{
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self main];
[self didChangeValueForKey:#"isExecuting"];
}
}
- (void)main
{
#try
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
bool taskIsFinished = NO;
while(taskIsFinished == NO && [self isCancelled] == NO)
{
NSDictionary *requestData = nil;
if(key == nil)
{
requestData = [self sendMessage];
}
else
{
requestData = [self resendMessage];
}
NSDictionary *apiResult = nil;
if(requestData != nil)
{
apiResult = [self sendMessageToServer:requestData];
}
if(apiResult != nil)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"shouldConfirmSentMessage" object:nil userInfo:apiResult];
}
taskIsFinished = YES;
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:#"isFinished"];
[self didChangeValueForKey:#"isExecuting"];
[pool drain];
}
#catch (NSException *e)
{
NSLog(#"Exception %#", e);
}
}
- (BOOL)isConcurrent
{
return YES;
}
- (BOOL)isFinished
{
return finished;
}
- (BOOL)isExecuting
{
return executing;
}
- (void)mergeContextChanges:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"mergeChatDataChanges" object:nil userInfo:[notification userInfo]];
}
- (void)mergeMainContextChanges:(NSNotification *)notification
{
NSSet *updated = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];
for(NSManagedObject *thing in updated)
{
[[context objectWithID:[thing objectID]] willAccessValueForKey:nil];
}
[context mergeChangesFromContextDidSaveNotification:notification];
}
You're using:
setMaxConcurrentOperationCount:X
My hunch is that X operations in the queue have not finished, therefore causing any subsequent operations added to the queue to not run until this is the case.
From the NSOperationQueue's isSuspended method documentation:
If you want to know when the queue’s suspended state changes, configure a KVO observer to observe the suspended key path of the operation queue.
Another idea that you can implement in parallel with the observer is to create a subclass of NSOperationQueue that redefines the setSuspended: method. In the redefined version you can set a breakpoint if you are running on the debugger, or print a stacktrace to the log if you are running w/o debugger.
Hope this helps.
take a look at ASIHTTPRequestConfig.h, it has some flags that you can turn on to see what is really happening behind the scenes.