如何監(jiān)聽(tīng)iOS設(shè)備靜音按鈕的狀態(tài)

通過(guò)使用指定方式播放一段極小音頻,比較播放的開(kāi)始和完成時(shí)間皆辽,來(lái)判斷當(dāng)前靜音按鈕的狀態(tài)萨赁。
我也針對(duì)常見(jiàn)的對(duì)音量方面的需求做了一個(gè)小工具弊琴,歡迎大家使用、指正位迂。


2018年9月6日更新:
1.【修正】——App從后臺(tái)切到前臺(tái)時(shí)【AVPlayerItemDidPlayToEndTimeNotification】通知被無(wú)故調(diào)用的問(wèn)題访雪;
2.【修正】——在有其他音/視頻播放時(shí)详瑞,初始化該工具會(huì)使正在播放的音/視頻間斷一下的問(wèn)題掂林。

解釋下第一個(gè)bug:實(shí)際使用中發(fā)現(xiàn),在使用原有AVPlayerItem的方式進(jìn)行預(yù)播放音頻后(用于本文最后說(shuō)的那個(gè)小坑)坝橡,使用AVPlayer正常播放音/視頻泻帮,此時(shí)將App從后臺(tái)切換到前臺(tái),用于預(yù)播放音頻的AVPlayerItem會(huì)無(wú)故發(fā)出AVPlayerItemDidPlayToEndTimeNotification的通知计寇,可能會(huì)影響到業(yè)務(wù)層锣杂。
為什么說(shuō)是無(wú)故呢?因?yàn)锳pp從后臺(tái)切換到前臺(tái)時(shí)番宁,預(yù)播放音頻早已經(jīng)結(jié)束了很久元莫,而且,當(dāng)時(shí)結(jié)束時(shí)已經(jīng)發(fā)出過(guò)AVPlayerItemDidPlayToEndTimeNotification通知了蝶押;也就是說(shuō)踱蠢,本已結(jié)束的音/視頻,會(huì)由于從后臺(tái)切到前臺(tái)而反復(fù)發(fā)出AVPlayerItemDidPlayToEndTimeNotification通知(這也是很神奇棋电,并沒(méi)有想通是什么原理茎截,也沒(méi)有查到相關(guān)的資料苇侵,如有大神了解,希望您不吝賜教~)企锌。


剛開(kāi)始看到這個(gè)需求的時(shí)候榆浓,覺(jué)得這個(gè)應(yīng)該會(huì)有相應(yīng)的api,直接調(diào)用就可以了撕攒。但是實(shí)際一查才發(fā)現(xiàn):并沒(méi)有陡鹃,準(zhǔn)確的說(shuō)是iOS5之后的版本相關(guān)api就不再支持了。細(xì)想下抖坪,其實(shí)這也挺符合Apple的行事作風(fēng)的杉适,app只要為用戶提供服務(wù)就好了,用戶的操作并不會(huì)讓你知曉柳击,極盡的保護(hù)用戶的一切隱私猿推。

那么在iOS5之后,我們?cè)跊](méi)有直接api的情況下捌肴,應(yīng)該如何檢測(cè)設(shè)備靜音按鈕處于什么狀態(tài)呢蹬叭?曲線救國(guó)~

首先鳴謝下RBDMuteSwitch這個(gè)庫(kù)。因?yàn)槲宜褂煤诵姆椒ㄒ彩墙梃b了這個(gè)庫(kù)中的方式來(lái)實(shí)現(xiàn)状知。

  • 首先秽五,這里我們要使用到一種平時(shí)不是很常用的播放音頻的方式
-(void)monitorMute{

    CFURLRef soundFileURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("detection"), CFSTR("aiff"), NULL);
    SystemSoundID soundFileID;
    AudioServicesCreateSystemSoundID(soundFileURLRef, &soundFileID);
    AudioServicesAddSystemSoundCompletion(soundFileID, NULL, NULL, soundCompletionBlock, (__bridge void*) self);
    AudioServicesPlaySystemSound(soundFileID);
    
}

static void soundCompletionBlock(SystemSoundID SSID, void *mySelf){
    AudioServicesRemoveSystemSoundCompletion(SSID);
    [[XTVolumeMonitor defaultMonitor] playToEnd];
}

AudioServicesPlaySystemSound方法支持的格式少,而且還要求音頻時(shí)長(zhǎng)為30s以下饥悴,但是坦喘,他有一個(gè)對(duì)我們最有用的特性:如果靜音按鈕為靜音狀態(tài),那么會(huì)《立即》執(zhí)行預(yù)先植入的soundCompletionBlock西设。相信到這您就可以瞬間想通后面的一切問(wèn)題了~

針對(duì)這一特性瓣铣,我通過(guò)記錄開(kāi)始播放和完成播放的時(shí)間,計(jì)算二者的差值贷揽,來(lái)判斷靜音按鈕的狀態(tài)棠笑。
由此也可以發(fā)現(xiàn),這里需要以回調(diào)的方式來(lái)向詢問(wèn)者返回值禽绪,這里我選擇了block蓖救,具體方式下文詳述。而且為了回調(diào)足夠及時(shí)印屁,所以使用了一個(gè)長(zhǎng)度僅為0.1s的音頻(該音頻素材也取自RBDMuteSwitch循捺,再次鳴謝!)雄人。

