iOS generating a video in the background task - ios

How would you go on creating a long video from images? It takes pretty long and the user will get bored to wait for it, so i'm thinking to generate the movie in background and notify the user after it finishes.
My app structure is like this, i have a UINavigationController that holds one controller with the simulated movie, just some images moving with CoreAnimation. Then i push a new controller that generates the movie. in controller2 i send request to controller1 to send me images with the frames to write on the movie (i generate images with CoreGraphics). This is almost blocking everything as it takes a lot of time and is continuous.
I read about background tasks and seems the only solution, but they do not last very long and might stop in the middle, generating 30sec of video takes about 6mins. I also can't declare my app as running in the background because it's not VoIP or other supported type.
Thanks for ideas.

To my understanding you can do that, although your App will only be running for a limited amount of time, but depending on he size of your video it can be sufficient. In fact I do exactly this on my animation authoring app idAnimate - Animating on the iPad with the touch of a finger. To my knowledge the app will be granted something around 10 minutes to complete the task, which can be sufficient. Should you app require additional time, you might want to look into how to optimise your video rendering algorithm, reduce the video quality or something.
Anyway here is a bit of code of how I do this assuming you use AVAssetWriter to generate the video:
First you have to make the call to get a background permission, and to provide a block for what to do when your time is complete (background task expiration handler):
UIApplication *app = [UIApplication sharedApplication];
_backgroundRenderingID = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:_backgroundRenderingID];
_backgroundRenderingID = UIBackgroundTaskInvalid;
}];
After that you can start rendering your video:
videoWriter = [[AVAssetWriter alloc] initWithURL:
[NSURL fileURLWithPath:self.moviePath] fileType:AVFileTypeMPEG4
error:&error];
NSParameterAssert(videoWriter);
...
And when you are done make sure you let the OS know that your task legible for the background is completed:
[[UIApplication sharedApplication] endBackgroundTask:_backgroundRenderingID];
I hope that helped.

Related

Increase loudness of app output

