在app中播放声音在背景中

时间:2014-12-31 03:46:08

标签: ios objective-c audio

尝试在应用在后台时播放声音。如果我用以下方法启动声音,我的代码会正确播放声音。背景我的意思是当手机屏幕关闭时(例如,当你把它放在口袋里时)。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

     [self startSilentBackgroundSound];  // works fine

}

如果我删除上面的代码并在此处执行,则在应用程序处于后台时, NOT 播放声音。

- (void)applicationDidEnterBackground:(UIApplication *)application {

     self.newTaskId = UIBackgroundTaskInvalid;
     self.newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
     [self startSilentBackgroundSound];  // does NOT work
}

在所需的背景模式中,我有以下内容:

App plays audio or streams audio/video using AirPlay
App downloads content from the network
App registers for location updates
App provides Voice over IP services
App downloads content in response to push notifications

如果有人知道GitHub项目,我会非常感谢!!!

////我的APP代码中的代码////////

-(void)startSilentBackgroundSound {
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        NSError *error = nil;
        NSLog(@"Activating audio session");
        if (![audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error]) {
            NSLog(@"Unable to set audio session category: %@", error);
        }
        BOOL result = [audioSession setActive:YES error:&error];
        if (!result) {
            NSLog(@"Error activating audio session: %@", error);
        }
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

        [self startAlarmSound];
    }

    -(void)stopSilentBackgroundSound {
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        NSError *error = nil;
        NSLog(@"Deactivating audio session");
        BOOL result = [audioSession setActive:NO error:&error];
        if (!result) {
            NSLog(@"Error deactivating audio session: %@", error);
        }

        [self stopSounds];
    }



    -(void)startAlarmSound {
        self.silentAudioController = [[SilentAudioController alloc] init];
        [self.silentAudioController tryPlayMusic];
    }

    -(void)stopSounds {
        [self.silentAudioController tryStopMusic];
        self.silentAudioController = nil;
    }

///这是我处理所有声音的文件

        #import "SilentAudioController.h"

        @import AVFoundation;

        @interface SilentAudioController () <AVAudioPlayerDelegate>

        @property (strong, nonatomic) AVAudioSession *audioSession;
        @property (strong, nonatomic) AVAudioPlayer *backgroundMusicPlayer;
        @property (assign) BOOL backgroundMusicPlaying;
        @property (assign) BOOL backgroundMusicInterrupted;
        @property (assign) SystemSoundID pewPewSound;

        @end

        @implementation SilentAudioController

        #pragma mark - Public

        - (instancetype)init
        {
            self = [super init];
            if (self) {
                [self configureAudioSession];
                [self configureAudioPlayer];
                [self configureSystemSound];
            }
            return self;
        }

        - (void)tryPlayMusic {
            // If background music or other music is already playing, nothing more to do here
            if (self.backgroundMusicPlaying || [self.audioSession isOtherAudioPlaying]) {
                return;
            }

            // Play background music if no other music is playing and we aren't playing already
            //Note: prepareToPlay preloads the music file and can help avoid latency. If you don't
            //call it, then it is called anyway implicitly as a result of [self.backgroundMusicPlayer play];
            //It can be worthwhile to call prepareToPlay as soon as possible so as to avoid needless
            //delay when playing a sound later on.
            [self.backgroundMusicPlayer prepareToPlay];
            [self.backgroundMusicPlayer play];
            self.backgroundMusicPlaying = YES;
        }

        - (void)tryStopMusic {
            [self.backgroundMusicPlayer stop];
            self.backgroundMusicPlaying = NO;
        }

        - (void)playSystemSound {
            AudioServicesPlaySystemSound(self.pewPewSound);
        }

        #pragma mark - Private

        - (void) configureAudioSession {
            // Implicit initialization of audio session
            self.audioSession = [AVAudioSession sharedInstance];

            // Set category of audio session
            // See handy chart on pg. 46 of the Audio Session Programming Guide for what the categories mean
            // Not absolutely required in this example, but good to get into the habit of doing
            // See pg. 10 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"

            NSError *setCategoryError = nil;
            if ([self.audioSession isOtherAudioPlaying]) { // mix sound effects with music already playing
                [self.audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&setCategoryError];
                self.backgroundMusicPlaying = NO;
            } else {
                [self.audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
            }
            if (setCategoryError) {
                NSLog(@"Error setting category! %ld", (long)[setCategoryError code]);
            }
        }

        - (void)configureAudioPlayer {
            // Create audio player with background music
            NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:@"background-music-aac" ofType:@"caf"];
            NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
            self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:nil];
            self.backgroundMusicPlayer.delegate = self;  // We need this so we can restart after interruptions
            self.backgroundMusicPlayer.numberOfLoops = -1;  // Negative number means loop forever
        }

        - (void)configureSystemSound {
            // This is the simplest way to play a sound.
            // But note with System Sound services you can only use:
            // File Formats (a.k.a. audio containers or extensions): CAF, AIF, WAV
            // Data Formats (a.k.a. audio encoding): linear PCM (such as LEI16) or IMA4
            // Sounds must be 30 sec or less
            // And only one sound plays at a time!
            NSString *pewPewPath = [[NSBundle mainBundle] pathForResource:@"pew-pew-lei" ofType:@"caf"];
            NSURL *pewPewURL = [NSURL fileURLWithPath:pewPewPath];
            AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &_pewPewSound);
        }

        #pragma mark - AVAudioPlayerDelegate methods

        - (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
            //It is often not necessary to implement this method since by the time
            //this method is called, the sound has already stopped. You don't need to
            //stop it yourself.
            //In this case the backgroundMusicPlaying flag could be used in any
            //other portion of the code that needs to know if your music is playing.

            self.backgroundMusicInterrupted = YES;
            self.backgroundMusicPlaying = NO;
        }

        - (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
            //Since this method is only called if music was previously interrupted
            //you know that the music has stopped playing and can now be resumed.
            [self tryPlayMusic];
            self.backgroundMusicInterrupted = NO;
        }

        @end

//更新//////////////

我已经实现了这个(hayageek.com/ios-long-running-background-task)长时间运行的任务,就像这个例子一样。现在声音文件在后台播放,但仅在模拟器上播放。在ios7手机和ios8手机上试过并且都没有播放声音文件?

2 个答案:

答案 0 :(得分:0)

你看过这个Apple Documentation了吗?您必须按照文档中的规定实施长时间运行的任务。

答案 1 :(得分:0)

解决方案就是这个

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];