blog.marcopeluso.com

In need of a clever subtitle.

How-to: Prevent iPhone From Deep Sleeping

As I have promised three weeks ago (and again a few days ago) I finally got around to writing this little how-to. I’m sorry for the delay. I hope this helps someone, anyway.

Mind you, this is my first attempt at writing a how-to and most of it was done while I was being tired. Also, English isn’t my native language, so please excuse any typos or other errors you may find.

If you have any suggestions on how to improve this how-to, please feel free to leave a comment.

Now, have fun!

Preface

We will create an iPhone application, that prevents the iPhone from deep sleeping while the app is running. It’s not a really useful application, as it does nothing but just that, but you can easily adapt the stuff you learn here and use it for your own application(s).

Here’s what we’re going to do: We will …

  • … create a new project in Xcode.
  • … add the necessary frameworks to this project.
  • … add a silent sound file to this project.
  • … create a class called “DeepSleepPreventer” and add it to this project.
  • … then use this class to prevent the iPhone from deep sleeping.

You can use this class in your apps to prevent the iPhone from deep sleeping, while they are running. Just add the needed frameworks and the DeepSleepPreventer class to your app and use the DeepSleepPreventer, whenever you need it.

Create a New Project in Xcode

I’m sure you all know how to do this, but for completeness’ sake, I’ll just go through the whole process, step by step.

Fire up Xcode. Click “File” -> “New Project”. We are gonna use the “View-based Application” template for this how-to, so select it and click “Choose …”.

how-to-1-1

Choose a location and name under which you want to save the project and click on “Save”. We are going to use “iPhoneInsomnia” as a name and save the project to the desktop (I know, I have a lot to tidy, judging by the screenshot).

how-to-1-2

Add the Necessary Frameworks

Now we’ll add the AVFoundation and the AudioToolbox frameworks to our project, as we will need them later on.

In our project window, we right-click (or control-click) our “Frameworks” group in the “Groups & Files” pane and click on “Add” -> “Existing Fameworks …”.

how-to-1-3

A file selection window should pop up now and should show you the content of the current iPhone SDK’s “Library” subfolder. If your starting up somewhere else, navigate to “/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library” first (see screenshot).

how-to-1-4

Further go to the Frameworks folder and select “AudioToolbox.framework” and “AVFoundation.framework”. Then click on “Add”.

how-to-1-5

In the upcoming window uncheck the “Copy …” checkbox, if it is selected and choose “Relative to Current SDK” as reference type. Then click “Add”.

how-to-1-6

Add a Silent Sound File

Now we need to add a silent sound file. You can create it with a sound tool of your choice. I named it “noSound.wav”. You can just use the file I created, if you like. It is part of the Github repository I created for this whole project. iPhoneInsomnia @ Github

We will first create a new group, named “DeepSleepPreventer” in the “Groups & Files” pane. Because we are very tidy people, we will add the sound file and our later created custom class to this group, too.

Right-click on “iPhoneInsomnia” and click on “Add” -> “New Group” and name it “DeepSleepPreventer”.

how-to-1-10

Now right-click this group and click “Add” -> “Existing Files …” and add the sound file to the project.

how-to-1-13

Navigate to the location of your sound file, select it and click “Add”.

how-to-1-14

Check the “Copy items …” checkbox and set “Reference Type” to “Default”. Click Add.

how-to-1-15

Create our New Class

Now it’s time to finally write some code. Almost. First we need to add a new class to the project.

Right-click the “DeepSleepPreventer” group and click “Add” -> “New File …”.

how-to-1-16

Choose the “Objective-C class” template under “iPhone OS” -> “Cocoa Touch Class” and select “NSObject” on the “Subclass of” pull down. Click “Next”.

how-to-1-17

Name the file “DeepSleepPreventer.m”, Check the “Also create .h” checkbox and click “Finish”.

how-to-1-18

Now modify “DeepSleepPreventer.h” to look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import <Foundation/Foundation.h>

@class AVAudioPlayer;

@interface DeepSleepPreventer : NSObject {
    AVAudioPlayer *audioPlayer;
    NSTimer *preventSleepTimer;
}
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
@property (nonatomic, retain) NSTimer *preventSleepTimer;
- (void)playPreventSleepSound;
- (void)startPreventSleep;
- (void)stopPreventSleep;
@end

We declared two properties here: an AVAudioPlayer, that will play our silent sound file and an NSTimer that will call -playPreventSleepSound. We actually create this timer in -startPreventSleep and invalidate it in -stopPreventSleep later.

Now we edit “DeepSleepPreventer.m” step by step.

First we import some header files, synthesize our accessors and mutators (or getters and setters, if you prefer to call them that):

1
2
3
4
5
6
7
8
#import "DeepSleepPreventer.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

@implementation DeepSleepPreventer

@synthesize audioPlayer;
@synthesize preventSleepTimer;

Modify -init to set up all the stuff we need to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- (id)init
{
    if ((self = [super init])) {
        // Activate audio session
        AudioSessionSetActive(true);
        // Set up audio session, to prevent iPhone from deep sleeping, while playing sounds
        UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
        AudioSessionSetProperty (
            kAudioSessionProperty_AudioCategory,
            sizeof (sessionCategory),
            &#038;sessionCategory
        );

        // Set up sound file
        NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"noSound"
                                                                  ofType:@"wav"];
        NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];

        // Set up audio player with sound file
        self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
        [self.audioPlayer prepareToPlay];

        // You may want to set this to 0.0 even if your sound file is silent.
        // I don't know exactly, if this affects battery life, but it can't hurt.
        [self.audioPlayer setVolume:0.0];
    }
    return self;
}