Let assume user set loudness on its iphone to 5/10 value, i want to increase volume that my app outcome from 0% to 100%, where 100% is 5/10 (value that is set by user). I want that action to be made slowly increasing, for example for 20 seconds.
If i understand correct, app can't exceed value of maximum volume output that is set by user.
Unfortunately i couldn't find a way to do that. Where should i begin to achieve that task?
I want to make an alarm.
Right now i use following logic to send push notification, that "wake up" user.
- (void)sendLocalPushForAlarm {
if (IS_OS_8_OR_LATER) {
[self registerForLocalNotification];
}
UILocalNotification *notification = [[UILocalNotification alloc] init];
[notification setAlertBody:NSLocalizedString(#"WAKE_UP", nil)];
if (IS_OS_8_OR_LATER) {
[notification setCategory:NotificationCategoryIdent];
}
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
the only way you could maniple the loudness is when your app is running in the foreground (or rather: if you MANUALLY play the right sound using e.g. AVPlayer. this is normally not possible in the bg, so I simplified it to 'foreground only')
apart from that there is no way.
(ugly) workaround to come close maybe: have multiple notifications with multiple sound files that are recorded at a different loudness level
==> my vote would be no way

Application idle Timer disable not working

Application idle timer disable is not working properly after record video from the application. I put below code in my application did finish launching. please suggest me if any one have idea to handle idle timer.
[[UIApplication sharedApplication] setIdleTimerDisabled: YES];
In the past there have been some bugs in iOS, in which it forgets that you have set idleTimerDisabled, for example after you have used the UIImagePickerController to take a picture. I am not sure whether Apple has fixed those bugs completely yet.
A work-around is to set it more often, for example in the viewWillAppear of your main view.

iOS 8 custom alarm using uilocalnotification and playing sound in background when phone is on silent

I am trying to build a custom alarm application. But the challenge I am facing is getting the sound played while app is in the background.
First method, UILocalNotification,
According to the Apple programming guidelines, the right way to make an alarm is
- (void)scheduleAlarmForDate:(NSDate*)theDate
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];
// Create a new notification.
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = #"alarmsound.caf";
alarm.alertBody = #"Time to wake up!";
[app scheduleLocalNotification:alarm];
}
}
Problem is,
if the user has the phone on silent, the notification sound will only be a small vibrate that doesn't suffice for a alarm.
Idealy, I want a alarm that will go off no matter the phone is on silent or normal to wake up the user.
Second way I can think of, AVAudioSession
But when the region is near or alarm trigger comes in, audioSession cannot be initiated in the background so any audioPlayer.play() methods won't do anything.
Besides the above 2 methods that both don't work, I can't seem to find any other ways to tackle the problem at hand.
I am trying to make an App which is a location based alarm.
I can set a region and custom sound for 30 seconds on my UILocalNotification but the sound won't play if phone is silent.
I can have a locationManager monitoring my region but I can't play a sound after I get notified from the background.
I've downloaded many Apps that are capable of doing this so I know there must be way of achieving it. However, after multiple tries in various angles, I can't seem to find any good solutions. If anyone had experience with making a custom alarm, please share some tips and pointers if you can.
Thank you.
Since my reputation is not enough to comment everywhere, I would write it here as an answer. Sorry about this.
I'm also suffering with the same problem. Though I cannot give you a solution, there might be some hints to you. To me, I think it might be impossible to achieve.
I have double checked two alarm application I use: Sleep Cycle and UNIQLO Wake Up. And I found out that these two applications asked you to keep it always running on the foreground to make sure that the alarm clock will work. Especially UNIQLO Wake Up, it will show you an alert when you save the alarm clock, telling you that press Home button may cause the alarm clock not working.
There is a post asking about similar question, and the author provide some names of the applications: How do I start playing audio when in silent mode locked in iOS 6. I checked the application called WaveAlarm. Similarly, if the cellphone is in mute mode and you put it into background, only UILocalNotification will work. This means, no sound will be played in this situation. If your cellphone is still in the mute mode, but you keep the application in the foreground, it will play a sound. The volume of the sound depends on the volume you set for video playing.
So to me, I think it might impossible to play alarm sound when you put the application into background and set the cellphone into mute mode. I guess the most possible way to achieve this is to ask users to keep it in foreground, and play a media with the alarm sound.
I'll try to achieve this function in these two days. If I have some other understandings, I'll edit this post here.

AVPlayer pauses for no obvious reason

