Stop radio after call - objective-c

I'm making an iphone Live radio application. My application is working fine in background mode. But, if the phone rings when radio app is playing in background mode, my radio stops.
MP AVAudioSessionDelegateMediaPlayerOnly end interruption. Interruptor <Phone> category <completed> resumable <0>, _state = 6
2013-01-02 10:26:24.487 Radio99[2527:707] MP endInterruptionFromInterruptor :: resuming playback at 1.000000

Use only AudioStreamer. (Never use AVAudioPlayer or MPMoviePlayerController it's not play radio after call).
NSURL *url =[NSURL URLWithString:#"http://y1.eoews.com/assets/ringtones/2012/5/18/34049/oiuxsvnbtxks7a0tg6xpdo66exdhi8h0bplp7twp.mp3"];
AudioStreamer *tempStreamer = [[AudioStreamer alloc] initWithURL:url];
self.streamer = tempStreamer;
[tempStreamer release]; [streamer start];
Add this code in background
- (void)applicationDidEnterBackground:(UIApplication *)application
{
CTCallCenter *_center = [[CTCallCenter alloc] init];
_center.callEventHandler = ^(CTCall *call)
{
if ([call.callState isEqualToString:CTCallStateIncoming])
{
NSLog(#"Pause");
[streamPlayer pause];
}
if ([call.callState isEqualToString:CTCallStateDisconnected])
{
NSLog(#"call:%#", call.callState);
NSLog(#"Play");
[streamPlayer start];
}
};
}
}

Related

freeing memory in a simple avaudioengine program?

I'm wondering how to free memory in this simple program that plays a file through a buffer and then stops it.
-(void)setupAudioOne
{
NSError *error;
BOOL success = NO;
_player = [[AVAudioPlayerNode alloc] init];
NSURL *hiphopOneURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Hip Hop 1" ofType:#"caf"]];
AVAudioFile *hiphopOneFile = [[AVAudioFile alloc] initForReading:hiphopOneURL error:&error];
_playerLoopBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[hiphopOneFile processingFormat] frameCapacity:(AVAudioFrameCount)[hiphopOneFile length]];
success = [hiphopOneFile readIntoBuffer:_playerLoopBuffer error:&error];
_engine = [[AVAudioEngine alloc] init];
[_engine attachNode:_player];
AVAudioMixerNode *mainMixer = [_engine mainMixerNode];
AVAudioFormat *stereoFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:2];
[_engine connect:_player to:mainMixer fromBus:0 toBus:0 format:stereoFormat];
[self startEngine];
}
Above is the general setup of the engine and the player node.
Then we implement the player with a play button:
- (IBAction)play:(id)sender {
if (!self.playerIsPlaying)
{
[self setupAudioOne];
[_player scheduleBuffer:_playerLoopBuffer atTime:nil options:AVAudioPlayerNodeBufferLoops completionHandler:nil];
[_player play];
}
}
And finally we stop the player with a stop button:
- (IBAction)stopHipHopOne:(id)sender {
if (self.playerIsPlaying) {
[_player stop];
}
playerIsPlaying is just a simple BOOL that determines if the _player is playing.
So basically my question is, when you hit the stop button as this program is written now, no memory will be freed.
Surely there is a simple line of code that I can add to the stop button that frees up the memory the engine and player is using?
Any thoughts?
Yes, there is. After stopping the player node, you can call:
[_engine disconnectNodeInput:_player];
[_engine detachNode:_player];
I saw you're also keeping a reference to the audio buffer, so you might want to nil that one as well. Let me know if that doesn't work for you. Something else could be leaking.

MPNowPlayingInfoCenter doesn't play on lock screen

I'm using MPMoviePlayerController to play audio/video and would like to continue playing when the app backgrounds and lock screen comes on. I'm setting MPNowPlayingInfoCenter's nowPlayingInfo in viewDidLoad and again on UIApplicationWillResignActiveNotification1 notification with the following:
- (void)appWillResignActive {
NSMutableDictionary *nowPlayingInfo = [[NSMutableDictionary alloc] init];
[nowPlayingInfo setObject:_session[#"session"][#"title"] forKey:MPMediaItemPropertyTitle];
[nowPlayingInfo setObject:_session[#"session"][#"author"] forKey:MPMediaItemPropertyArtist];
[nowPlayingInfo setObject:_session[#"session"][#"album"] forKey:MPMediaItemPropertyAlbumTitle];
[nowPlayingInfo setObject:[NSNumber numberWithDouble:_videoController.playableDuration] forKey:MPMediaItemPropertyPlaybackDuration];
[nowPlayingInfo setObject:#(1.0f) forKey:MPNowPlayingInfoPropertyPlaybackRate];
[nowPlayingInfo setObject:[NSNumber numberWithDouble:_videoController.currentPlaybackTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
if (_session[#"session"][#"album_art"] != nil) {
UIImage *albumArtImage = [UIImage imageNamed:_session[#"session"][#"album_art"]];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:albumArtImage];
[nowPlayingInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
}
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nowPlayingInfo];
}
The lock screen shows the current info, but it's not playing at all. The elapsed time seems about right, but the total playable time is incorrect. Pressing play doesn't start it either. I'm not sure what's wrong, any thoughts?

How to play audio in notification action in ios8?

I'm trying to use new ios8 notification actions to let users play audio from their lock screen.
I manage to download the data in the background, but the avaudioplayer does not seem to play.
Any help would be greatly appreciated !
Here is the code :
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
//handle the actions
if ([identifier isEqualToString:#"ACCEPT_IDENTIFIER"]){
Message *newMessage = [Message rawMessageToInstance:[userInfo valueForKey:#"message"]];
AVAudioSession* session = [AVAudioSession sharedInstance];
BOOL success; NSError* error;
success = [session setCategory:AVAudioSessionCategoryPlayback
error:&error];
if (!success)
NSLog(#"AVAudioSession error setting category:%#",error);
[session setActive:YES error:nil];
NSLog(#"%lu",newMessage.identifier);
[ApiUtils downloadAudioFileAtURL:[newMessage getMessageURL] success:^void(NSData *data) {
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:nil];
[player setVolume:2];
[player play];
[self performSelector:#selector(completeNotif:) withObject:completionHandler afterDelay:[player duration]];
} failure:^(){
completionHandler();
}];
}
}
I had the same problem ... first I came up, it must have to do something with background and sound playing options - so I added the background audio flag to the info.plist.
With standard AVAudio stuf it works on the simulator, but not on the device. The special hook is, that you want to start the audio while you are in background - so add the code from anger: How to use kAudioSessionProperty_OverrideCategoryMixWithOthers before starting with the AVAudioPlayer and it will also work on the device.
Hope that helps, for me it works.

iPad capturing 16:9 photos

I am building a prototype app on iOS, and I’m cannibalizing some Apple sample code to do it (thin ice, I know—this code uses goto statements :\ ). I am using the AVCam project from Session 520 - What's New in Camera Capture. I don’t need video capture capability, just still photos.
The device inputs and outputs are set up thusly:
// Init the device inputs
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backFacingCamera] error:nil];
AVCaptureDeviceInput *newAudioInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self audioDevice] error:nil];
// Setup the still image file output
AVCaptureStillImageOutput *newStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = #{AVVideoCodecKey: AVVideoCodecJPEG};
[newStillImageOutput setOutputSettings:outputSettings];
// Create session (use default AVCaptureSessionPresetHigh)
AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init];
// Add inputs and output to the capture session
if ([newCaptureSession canAddInput:newVideoInput]) {
[newCaptureSession addInput:newVideoInput];
}
if ([newCaptureSession canAddInput:newAudioInput]) {
[newCaptureSession addInput:newAudioInput];
}
if ([newCaptureSession canAddOutput:newStillImageOutput]) {
[newCaptureSession addOutput:newStillImageOutput];
}
[self setStillImageOutput:newStillImageOutput];
[self setVideoInput:newVideoInput];
[self setAudioInput:newAudioInput];
[self setSession:newCaptureSession];
And here is the method that’s called when I tap the shutter button:
- (void) captureStillImage
{
AVCaptureConnection *stillImageConnection = [[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo];
if ([stillImageConnection isVideoOrientationSupported])
[stillImageConnection setVideoOrientation:orientation];
[[self stillImageOutput]
captureStillImageAsynchronouslyFromConnection:stillImageConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
ALAssetsLibraryWriteImageCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
if (error)
{
if ([[self delegate] respondsToSelector:#selector(captureManager:didFailWithError:)])
{
[[self delegate] captureManager:self didFailWithError:error];
}
}
};
if (imageDataSampleBuffer != NULL)
{
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
UIImage *image = [[UIImage alloc] initWithData:imageData];
if ([self.delegate respondsToSelector:#selector(captureManagerCapturedImage:)])
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate captureManagerCapturedImage:image];
});
}
[library writeImageToSavedPhotosAlbum:[image CGImage]
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:completionBlock];
}
else
{
completionBlock(nil, error);
}
if ([[self delegate] respondsToSelector:#selector(captureManagerStillImageCaptured:)])
{
[[self delegate] captureManagerStillImageCaptured:self];
}
}];
}
This code successfully captures an image and saves it to the library. However, at some point while I was working on it, it changed from capturing 5-megapixel 4:3 images to capturing 1920x1080 16:9 images. I can’t find anywhere that the aspect ratio is specified, and I didn’t change any of the code relating to the configuration of the camera, capture sessions, or capture connection. Why did my camera start taking 16:9 photos?
Update: I just re-ran Apple’s original sample code, and it appears that it is also saving 16:9 images captured directly from the video. It is quite possible that I was insane before, or I took a test shot with Camera.app and was looking at that. So my real question is, how do I show a live feed from the camera on the screen while I’m shooting, and take a full-resolution photo. I can’t use UIImagePickerController, because I need to be able to overlay things on top of the live camera feed.
Update 2: I was able to solve this by throwing out the AVCapture code I was using. It turns out that UIImagePickerController does what I needed. I didn’t realize you could overlay custom controls - I thought it took over the whole screen until you were done taking a picture.
If you're capturing frames from a video source, you'll end up with a resolution of 16:9. Capturing frames from a video source and taking photos are different things.

How to Play Audio in background in IPhone?

I'm trying to play audio file at particular time which i have set.for that I have added audio in "UIBackgroundModes" in info.plist and backgroundtaskidentifier in didEnterBackground.Its working in simulator but not in device.Can anyone help to solve this.
Thanks in Advance...
You can check out this reference app with streaming and backgrounding of audio.
EDIT:
Example of a local notification w/ attached sound. More detail here.
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIInvalidBackgroundTask, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIInvalidBackgroundTask;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
while ([application backgroundTimeRemaining] > 1.0) {
NSString *friend = [self checkForIncomingChat];
if (friend) {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif) {
localNotif.alertBody = [NSString stringWithFormat:
NSLocalizedString(#"%# has a message for you.", nil), friend];
localNotif.alertAction = NSLocalizedString(#"Read Message", nil);
localNotif.soundName = #"alarmsound.caf";
localNotif.applicationIconBadgeNumber = 1;
[application presentLocalNotificationNow:localNotif];
[localNotif release];
friend = nil;
break;
}
}
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIInvalidBackgroundTask;
});
}
If I understand you correctly, you want to play a sound at a particular time, no matter if your app is active and foregrounded at that time? Your only (app review-friendly) option is to schedule a local notification, as in slf's answer. UIBackgroundModes won't help you: the audio background mode is for being allowed to execute code while backgrounded only when you start playing audio when you are foregrounded. Example usages are music players and radio apps.
If you explain your use case more thoroughly, I might have a better answer.