您的位置:首页 > 理论基础 > 计算机网络

iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断)

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









初始化AudioSession和基本配置

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

[objc] view
plaincopy





-(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



***AudioSession *session = [***AudioSession sharedInstance];



NSError *setCategoryError = nil;



BOOL success = [session setCategory:***AudioSessionCategoryPlayback 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用于处理中断处理,***AudioSession主要调用setCategory和setActive方法来进行设置,***AudioSessionCategoryPlayback一般用于支持后台播放,在官方文档可以看到其他的类型,每个分别适用于不同的场合:

123456789101112131415161718192021NSString *const <a href="file:///Users/lipengxuan/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS6.0.iOSLibrary.docset/Contents/Resources/Documents/documentation/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryAmbient"><blockquote>***AudioSessionCategoryAmbient</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategorySoloAmbient"><blockquote>***AudioSessionCategorySoloAmbient</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryPlayback"><blockquote>***AudioSessionCategoryPlayback</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryRecord"><blockquote>***AudioSessionCategoryRecord</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryPlayAndRecord"><blockquote>***AudioSessionCategoryPlayAndRecord</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryAudioProcessing"><blockquote>***AudioSessionCategoryAudioProcessing</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/***Foundation/Reference/***AudioSession_ClassReference/Reference/Reference.html#//apple_ref/doc/c_ref/***AudioSessionCategoryMultiRoute"><blockquote>***AudioSessionCategoryMultiRoute</blockquote></a>;
1

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





库的引入包括:

AudioToolBox.framework

MediaPlayer.framework

CoreMedia.framework

***Foundation.framework



后台播放

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

[objc] view
plaincopy





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



[application beginReceivingRemoteControlEvents];

}

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

[objc] view
plaincopy





-(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里加上这两个函数:

[objc] view
plaincopy





- (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控制



然后添加下面的代码:



[objc] view
plaincopy





-(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;



}


锁屏封面

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

[objc] view
plaincopy





- (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前面加入这个静态方法

[objc] view
plaincopy





static void ASAudioSessionInterruptionListener(voidvoid *inClientData, UInt32 inInterruptionState)



{



[[ToolManager defaultManager] handleInterruption:inInterruptionState];



}

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

[objc] view
plaincopy





- (void)handleInterruptionChangeToState:(NSNotification *)notification



{



AudioQueuePropertyID inInterruptionState=[[notification object] longValue];







if (inInterruptionState == kAudioSessionBeginInterruption)



{



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



}



else if (inInterruptionState == kAudioSessionEndInterruption)



{



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







}



}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