音頻方面的知識,相對其他編程還是較為複雜的,特別是要搞清楚架構裡具體使用的參數和方法,不然寫起代碼來非常迷茫.
1:播放簡短性質的音頻,例如按鍵聲音,等可以這樣實現.
一:引入架構:
#import <AudioToolbox/AudioToolbox.h>
二:先聲明一個聲音源ID
SystemSoundID _bookSoundID;
三:提供需要播放的音頻地址進行聲音源的註冊.
NSURL *bookSoundUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"bookSound" ofType:@"wav"]]; AudioServicesCreateSystemSoundID((__bridge CFURLRef)bookSoundUrl, &_bookSoundID);
四:在需要的時候播放:
AudioServicesPlaySystemSound(_bookSoundID);
五:不用的聲音源記得釋放掉
AudioServicesDisposeSystemSoundID(_bookSoundID);
2: 關於 AVAudioSession 的使用
首Crowdsourced Security Testing道 AVAudioSession 是一個單例模式,也就是說,不用開發人員自行執行個體化. 這個類在各種音頻環境中起著非常重要的作用
一:首先是設定 AVAudioSession 的 類別
擷取輸入硬 件 擷取輸出硬體 與IPOD混合 遵從響鈴/靜音按鍵
AVAudioSessionCategoryAmbient 否 是 是 是
AVAudioSessionCategorySoloAmbient 否 是 否 是
AVAudioSessionCategoryPlayback 否 是 否 否
AVAudioSessionCategoryRecord 是 否 否 否
AVAudioSessionCategoryPlayAndRecord 是 是 否 否
根據實際的使用方式來設定具體的類別,設定代碼如下:
AVAudioSession * audioSession = [AVAudioSession sharedInstance]; //得到AVAudioSession單例對象[audioSession setDelegate:self];//設定代理[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error];//設定類別,表示該應用同時支援播放和錄音[audioSession setActive:YES error: &error];//啟動音頻會話管理,此時會阻斷後台音樂的播放.
二:在錄製完聲音或者播放完聲音後,可以將音頻會話關閉,來延續後台音樂的播放,代碼如下:
[[AVAudioSession sharedInstance] setActive:NO error: nil];
三:通過音頻會話可以強制的設定應用程式使用指定的輸出方式,例如:內聲道,擴音器,代碼如下:
UInt32 audioRouteOverride = hasHeadset ?kAudioSessionOverrideAudioRoute_None:kAudioSessionOverrideAudioRoute_Speaker; AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
kAudioSessionOverrideAudioRoute_None 內聲道,耳機
kAudioSessionOverrideAudioRoute_Speaker 擴音器
四:那麼怎麼判斷使用者是否已經插入耳機?代碼如下: (參考:http://iandworld.sinaapp.com/?p=184001)
- (BOOL)hasHeadset {//模擬器不支援#if TARGET_IPHONE_SIMULATOR #warning *** Simulator mode: audio session code works only on a device return NO;#else CFStringRef route; UInt32 propertySize = sizeof(CFStringRef); AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route); if((route == NULL) || (CFStringGetLength(route) == 0)){ // Silent Mode NSLog(@"AudioRoute: SILENT, do nothing!"); } else { NSString* routeStr = (__bridge NSString*)route; NSLog(@"AudioRoute: %@", routeStr); /* Known values of route: * "Headset" * "Headphone" * "Speaker" * "SpeakerAndMicrophone" * "HeadphonesAndMicrophone" * "HeadsetInOut" * "ReceiverAndMicrophone" * "Lineout" */ NSRange headphoneRange = [routeStr rangeOfString : @"Headphone"]; NSRange headsetRange = [routeStr rangeOfString : @"Headset"]; if (headphoneRange.location != NSNotFound) { return YES; } else if(headsetRange.location != NSNotFound) { return YES; } } return NO;#endif }
返回YES,表示已經插入耳機,返回NO表示沒有插入耳機
五:監聽使用者拔出插入耳機事件
1:註冊監聽事件,和回呼函數
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, audioRouteChangeListenerCallback, self);
2:實現回呼函數進行相關處理:
void audioRouteChangeListenerCallback ( void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue ) { if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return; // Determines the reason for the route change, to ensure that it is not //because of a category change. CFDictionaryRefrouteChangeDictionary = inPropertyValue; CFNumberRef routeChangeReasonRef = CFDictionaryGetValue (routeChangeDictionary, CFSTR (kAudioSession_AudioRouteChangeKey_Reason)); SInt32 routeChangeReason; CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason); NSLog(@" ===================================== RouteChangeReason : %d", routeChangeReason); AudioHelper *_self = (AudioHelper *) inUserData; if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) { [_self resetSettings]; if (![_self hasHeadset]) { [[NSNotificationCenter defaultCenter] postNotificationName:@"ununpluggingHeadse" object:nil]; } } else if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) { [_self resetSettings]; if (![_self hasMicphone]) { [[NSNotificationCenter defaultCenter] postNotificationName:@"pluggInMicrophone" object:nil]; } } else if (routeChangeReason == kAudioSessionRouteChangeReason_NoSuitableRouteForCategory) { [_self resetSettings]; [[NSNotificationCenter defaultCenter] postNotificationName:@"lostMicroPhone" object:nil]; } //else if (routeChangeReason == kAudioSessionRouteChangeReason_CategoryChange ) { // [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; //} [_self printCurrentCategory];}
六:如何保持後台音樂的一直播放呢? (參考:http://blog.csdn.net/yhawaii/article/details/7788340)
1:在Info.plist中,添加"Required background modes"鍵,其值設定如所示:
2:系統音頻服務支援音頻播放,並關閉其他現正播放的音頻
AVAudioSession *session = [AVAudioSession sharedInstance];[session setActive:YES error:nil];[session setCategory:AVAudioSessionCategoryPlayback error:nil];
3:設定app支援接受遠端控制事件代碼:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
設定app支援接受遠端控制事件,其實就是在dock中可以顯示應用程式圖示,同時點擊該圖片時,開啟app,如所示:
4:執行 AVAudioPlayer
七 關於音量
1:由應用主動擷取系統音量
UInt32 dataSize = sizeof(float);AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareOutputVolume, &dataSize, &keyVolume);
擷取之前要確保
AVAudioSession *session = [AVAudioSession sharedInstance];[session setActive:YES error:nil];[session setCategory:AVAudioSessionCategoryPlayback error:nil];
2:由應用主動設定系統音量 (參考:http://blog.csdn.net/studyrecord/article/details/6452354)
八:關於音頻邊下載邊播放的實現.
請參考:AudioStreamer
https://github.com/mattgallagher/AudioStreamer
如果你只是想簡簡單單線上播放以下不做任何處理. 那使用AVPlayer 等等 去實現線上播放,也是可以的,但是如果要實現更多更能,還是別折騰這玩意,浪費生命.