標籤:
在沒有網路的情況下,音訊後台播放比較簡單,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一般用於支援後台播放,在官方文檔可以看到其他的類型,每個分別適用於不同的場合:
| 123456789101112131415161718192021 |
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]] > ; |
除了代碼的初始化,很重要的一步是對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——->”);
}
}
iOS音訊後台播放總結