音頻在靜音情況下正常播放聲音

這就要說到

AVAudioSession-Category的正確使用姿勢

解決問題代碼如下

// 使用這個category的應用不會隨著手機靜音鍵打開而靜音,可在手機靜音下播放聲音
    NSError *setCategoryError = nil;
    BOOL success = [[AVAudioSession sharedInstance]
                    setCategory: AVAudioSessionCategoryPlayback
                    error: &setCategoryError];
    
    if (!success) { /* handle the error in setCategoryError */ }

最近,在開發(fā)一款音樂播放器類型項目中遇到的一些與AVAudioSession-Category設置的一些坑,以下是整個過程的一些經(jīng)驗總結。
1.常規(guī)播放
一般如果應用只有簡單音樂播放功能梦谜,那么我們的AVAudioSession-Category只用像如下一樣設置即可:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];     [[AVAudioSession sharedInstance] setActive:YES error:nil];

此時如果我們只是播放音樂,而不需要獨占鎖屏界面時袭景,還可以設置:

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
                                     withOptions:AVAudioSessionCategoryOptionMixWithOthers
                                           error:nil];

這樣我們兼容其他后臺播放的音樂一起進行播放唁桩,不過大部分場景下,我們是需要獨占式后臺播放耸棒。
2.常規(guī)錄音
在錄音的時候荒澡,我們一般如以下設置:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];     
[[AVAudioSession sharedInstance] setActive:YES error:nil];

3.如果將錄音和播放同時進行時,我們改選擇何種Category与殃?
同時進行播放和錄音時单山,我們需要這樣設置:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord                                            error:nil];     
[[AVAudioSession sharedInstance] setActive:YES error:nil];

需要注意的是,設置成這樣的情況下幅疼,如果米奸,在錄音未開啟的情況下,直接進行播放爽篷,則會出現(xiàn)悴晰,播放音量特別小的情況,我們需要在播放之前狼忱,將錄音打開膨疏。
4.前后臺切換
上述的模式,在iOS系統(tǒng)下钻弄,是不允許錄音和播放在后臺狀態(tài)下同時進行的(PS:語音視頻通話是通過CallKit實現(xiàn)的,不用于常規(guī)的播放和錄音功能)者吁。由此窘俺,我們在應用進入后臺時就需要關掉其中一個功能。
以后臺支持播放為例,在應用將要失活時瘤泪,先切換模式灶泵,再關掉錄音功能:

// stopRecording...
// 切換模式
  [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
  [[AVAudioSession sharedInstance] setActive:YES error:nil];

應用即將進入前臺時,切換模式对途,再開啟錄音功能:

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord                                            error:nil];
    [[AVAudioSession sharedInstance] setActive:YES                                          error:nil];

// 延遲恢復赦邻,否則會導致AVAudioSession的i/o錯誤

    [self performSelectorOnMainThread:@selector(startRecording) withObject:nil waitUntilDone:NO];

5.電話中斷
電話鬧鐘的中斷也會對,[AVAudioSession sharedInstance] 產(chǎn)生影響实檀。
我們一般場景下會用 下面這個通知進行監(jiān)控并處理暫停和恢復的工作:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:nil]; 
- (void)handleInterruption:(NSNotification*)notification { NSLog(@"interruption info:%@",notification.userInfo); }

但是惶洲,當我們在處理第四個場景前后臺的情況下,這個通知膳犹,在中斷的時候會進入恬吕,但是電話結束后,不會再接收到中斷結束的通知须床。
原因:
有的app使用了AVCaptureDevice和AVCaptureSession铐料,以進行錄音錄像操作。為了調優(yōu)app設置豺旬,以更好的進行錄音錄像钠惩,從iOS7開始,在默認情況下族阅,AVCaptureSession會使用app的AVAudioSession篓跛,并對其進行修改。這樣耘分,設置的中斷監(jiān)聽方法會失效举塔。
而電話來電也會使我們的應用接收到 失活的通知,在失活的時候處理了AVAudioSession求泰,就會導致上述通知失效央渣。
解決方案:我這里采用了比較折中的方案,因為我們的需求渴频,對于第四條的處理是必要的芽丹。使用的是 CoreTelephony框架下的CTCallCenter對象,來監(jiān)控電話的 撥入接通卜朗、掛斷等狀態(tài)拔第。代碼如下:

self.center = [[CTCallCenter alloc] init];
// TODO: 檢測到來電后的處理
self.center.callEventHandler = ^(CTCall * call){
    if (call.callState == CTCallStateIncoming ||
        call.callState == CTCallStateConnected ||
        call.callState == CTCallStateDialing)
    {
    }
    else if (call.callState == CTCallStateDisconnected)
    {
    }
};

通過各種打電話的場景測試后,可以實現(xiàn)電話中斷恢復功能场钉。
ps:至于鬧鐘的中斷以及siri等其他中斷蚊俺,暫時沒有調研和實現(xiàn)。
6.藍牙車載
終于來到了本文的最后一個部分了逛万,也是最為曲折的一部分泳猬。
本來以為車載的車機連接后對于iPhone的播放控制與鎖屏控制類似,直接在系統(tǒng)媒體遠程控制監(jiān)控中就能夠拿到相應的控制方法回調。
在APPDelegate中加上如下代碼:

//監(jiān)聽遠程交互方法
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
    switch (event.subtype)
    {
            //播放
        case UIEventSubtypeRemoteControlPlay:
            break;
            //停止
        case UIEventSubtypeRemoteControlPause:
            break;
            //下一首
        case UIEventSubtypeRemoteControlNextTrack:
            break;
            //上一首
        case UIEventSubtypeRemoteControlPreviousTrack:
            break;
        default:
          break;
    }
}

事實上得封,當我們的應用只有簡單的播放功能的時候埋心,上述代碼的確可以完美的實現(xiàn)車機對于播放的控制功能。但是當應用出于前臺的情況下忙上,我們添加上了一直錄音的功能的時候拷呆,用車機控制播放,就完全沒有任何響應了疫粥〔绺可以注意到的是,我們看到車機的屏幕上手形,會顯示通話中啥供。查閱了各種資料和文章,都沒有找到相關的解決辦法和原理解釋库糠。
最后伙狐,想到了看看有沒有其他類似的語音識別及播放功能的應用(iOS)有沒有類似的處理,結果調研到百度地圖 中的小度 有相關的處理瞬欧。在它的設置中贷屎,找到 語音設置有一個藍牙連接設置 。兩個模式設置 如下:
a.藍牙設備播報艘虎,小度無法喚醒使用(播放體驗最佳)
b.藍牙設備播報唉侄,小度喚醒正常使用(車機顯示通話中,播報音量可能變小)
由此可以看出野建,a場景下 錄音功能關閉属划,只有語音播報功能,b場景下候生,錄音功能開啟同眯,車機就是會識別到手機設備在錄音和播放中,認為就是在通話中唯鸭,這個是車機本身的限制须蜗,無法從應用層進行優(yōu)化。而且目溉,百度地圖的給用的默認選擇就是明肮,連接藍牙的情況下,小度不能喚醒缭付。
綜合上面我們協(xié)同產(chǎn)品柿估,從交互層面上更改,保證陷猫,在連接車機的情況下官份,能夠控制播放只厘。具體處理交互如下:
在應用進入到前臺時烙丛,檢測到連接了藍牙設備舅巷,彈出彈框,讓用戶選擇河咽,繼續(xù)開啟喚醒功能開始钠右,關閉喚醒功能(保證播放控制功能)。繼續(xù)開啟的情況下忘蟹,車機無法控制播放飒房。
下面是檢測是否有輸出設備連接的代碼(并未找到檢查當前是否有連接藍牙設備的方法):

+ (BOOL)checkIsConnectToBluetooth
{
    BOOL isBluetooth = NO;
    // 找出當前所有支持輸入的設備  availableInputs 這里面會出現(xiàn) iPhone麥克風, 藍牙耳機1, 藍牙耳機2 , 三個對象, 在一個數(shù)組里.
    NSArray* inputArray = [[AVAudioSession sharedInstance] availableInputs];
    for (AVAudioSessionPortDescription* desc in inputArray)
    {
        if ([desc.portType isEqualToString:AVAudioSessionPortBluetoothLE] ||
            [desc.portType isEqualToString:AVAudioSessionPortBluetoothHFP] ||
            [desc.portType isEqualToString:AVAudioSessionPortBluetoothA2DP])
        {
            isBluetooth = YES;
        }
    }
    return isBluetooth;
}

同時,還需要配合Category的設置:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord                                          withOptions:AVAudioSessionCategoryOptionAllowBluetooth                                                error:&error];        
[[AVAudioSession sharedInstance] setActive:YES error:&error1];

AVAudioSessionCategoryOptionAllowBluetooth這是必須要添加的媚值,否則上面的方法狠毯,連接藍牙后,在應用即將活躍的監(jiān)控的時候褥芒,是會返回NO嚼松,拿不到準確的值。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末锰扶,一起剝皮案震驚了整個濱河市献酗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坷牛,老刑警劉巖罕偎,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異京闰,居然都是意外死亡颜及,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門蹂楣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俏站,“玉大人,你說我怎么就攤上這事捐迫∏瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵施戴,是天一觀的道長反浓。 經(jīng)常有香客問我,道長赞哗,這世上最難降的妖魔是什么雷则? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮肪笋,結果婚禮上月劈,老公的妹妹穿的比我還像新娘度迂。我一直安慰自己,他們只是感情好猜揪,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布惭墓。 她就那樣靜靜地躺著,像睡著了一般而姐。 火紅的嫁衣襯著肌膚如雪腊凶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天拴念,我揣著相機與錄音钧萍,去河邊找鬼。 笑死政鼠,一個胖子當著我的面吹牛风瘦,可吹牛的內容都是我干的。 我是一名探鬼主播公般,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼万搔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了俐载?” 一聲冷哼從身側響起蟹略,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遏佣,沒想到半個月后挖炬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡状婶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年意敛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膛虫。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡草姻,死狀恐怖,靈堂內的尸體忽然破棺而出稍刀,到底是詐尸還是另有隱情撩独,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布账月,位于F島的核電站综膀,受9級特大地震影響,放射性物質發(fā)生泄漏局齿。R本人自食惡果不足惜剧劝,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抓歼。 院中可真熱鬧讥此,春花似錦拢锹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至取胎,卻和暖如春展哭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闻蛀。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留您市,地道東北人觉痛。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像茵休,于是被迫代替她去往敵國和親薪棒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345