音頻方面的知識,相對其他程式設計還是較為複雜的,特别是要搞清楚架構裡具體使用的參數和方法,不然寫起代碼來非常迷茫.
1:播放簡短性質的音頻,例如按鍵聲音,等可以這樣實作.
一:引入架構:
[csharp] view plain copy
- #import <AudioToolbox/AudioToolbox.h>
二:先聲明一個聲音源ID [csharp] view plain copy
- SystemSoundID _bookSoundID;
三:提供需要播放的音頻位址進行聲音源的注冊. [csharp] view plain copy
- NSURL *bookSoundUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"bookSound" ofType:@"wav"]];
- AudioServicesCreateSystemSoundID((__bridge CFURLRef)bookSoundUrl, &_bookSoundID);
四:在需要的時候播放: [csharp] view plain copy
- AudioServicesPlaySystemSound(_bookSoundID);
五:不用的聲音源記得釋放掉 [csharp] view plain copy
- AudioServicesDisposeSystemSoundID(_bookSoundID);
2: 關于 AVAudioSession 的使用
首先知道 AVAudioSession 是一個單例模式,也就是說,不用開發者自行執行個體化. 這個類在各種音頻環境中起着非常重要的作用
一:首先是設定 AVAudioSession 的 類别
擷取輸入硬 件 擷取輸出硬體 與IPOD混合 遵從振鈴/靜音按鍵
AVAudioSessionCategoryAmbient 否 是 是 是
AVAudioSessionCategorySoloAmbient 否 是 否 是
AVAudioSessionCategoryPlayback 否 是 否 否
AVAudioSessionCategoryRecord 是 否 否 否
AVAudioSessionCategoryPlayAndRecord 是 是 否 否
根據實際的使用情況來設定具體的類别,設定代碼如下:
[csharp] view plain copy
- AVAudioSession * audioSession = [AVAudioSession sharedInstance]; //得到AVAudioSession單例對象
- [audioSession setDelegate:self];//設定代理
- [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error];//設定類别,表示該應用同時支援播放和錄音
- [audioSession setActive:YES error: &error];//啟動音頻會話管理,此時會阻斷背景音樂的播放.
二:在錄制完聲音或者播放完聲音後,可以将音頻會話關閉,來延續背景音樂的播放,代碼如下: [csharp] view plain copy
- [[AVAudioSession sharedInstance] setActive:NO error: nil];
三:通過音頻會話可以強制的設定應用程式使用指定的輸出方式,例如:内聲道,揚聲器,代碼如下: [csharp] view plain copy
- UInt32 audioRouteOverride = hasHeadset ?kAudioSessionOverrideAudioRoute_None:kAudioSessionOverrideAudioRoute_Speaker;
- AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
kAudioSessionOverrideAudioRoute_None 内聲道,耳機
kAudioSessionOverrideAudioRoute_Speaker 揚聲器
四:那麼怎麼判斷使用者是否已經插入耳機?代碼如下: (參考:http://iandworld.sinaapp.com/?p=184001)
[csharp] view plain copy
- - (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);
- 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:注冊監聽事件,和回調函數
[csharp] view plain copy
- AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
- audioRouteChangeListenerCallback,
- self);
2:實作回調函數進行相關處理: [csharp] view plain copy
- 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.
- CFDictionaryRef routeChangeDictionary = 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"鍵,其值設定如下圖所示:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5IjN38VOyMTO0IDM2MTMvw1Nw8CXyAzMxAjMvw1ckF2bsBXdvwFdl5mLuR2cj5Set1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2:系統音頻服務支援音頻播放,并關閉其他正在播放的音頻
[csharp] view plain copy
- AVAudioSession *session = [AVAudioSession sharedInstance];
- [session setActive:YES error:nil];
- [session setCategory:AVAudioSessionCategoryPlayback error:nil];
3: 設定app支援接受遠端控制事件代碼:
[csharp] view plain copy
- [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
設定app支援接受遠端控制事件,其實就是在dock中可以顯示應用程式圖示,同時點選該圖檔時,打開app,如下圖所示:
4:執行 AVAudioPlayer
七 關于音量
1:由應用主動擷取系統音量
[csharp] view plain copy
- UInt32 dataSize = sizeof(float);
- AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareOutputVolume,
- &dataSize,
- &keyVolume);
擷取之前要確定
[csharp] view plain copy
- 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 等等 去實作線上播放,也是可以的,但是如果要實作更多更能,還是别折騰這玩意,浪費生命.