zoukankan      html  css  js  c++  java
  • iOS音频的后台播放总结

     在没有网络的情况下,音频的后台播放比较简单,google一下可以搜到很多资料,但是如果每次歌曲的请求都是通过网络,就不成了,有时可以也扛不了几首,这里总结下实现方法,可以实现像电台一样的功能,后台播放,网络请求歌曲,Remote控制,锁屏有封面,电话和听歌打断处理等。

    IMG_0149 IMG_0150

    初始化AudioSession和基本配置

    音频播放器采用的AVPlayer ,自己进行了功能封装,暂且不谈,在程序启动的时候需要配置AudioSession,AudioSession负责应用音频的设置,比如支不支持后台,打断等等,这一步很重要,比如在viewdidload里初始化AVplayer以后要调用下面的函数:

    -(void)setAudioSession{

    //AudioSessionInitialize用于控制打断 ,后面会说

    AudioSessionInitialize (

    NULL,                          // ‘NULL’ to use the default (main) run loop

    NULL,                          // ‘NULL’ to use the default run loop mode

    ASAudioSessionInterruptionListener,  // a reference to your interruption callback

    NULL                       // data to pass to your interruption listener callback

    );

    //这种方式后台,可以连续播放非网络请求歌曲,遇到网络请求歌曲就废,需要后台申请task

    AVAudioSession *session = [AVAudioSession sharedInstance];

    NSError *setCategoryError = nil;

    BOOL success = [session setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];

    if (!success)

    {

    /* handle the error condition */

    return;

    }

    NSError *activationError = nil;

    success = [session setActive:YES error:&activationError];

    if (!success)

    {

    /* handle the error condition */

    return;

    }

    }

    AudioSessionInitialize用于处理中断处理,AVAudioSession主要调用setCategory和setActive方法来进行设置,AVAudioSessionCategoryPlayback一般用于支持后台播放,在官方文档可以看到其他的类型,每个分别适用于不同的场合:

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryAmbient"]] >
    <blockquote]] > AVAudioSessionCategoryAmbient</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategorySoloAmbient"]] >
    <blockquote]] > AVAudioSessionCategorySoloAmbient</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryPlayback"]] >
    <blockquote]] > AVAudioSessionCategoryPlayback</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryRecord"]] >
    <blockquote]] > AVAudioSessionCategoryRecord</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryPlayAndRecord"]] >
    <blockquote]] > AVAudioSessionCategoryPlayAndRecord</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryAudioProcessing"]] >
    <blockquote]] > AVAudioSessionCategoryAudioProcessing</blockquote]] >
    </a]] > ;
    NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryMultiRoute"]] >
    <blockquote]] > AVAudioSessionCategoryMultiRoute</blockquote]] >
    </a]] > ;
     
    1
     

    除了代码的初始化,很重要的一步是对info-plist的设置,让应用支持音频的后台播放

    屏幕快照 2012-12-26 下午12.16.37

    库的引入包括:

    AudioToolBox.framework

    MediaPlayer.framework

    CoreMedia.framework

    AVFoundation.framework

    后台播放

    正常情况下,如果配置了AVAudioSessionCategoryPlayback这个方法并修改了info-plist文件,应用就已经支持后台音频播放了,但是如果每一首歌曲都不存在本地,在网络的话就不行了,需要申请后台任务来进行处理,首先修改:

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

    [application beginReceivingRemoteControlEvents];
    }

    然后在播放器的播放函数里添加:

    -(void)justPlay{

    UIBackgroundTaskIdentifier bgTask = 0;

    if([UIApplication sharedApplication].applicationState== UIApplicationStateBackground) {

    NSLog(@”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx后台播放”);

    [thePlayer play];

    UIApplication*app = [UIApplication sharedApplication];

    UIBackgroundTaskIdentifier newTask = [app beginBackgroundTaskWithExpirationHandler:nil];

    if(bgTask!= UIBackgroundTaskInvalid) {

    [app endBackgroundTask: bgTask];

    }

    bgTask = newTask;

    }

    else {

    NSLog(@”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx前台播放”);

    [thePlayer play];

    }

    }

    这样播放就可以进行前台或者后台的判断,支持网络后台播放了,一首一首连续播放。

    Remote控制

    在播放视图的ViewController里加上这两个函数:

    - (void)viewDidAppear:(BOOL)animated {

    NSLog(@”viewDidAppear!!!”);

    [super viewDidAppear:animated];

    //Once the view has loaded then we can register to begin recieving controls and we can become the first responder

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

    [self becomeFirstResponder];

    }

    - (void)viewWillDisappear:(BOOL)animated {

    NSLog(@”viewWillDisappear!!!”);

    [super viewWillDisappear:animated];

    //End recieving events

    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];

    [self resignFirstResponder];

    }

    当然也可以同理放到delegate.m里面的进入后台和回到前台的函数中,否则的话,上面的代码只是允许当前视图的情况下进入后台可以Remote控制

    然后添加下面的代码:

    -(void)remoteControlReceivedWithEvent:(UIEvent *)event{

    //if it is a remote control event handle it correctly

    if (event.type == UIEventTypeRemoteControl) {

    if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {

    [self playerTap];

    } else if (event.subtype == UIEventSubtypeRemoteControlNextTrack){

    [self nextSongAuto];

    [self configNowPlayingInfoCenter];

    }

    }

    }

    //Make sure we can recieve remote control events

    - (BOOL)canBecomeFirstResponder {

    return YES;

    }

    锁屏封面

    一般在每次切换歌曲或者更新信息的时候要调用这个方法

    - (void)configNowPlayingInfoCenter {

    NSDictionary *albumDic=[currentParserSongArray objectAtIndex:songIndex];

    if (NSClassFromString(@”MPNowPlayingInfoCenter”)) {

    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];

    [dict setObject:[albumDic objectForKey:@"name"] forKey:MPMediaItemPropertyTitle];

    [dict setObject:[albumDic objectForKey:@"singer"] forKey:MPMediaItemPropertyArtist];

    [dict setObject:[albumDic objectForKey:@"album"] forKey:MPMediaItemPropertyAlbumTitle];

    MPMediaItemArtwork * mArt = [[MPMediaItemArtwork alloc] initWithImage:cdCoverImgView.image];

    [dict setObject:mArt forKey:MPMediaItemPropertyArtwork];

    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nil;

    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];

    }

    }

    打断处理

    试用了官方文档上的各种代理方法,打断通知,都没用,后来用C函数处理可以控制打断,首先AudioToolBox.framework是需要引入的

    在设定session的时候调用了ASAudioSessionInterruptionListener这个函数 ,就是处理打断的,在所需加入的类的实现

    @implementation前面加入这个静态方法

    static void ASAudioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)

    {

    [[ToolManager defaultManager] handleInterruption:inInterruptionState];

    }

    每次打断结束或者开始都会调用这个方法  ,inInterruptionState来判断是开始还是结束,因为是C函数,不可以直接调用类中[self  xxx]方法,通知也没用 ,故写了个单例类,接收这个参数,然后进行判断

    - (void)handleInterruptionChangeToState:(NSNotification *)notification

    {

    AudioQueuePropertyID inInterruptionState=[[notification object] longValue];

    if (inInterruptionState == kAudioSessionBeginInterruption)

    {

    NSLog(@”begin interruption——->”);

    }

    else if (inInterruptionState == kAudioSessionEndInterruption)

    {

    NSLog(@”end interruption——->”);

    }

  • 相关阅读:
    大数据之路Week08_day02 (Flume架构介绍和安装)
    Hive调优
    hive的shell用法(脑子糊涂了,对着脚本第一行是 #!/bin/sh 疯狂执行hive -f 结果报错)
    Week08_day01 (Hive 自定义函数 UDF 一个输入,一个输出(最常用))
    Week08_day01 (Hive开窗函数 row_number()的使用 (求出所有薪水前两名的部门))
    Week08_day01 (Hive实现按照指定格式输出每七天的消费平均数)
    Week08_day01 (Hive实现WordCount计数)
    SQL中 count(*)和count(1)的对比,区别
    大数据之路week07--day07 (修改mysql默认编码)
    10进制转换成16进制的函数(自写函数模板)
  • 原文地址:https://www.cnblogs.com/Milo-CTO/p/4446318.html
Copyright © 2011-2022 走看看