While playing a video, I'm seeing rate change notifications from AVPlayer that don't seem to be connected to app activity.
When my app receives a UIApplicationDidEnterBackgroundNotification notification, I tell the AVPlayer to pause.  The logic is that it should come back to the foreground at the same place the user left. If I do not call pause when going to the background, the problem doesn't appear.
The sequence of events sent to the player is pause, seekToTime:, play.  Generally, this works fine but, after the app has been sent to the background and then returned to the foreground, each play invocation results in two rate changes from the AVPlayer.  The first is to 1 and the second, immediately following, is to 0.  This pattern continues for each call to  -[AVPlayer play] as long as that player instance is in use.
I'm able to put a breakpoint on -[AVPlayer pause] and I do not see it being hit when the rate changes to 0.  If I comment out the seekToTime: call, the problem goes away.  If I use seekToTime:completionHandler:, I also get the same problem although my block's finished parameter is YES.
Apart from "how do I fix this", I'm interested in any details about how to detect the reason for rate changes in AVPlayer that aren't connected to play/pause.  (Putting a breakpoint on -[AVPlayer setRate:] never seems to trigger.)
(One workaround that almost works is to save the player position when entering the background, let it play, and fix the position when returning to the foreground.  This also requires some manipulation of audio levels, which is probably doable, but another problem is that not all background notifications indicate that the view has been obscured (e.g. double-tap home button).  This leads to cases where my workaround shows a distracting moving image when the app is interrupted but still visible.)
Suggestions?
(A last bit of extra information: In all the cases I've tried, I eventually get to a state where the AVPlayer is changing the rate from 1 to 0 moments after I invoke 'play' if I've returned from the background and then performed a seek. There are things I can do to make it less frequent but none that eliminate it except getting rid of the AVPlayer and creating a new instance. This results is very long delays but is better than a complete malfunction...I guess.
I have some evidence that the seek distance affects the result, which suggests that the error might be in the underlying buffering mechanism. Without knowing what causes the rate change (other than play/pause) I don't see a way to investigate further.)
You are probably getting an AVPlayerItemPlaybackStalledNotification.
Try this:
[[NSNotificationCenter defaultCenter]
addObserverForName:AVPlayerItemPlaybackStalledNotification
object:cell.avPlayerItem
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
DDLogVerbose(#"%#", #"AVPlayerItemPlaybackStalledNotification");
}];
However, Apple docs say Playback will continue once a sufficient amount of media has subsequently been delivered. (https://developer.apple.com/library/iOS/documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009532-CH1-SW83)
This is not happening for me or you.
I am still tracking the reason down.
EDIT:
This was the problem for me. When AVPlayerItem.likelyToKeepUp was YES then it wouldn't happen.
Not sure why it wasn't resuming.
EDIT:
From the Apple docs there is a situation where playback will not resume:
This property communicates a prediction of playability. Factors
considered in this prediction include I/O throughput and media decode
performance. It is possible for playbackLikelyToKeepUp to indicate NO
while the property playbackBufferFull indicates YES. In this event the
playback buffer has reached capacity but there isn't the statistical
data to support a prediction that playback is likely to keep up in the
future.
It is up to you to decide whether to continue media playback.

UILocalNotification how to call certain method if application is in background

I am creating player application, which is playing audio streams through internet. I want to add alarm functionality in my app - in particular time my player begins to play audio stream, I am trying to use UILocalNotification mechanism. But I've difficulties with it when my application in background mode, I can't call 'play' method, when notification is receiced (can't without user interaction). May be it is impossible?
But I bought this application:
http://itunes.apple.com/us/app/radio-alarm-clock-mp3-radio/id380271167?mt=8
And it seems like radio can start playing when local notification is received. Alarm can start playing radio when my app is in background mode.
Earlier I was trying to use NSTimer for this, but when my app goes to background, timer stops. If I use beginBackgroundTaskWithExpirationHandler: it works only 10 minutes. My app has special flag in plist, what is is audio application, and can playing music in background. In this case timers are working. But if I stop playing and go to background, timer is not working.
When I use \Radio Alarm Clock' application, I hear 'white noise' from dinamic, when music in not playing. May be it is the secret of this application?
Can you help me with my problem? Thanks.
maybe it's too late.
I had a look to the app you've mentioned at http://itunes.apple.com/us/app/radio-alarm-clock-mp3-radio/id380271167?mt=8 and yes, I think you are absolutely right, the only way to achieve that the application remains active while in background is to play a fake sound while it is in the background, which should be prohibited by Apple.
I've also seen that they don't use the remote iPod control, and this was strange at a first look.
At the end my opinion is that they do the following:
Avoid the call to beginReceivingRemoteControlEvents which allows to activate the iPod controls while in background (in fact they don't have it)
In this way, the status bar doesn't show the play icon while
the app plays audio
When the app goes in background, it probably plays a no sound periodically (once every 10 secs for example), in this way the app remains active
I saw that they also avoided to manage interruptions, for example in case another app is in foreground and plays music. Again Apple should have rejected the app for that reason, cos it is against the rules to follow while in background, but maybe they didn't see it during the acceptance tests.
So my interpretation is that they have intentionally missed to activate the iPod controls, just to avoid to show the play icon in the status bar while in background. In this way, the users are unaware that the app is active and is doing something strange after they close it.
In addition you can see that the app doesn't interrupt when another app plays in foreground a sound or audio, because otherwise they risk that the app doesn't restart on time when the alarm shpould fire.
That's just my idea of how they do that, and I think this is the only way for an audio app on iOS to remain active while it is in background and is supposed to be halted (well, in case Apple doesn't see the trick).
Have you tried adding this to appdelegate.m
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
// Call your method in here.
}
if you have can you add code for us to see what your doing.

Resources