天天看點

iOS 關于音頻開發

音頻方面的知識,相對其他程式設計還是較為複雜的,特别是要搞清楚架構裡具體使用的參數和方法,不然寫起代碼來非常迷茫.

1:播放簡短性質的音頻,例如按鍵聲音,等可以這樣實作.

一:引入架構:

[csharp] view plain copy

  1. #import <AudioToolbox/AudioToolbox.h>  

二:先聲明一個聲音源ID [csharp] view plain copy

  1. SystemSoundID _bookSoundID;  

三:提供需要播放的音頻位址進行聲音源的注冊. [csharp] view plain copy

  1. NSURL *bookSoundUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"bookSound" ofType:@"wav"]];  
  2. AudioServicesCreateSystemSoundID((__bridge CFURLRef)bookSoundUrl, &_bookSoundID);  

四:在需要的時候播放: [csharp] view plain copy

  1. AudioServicesPlaySystemSound(_bookSoundID);  

五:不用的聲音源記得釋放掉 [csharp] view plain copy

  1. AudioServicesDisposeSystemSoundID(_bookSoundID);  

2: 關于 AVAudioSession 的使用

首先知道 AVAudioSession  是一個單例模式,也就是說,不用開發者自行執行個體化. 這個類在各種音頻環境中起着非常重要的作用

一:首先是設定 AVAudioSession 的 類别

                                                                                      擷取輸入硬 件          擷取輸出硬體       與IPOD混合      遵從振鈴/靜音按鍵

AVAudioSessionCategoryAmbient                            否                               是                          是                         是

AVAudioSessionCategorySoloAmbient                    否                              是                           否                         是

AVAudioSessionCategoryPlayback                          否                               是                           否                        否

AVAudioSessionCategoryRecord                              是                              否                           否                         否

AVAudioSessionCategoryPlayAndRecord              是                              是                           否                         否

根據實際的使用情況來設定具體的類别,設定代碼如下:

[csharp] view plain copy

  1. AVAudioSession * audioSession = [AVAudioSession sharedInstance]; //得到AVAudioSession單例對象  
  2. [audioSession setDelegate:self];//設定代理  
  3. [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &error];//設定類别,表示該應用同時支援播放和錄音  
  4. [audioSession setActive:YES error: &error];//啟動音頻會話管理,此時會阻斷背景音樂的播放.  

二:在錄制完聲音或者播放完聲音後,可以将音頻會話關閉,來延續背景音樂的播放,代碼如下: [csharp] view plain copy

  1. [[AVAudioSession sharedInstance] setActive:NO error: nil];  

三:通過音頻會話可以強制的設定應用程式使用指定的輸出方式,例如:内聲道,揚聲器,代碼如下: [csharp] view plain copy

  1. UInt32 audioRouteOverride = hasHeadset ?kAudioSessionOverrideAudioRoute_None:kAudioSessionOverrideAudioRoute_Speaker;  
  2. AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);  

kAudioSessionOverrideAudioRoute_None  内聲道,耳機

kAudioSessionOverrideAudioRoute_Speaker 揚聲器

四:那麼怎麼判斷使用者是否已經插入耳機?代碼如下: (參考:http://iandworld.sinaapp.com/?p=184001)

[csharp] view plain copy

  1. - (BOOL)hasHeadset {  
  2. //模拟器不支援  
  3. #if TARGET_IPHONE_SIMULATOR  
  4.     #warning *** Simulator mode: audio session code works only on a device  
  5.     return NO;  
  6. #else  
  7.     CFStringRef route;  
  8.     UInt32 propertySize = sizeof(CFStringRef);  
  9.     AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route);  
  10.     if((route == NULL) || (CFStringGetLength(route) == 0)){  
  11.         // Silent Mode  
  12.         NSLog(@"AudioRoute: SILENT, do nothing!");  
  13.     } else {  
  14.         NSString* routeStr = (__bridge NSString*)route;  
  15.         NSLog(@"AudioRoute: %@", routeStr);  
  16.         NSRange headphoneRange = [routeStr rangeOfString : @"Headphone"];  
  17.         NSRange headsetRange = [routeStr rangeOfString : @"Headset"];  
  18.         if (headphoneRange.location != NSNotFound) {  
  19.             return YES;  
  20.         } else if(headsetRange.location != NSNotFound) {  
  21.             return YES;  
  22.         }  
  23.     }  
  24.     return NO;  
  25. #endif  
  26. }  

