iOS音頻的後臺播放總結(後臺網絡請求歌曲,Remote控制,鎖屏封面,各種打斷)

在沒有網絡的情況下,音頻的後臺播放比較簡單,google一下可以搜到很多資料,但是如果每次歌曲的請求都是通過網絡,就不成了,有時可以也扛不了幾首,這裏總結下實現方法,可以實現像電臺一樣的功能,後臺播放,網絡請求歌曲,Remote控制,鎖屏有封面,電話和聽歌打斷處理等。

 

 

初始化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一般用於支持後臺播放,在官方文檔可以看到其他的類型,每個分別適用於不同的場合:


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_Cla***eference/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_Cla***eference/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_Cla***eference/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_Cla***eference/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_Cla***eference/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_Cla***eference/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_Cla***eference/Reference/Reference.html#//apple_ref/doc/c_ref/AVAudioSessionCategoryMultiRoute">

<blockquote>AVAudioSessionCategoryMultiRoute</blockquote>

</a>;


1


 


除了代碼的初始化,很重要的一步是對info-plist的設置,讓應用支持音頻的後臺播放

庫的引入包括:

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——->”);

 

}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章