還有一點(diǎn)想強(qiáng)調(diào)一下从橘,就是這里的通過(guò)靜音按鈕置于靜音將音量調(diào)小至0,是兩種不同的狀態(tài),對(duì)于該種檢測(cè)方式洋满,只有通過(guò)靜音按鈕置于靜音的方式晶乔,才會(huì)被判斷為靜音狀態(tài),完全滿足我的要求牺勾。

  • 那么其他的靜音狀態(tài)或者音量狀態(tài)正罢,怎么辦呢?
    根據(jù)我目前能夠想象到的需求驻民,我的這個(gè)工具主要提供了三個(gè)api:
  1. 判斷當(dāng)前靜音按鈕是否為靜音狀態(tài)
/**
 用于回調(diào)當(dāng)前靜音按鈕是否為靜音狀態(tài)的block

 @param isMute 如果靜音按鈕當(dāng)前為靜音狀態(tài)翻具,則為YES,否則為NO
 */
typedef void(^MuteBlock)(BOOL isMute);

/**
 當(dāng)前靜音按鈕是否為靜音狀態(tài)
 */
@property (nonatomic, copy) MuteBlock muteBlock;
  1. 獲取當(dāng)前的真實(shí)音量(靜音按鈕處于靜音狀態(tài)時(shí)音量為0)
/**
 用于回調(diào)當(dāng)前真實(shí)音量的block
 
 @param currentRealVolume 當(dāng)前的真實(shí)音量
 */
typedef void(^RealVolumeBlock)(CGFloat currentRealVolume);

/**
 當(dāng)前的真實(shí)音量(靜音按鈕處于靜音狀態(tài)時(shí)音量為0)
 */
@property (nonatomic, copy) RealVolumeBlock realVolumeBlock;
  1. 監(jiān)聽(tīng)音量變化(不考慮靜音按鈕處于靜音狀態(tài)的情況回还,該情況下仍正常返回實(shí)際的音量值裆泳,而不是0)
/**
 用于監(jiān)聽(tīng)音量變化的block

 @param oldVolume 原始音量值
 @param newVolume 新的音量值
 */
typedef void(^VolumeChangeBlock)(CGFloat oldVolume, CGFloat newVolume);

/**
 監(jiān)聽(tīng)音量變化(不考慮靜音按鈕處于靜音狀態(tài)的情況,該情況下仍正常返回實(shí)際的音量值柠硕,而不是0)
 */
@property (nonatomic, copy) VolumeChangeBlock volumeChangeBlock;
  • 這里有一個(gè)小坑需要強(qiáng)調(diào)下:
    常規(guī)的獲取當(dāng)前音量和監(jiān)聽(tīng)音量變化的操作工禾,相信大家都能瞬間實(shí)現(xiàn),但是蝗柔,如果你在執(zhí)行這兩個(gè)方法之前闻葵,沒(méi)有過(guò)任何一次的音頻播放,那么獲取到的這兩個(gè)值都是不準(zhǔn)確的:
    獲取當(dāng)前音量一直為一個(gè)值癣丧,也就是說(shuō)即使你調(diào)整了音量槽畔,獲取的還是最初的值;
    對(duì)音量變化的監(jiān)聽(tīng)則徹底不會(huì)觸發(fā)-(void)observeValueForKeyPath:ofObject: change:context:方法胁编。
    因此厢钧,我在工具的初始化方法中,執(zhí)行了一次極小音頻的播放嬉橙,保證您在任何情況下獲取的音量值及對(duì)音量變化的監(jiān)聽(tīng)都是正確的早直。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市憎夷,隨后出現(xiàn)的幾起案子莽鸿,更是在濱河造成了極大的恐慌,老刑警劉巖拾给,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異兔沃,居然都是意外死亡蒋得,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門乒疏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)额衙,“玉大人,你說(shuō)我怎么就攤上這事∏喜啵” “怎么了县踢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)伟件。 經(jīng)常有香客問(wèn)我硼啤,道長(zhǎng),這世上最難降的妖魔是什么斧账? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任谴返,我火速辦了婚禮,結(jié)果婚禮上咧织,老公的妹妹穿的比我還像新娘嗓袱。我一直安慰自己,他們只是感情好习绢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布渠抹。 她就那樣靜靜地躺著,像睡著了一般闪萄。 火紅的嫁衣襯著肌膚如雪逼肯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天桃煎,我揣著相機(jī)與錄音篮幢,去河邊找鬼。 笑死为迈,一個(gè)胖子當(dāng)著我的面吹牛三椿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葫辐,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼搜锰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了耿战?” 一聲冷哼從身側(cè)響起蛋叼,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剂陡,沒(méi)想到半個(gè)月后狈涮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸭栖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年歌馍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晕鹊。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡松却,死狀恐怖暴浦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晓锻,我是刑警寧澤歌焦,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站砚哆,受9級(jí)特大地震影響独撇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窟社,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一券勺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灿里,春花似錦关炼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至色鸳,卻和暖如春社痛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背命雀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蒜哀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吏砂。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓撵儿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狐血。 傳聞我的和親對(duì)象是個(gè)殘疾皇子淀歇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容