傳回YES,表示已經插入耳機,傳回NO表示沒有插入耳機

五:監聽使用者拔出插入耳機事件

1:注冊監聽事件,和回調函數

[csharp] view plain copy

  1. AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,  
  2.                                      audioRouteChangeListenerCallback,  
  3.                                      self);  

2:實作回調函數進行相關處理: [csharp] view plain copy

  1. void audioRouteChangeListenerCallback (  
  2.                                        void                      *inUserData,  
  3.                                        AudioSessionPropertyID    inPropertyID,  
  4.                                        UInt32                    inPropertyValueSize,  
  5.                                        const void                *inPropertyValue  
  6.                                        ) {  
  7.     if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;  
  8.     // Determines the reason for the route change, to ensure that it is not  
  9.     //      because of a category change.  
  10.     CFDictionaryRef routeChangeDictionary = inPropertyValue;  
  11.     CFNumberRef routeChangeReasonRef =  
  12.     CFDictionaryGetValue (routeChangeDictionary,  
  13.                           CFSTR (kAudioSession_AudioRouteChangeKey_Reason));  
  14.     SInt32 routeChangeReason;  
  15.     CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);  
  16.     NSLog(@" ===================================== RouteChangeReason : %d", routeChangeReason);  
  17.     AudioHelper *_self = (AudioHelper *) inUserData;  
  18.     if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {  
  19.         [_self resetSettings];  
  20.         if (![_self hasHeadset]) {  
  21.             [[NSNotificationCenter defaultCenter] postNotificationName:@"ununpluggingHeadse"  
  22.                                                                 object:nil];  
  23.         }  
  24.     } else if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) {  
  25.         [_self resetSettings];  
  26.         if (![_self hasMicphone]) {  
  27.             [[NSNotificationCenter defaultCenter] postNotificationName:@"pluggInMicrophone"  
  28.                                                                 object:nil];  
  29.         }  
  30.     } else if (routeChangeReason == kAudioSessionRouteChangeReason_NoSuitableRouteForCategory) {  
  31.         [_self resetSettings];  
  32.         [[NSNotificationCenter defaultCenter] postNotificationName:@"lostMicroPhone"  
  33.                                                             object:nil];  
  34.     }  
  35.     //else if (routeChangeReason == kAudioSessionRouteChangeReason_CategoryChange  ) {  
  36.     //    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];  
  37.     //}  
  38.     [_self printCurrentCategory];  
  39. }  

六:如何保持背景音樂的一直播放呢? (參考:http://blog.csdn.net/yhawaii/article/details/7788340)

1:在Info.plist中,添加"Required background modes"鍵,其值設定如下圖所示:

iOS 關于音頻開發

2:系統音頻服務支援音頻播放,并關閉其他正在播放的音頻

[csharp] view plain copy

  1. AVAudioSession *session = [AVAudioSession sharedInstance];  
  2. [session setActive:YES error:nil];  
  3. [session setCategory:AVAudioSessionCategoryPlayback error:nil];  

3: 設定app支援接受遠端控制事件代碼:

[csharp] view plain copy

  1. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];  

設定app支援接受遠端控制事件,其實就是在dock中可以顯示應用程式圖示,同時點選該圖檔時,打開app,如下圖所示:

iOS 關于音頻開發

4:執行 AVAudioPlayer  

七 關于音量

1:由應用主動擷取系統音量

[csharp] view plain copy

  1. UInt32 dataSize = sizeof(float);  
  2. AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareOutputVolume,  
  3.                                            &dataSize,  
  4.                                            &keyVolume);  

擷取之前要確定

[csharp] view plain copy

  1. AVAudioSession *session = [AVAudioSession sharedInstance];  
  2. [session setActive:YES error:nil];  
  3. [session setCategory:AVAudioSessionCategoryPlayback error:nil];  

2:由應用主動設定系統音量 (參考:http://blog.csdn.net/studyrecord/article/details/6452354)

八:關于音頻邊下載下傳邊播放的實作.

請參考:AudioStreamer

https://github.com/mattgallagher/AudioStreamer

如果你隻是想簡簡單單線上播放以下不做任何處理. 那使用AVPlayer 等等 去實作線上播放,也是可以的,但是如果要實作更多更能,還是别折騰這玩意,浪費生命.