Now we implement -playPreventSleepSound:

1
2
3
- (void)playPreventSleepSound {
    [self.audioPlayer play];
}

This should be self explanatory.

Now -startPreventSleep (this is the method we will call, if we want the iPhone to stay awake):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)startPreventSleep {
    // We need to play a sound at least every 10 seconds to keep the iPhone awake.
    // We create a new repeating timer, that begins firing now and then every ten seconds.
    // Every time it fires, it calls -playPreventSleepSound
    self.preventSleepTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0]
                                                      interval:10.0
                                                        target:self
                                                      selector:@selector(playPreventSleepSound)
                                                      userInfo:nil
                                                       repeats:YES];
    // We add this timer to the current run loop
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:self.preventSleepTimer forMode:NSDefaultRunLoopMode];
}

-stopPreventSleep stops the sleep preventing.

1
2
3
4
- (void)stopPreventSleep {
    [self.preventSleepTimer invalidate];
    self.preventSleepTimer = nil;
}

Finally -dealloc to clean up our mess:

1
2
3
4
5
6
7
8
- (void)dealloc {
    // memory management
    [preventSleepTimer release];
    [audioPlayer release];
    [super dealloc];
}
// Don't forget the matching @end to our @implementation
@end

Use the DeepSleepPreventer Class

Now switch to “iPhoneInsomniaAppDelegate.h”. We will add a property if the type or our class DeepSleepPreventer to the application delegate now. Modify “iPhoneInsomniaAppDelegate.h”, to look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <UIKit/UIKit.h>

@class iPhoneInsomniaViewController;
@class DeepSleepPreventer;

@interface iPhoneInsomniaAppDelegate : NSObject  {
    UIWindow *window;
    iPhoneInsomniaViewController *viewController;
    DeepSleepPreventer *deepSleepPreventer;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet iPhoneInsomniaViewController *viewController;
@property (nonatomic, retain) DeepSleepPreventer *deepSleepPreventer;

@end

Now move on to “iPhoneInsomniaAppDelegate.m”. We will instantiate and use our DeepSleepPreventer in -applicationDidFinishLaunching:. In your own app, you would do this in a place, where it fits best.

First we need to import our class header file and synthesize our new property:

1
2
3
4
5
6
7
8
9
#import "iPhoneInsomniaAppDelegate.h"
#import "iPhoneInsomniaViewController.h"
#import "DeepSleepPreventer.h"

@implementation iPhoneInsomniaAppDelegate

@synthesize window;
@synthesize viewController;
@synthesize deepSleepPreventer;

Now modify -applicationDidFinishLaunching: to look like this:

1
2
3
4
5
6
7
8
- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Here we create our deepSleepPreventer and get it to keep our iPhone from deep sleeping
    self.deepSleepPreventer = [[DeepSleepPreventer alloc] init];
    [self.deepSleepPreventer startPreventSleep];

    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

And finally the rest of “iPhoneInsomniaAppDelegate.m”. Release our property in -dealloc:

1
2
3
4
5
6
7
8
9
- (void)dealloc {
    [deepSleepPreventer release];
    [viewController release];
    [window release];
    [super dealloc];
}

// Don't forget the matching @end to our @implementation
@end

Well, that’s it! We are done! :)

Use This in Your Own App

Just add the two frameworks “AVFoundation.framework” and “AudioToolbox.framework” to your own app, add the sound file “noSound.wav” and the files “DeepSleepPreventer.h” and “DeepSleepPreventer.m” to it and instantiate and use an object of the “DeepSleepPreventer” class where it fits best, and you’re ready to go.

License

The source code of this how-to is licensed under the New BSD License. Here comes the license text:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Copyright (c) 2009-2010, Marco Peluso - marcopeluso.com
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from
     this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Issues and Epilog

I couldn’t start my MPMusicPlayer in my music alarm clock app, while I was playing the silent sound with the AVAudioPlayer. So I’m guessing, it’s not possible to play other sounds while this sound plays, at least not via the MPMediaPlayer class.

As I didn’t use any other sounds in my applications yet, I don’t know if this assumption is correct. If you have any more experience with this or any more other useful or relevant information, please leave a comment. I will then update this how-to.

Also, as Shabbir Vijapura pointed out in a comment to my previous post there might be an easier way, to run timers on the iPhone, while it is asleep. I haven’t tested this myself, yet, though, so I cannot guarantee, that this really works. I will test it in the the next couple of days and then update this post, if I find the time.

Update: Apparently this method, doesn’t work, as Shabbir pointed out in the comments.

Furthermore, if you have any experience yourself, dealing with the iPhone’s deep sleep behaviour and would like to share, or if you have any other suggestions or questions, please feel free to leave a comment.

Thanks for reading. I hope this is useful to someone out there.

Downloads

You can download a drop-in piece of code and the silent sound file from GitHub: MMPDeepSleepPreventer on Github

Or you can download the whole demo project, including all source code and the silent sound file: iPhoneInsomnia on GitHub

All the code is licensed under the New BSD License. Feel free, to use it in your own apps. Some attribution would be appreciated.