iOS下AirPlay投屏功能實現(xiàn)

這篇文章注重于如何實現(xiàn)AirPlay投屏功能.具體AirPlay的實現(xiàn)邏輯這里不再贅述,網(wǎng)上帖子很多

首先.想要呼出AirPlay列表的話,需要將MPVolumnView控件聲明且添加到UI.上使用之前需要引入頭文件<MediaPlayer/MediaPlayer.h>.后續(xù)如果有AirPlay設(shè)備可用并且MPVolumnView存在于UI中的話.即可呼出列表
MPVolumnView:一個系統(tǒng)內(nèi)置的控件.繼承自UIView.內(nèi)部自定義了三個控件:MPVolumeSlider(音量進度條)UILabel(顯示文字)MPButton(點擊呼出AirPlay選擇器)
①如何解決MPVolumnView添加到UI中之后高亮效果會出現(xiàn)系統(tǒng)原生icon的問題
答:設(shè)置不同State的image為ni即可.
code:

MPVolumnView *volumnView = [[MPVolumnView alloc] init];
//此處btnSender的實際類型為MPButton
UIButton *btnSender = [volumnView objectWithBlock:^BOOL(UIView *obj) {
        return [obj isKindOfClass:[UIButton class]];
    }];
    [btnSender setImage:nil forState:UIControlStateNormal];
    [btnSender setImage:nil forState:UIControlStateHighlighted];
    [btnSender setImage:nil forState:UIControlStateSelected];

②如何解決在沒有可用設(shè)備情況下點擊MPVolumnView不會呼出AudioRoutePicker的問題
答:目前我找到的一個解決方案是完全無視MPVolumnView.將它在init時frame設(shè)置為0,0,0,0 然后在界面上自己添加一個UIButton.在它的點擊事件中給MPVolumnView的MPButton發(fā)送一個UIControlEventTouchUpInside來觸發(fā)MPVolumnView的_displayAudioRoutePicker事件
code:

//首先.自定義類.并且繼承MPVolumnView
@interface SparkMPVolumnView : MPVolumeView

@property(nonatomic,weak)UIButton *MPButton;
@end

@implementation SparkMPVolumnView

-(instancetype)init{
    if(self = [self initWithFrame:CGRectZero]){
        self.backgroundColor = [UIColor clearColor];
        self.showsVolumeSlider = NO;
        self.tag = kTVMPVolumeViewTag;
        [self initMPButton];
    }
    return self;
}
//這個的目的是在AirPlay沒有任何設(shè)備時也能呼出Picker使用
- (void)initMPButton{
    UIButton *btnSender = [self.subviews objectWithBlock:^BOOL(UIView *obj) {
        return [obj isKindOfClass:[UIButton class]];
    }];
    [btnSender setImage:nil forState:UIControlStateNormal];
    [btnSender setImage:nil forState:UIControlStateHighlighted];
    [btnSender setImage:nil forState:UIControlStateSelected];
    [btnSender setBounds:CGRectZero];
    self.MPButton = btnSender;
}
//在自定義按鈕的按下事件中發(fā)送給MPButton
//此處sparkVolumView為一個SparkMPVolumnView實例
-(void)airPlayButtonAction:(UIButton *)sender{
        [self.sparkVolumView.MPButton sendActionsForControlEvents:UIControlEventTouchUpInside];
}

③如何知道AirPlay的連接和斷開狀態(tài)?
答:其他資料大多是通過注冊MPVolumeViewWirelessRouteActiveDidChangeNotification來進行判斷的.但是這個通知有一個問題就是在存在多個MPVolumnView時會出現(xiàn)多次發(fā)送,并且如果在聲明MPVolumnView控件時是連接AirPlay設(shè)備的,它會先發(fā)送一個屬性wirelessRouteActive為NO的通知(即未連接任何設(shè)備),然后立馬發(fā)送一個wirelessRouteActive位YES的通知(連接到了設(shè)備).故我并未采用此方案.
我注冊了AVAudioSessionRouteChangeNotification通知.這個通知在音頻通道發(fā)生變化時會進行調(diào)用(例如插入/拔出耳機 揚聲器/聽筒切換 連接/斷開AirPlay設(shè)備).這個的通知是唯一且不重復(fù)的.在發(fā)生改變時[AVAudioSession sharedInstance]會發(fā)送此通知.在具體通知中通過獲取當(dāng)前的AirPlay通道名稱來判斷是否連接到了投屏設(shè)備
code:

-(void)registerNotification{
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteHasChangedNotification:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
}
- (void)audioRouteHasChangedNotification:(NSNotification *)notification{
    NSString *airplayDeviceName = [self activeAirplayOutputRouteName];
    BOOL isAirPlay = self.airplayDeviceName.length > 0;
}
//遍歷當(dāng)前設(shè)備所有通道.返回isEqualToString:AVAudioSessionPortAirPlay通道的具體名稱,如果名稱不為nil則為當(dāng)前連接到了AirPlay
- (NSString*)activeAirplayOutputRouteName
{
    AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    AVAudioSessionRouteDescription* currentRoute = audioSession.currentRoute;
    for (AVAudioSessionPortDescription* outputPort in currentRoute.outputs){
        if ([outputPort.portType isEqualToString:AVAudioSessionPortAirPlay])
            return outputPort.portName;
    }
    
    return nil;
}

④為什么播放過程中會電視端會出現(xiàn)暫停和退出播放的情況
答:AirPlay實現(xiàn)的原理是一個Socket通信.并且會在新的通道請求之后斷開之前的.所有在項目中你理論上是有多處會播放視頻的.只要調(diào)用一個新播放器的Play方法.設(shè)備端就會認(rèn)為你重新發(fā)起了一個Socket請求,斷開之前的播放并且發(fā)起新的視頻播放.故需要保證在AirPlay連接的情況下不調(diào)用任何視頻的暫停和播放代碼.
在我的項目中邏輯是比較復(fù)雜的,故實現(xiàn)方式是通過一個單例的Manager強引用一個AVPlayer,所有的AirPlay播放和暫停請求都通過它來實現(xiàn)..其他代碼只要保證在連接AirPlay的時候不進行操作就可以了.

⑤AirPlay在播放時播放新視頻為什么可能會投屏失敗?
答:這個我也無解.沒有查到相關(guān)的資料.現(xiàn)在的解決方案是在投放新視頻前檢測,如果只有有視頻,暫停播放并且將AVPlayer設(shè)置為nil.保證電視端退出投屏,隨后增加1.5f延時再進行播放.基本解決了投屏失敗的問題

其他問題歡迎大家在評論區(qū)討論,做AirPlay時趟了許多坑.希望這篇文章能幫助大家少走彎路.有不對的地方希望指出,第一時間修正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弛槐,一起剝皮案震驚了整個濱河市阵谚,隨后出現(xiàn)的幾起案子削彬,更是在濱河造成了極大的恐慌,老刑警劉巖使兔,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異藤韵,居然都是意外死亡虐沥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門泽艘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欲险,“玉大人,你說我怎么就攤上這事匹涮√焓裕” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵然低,是天一觀的道長喜每。 經(jīng)常有香客問我务唐,道長,這世上最難降的妖魔是什么带兜? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任枫笛,我火速辦了婚禮,結(jié)果婚禮上刚照,老公的妹妹穿的比我還像新娘刑巧。我一直安慰自己,他們只是感情好涩咖,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布海诲。 她就那樣靜靜地躺著,像睡著了一般檩互。 火紅的嫁衣襯著肌膚如雪特幔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天闸昨,我揣著相機與錄音蚯斯,去河邊找鬼。 笑死饵较,一個胖子當(dāng)著我的面吹牛拍嵌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播循诉,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼横辆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茄猫?” 一聲冷哼從身側(cè)響起狈蚤,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎划纽,沒想到半個月后脆侮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡勇劣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年靖避,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片比默。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡幻捏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出命咐,到底是詐尸還是另有隱情粘咖,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布侈百,位于F島的核電站瓮下,受9級特大地震影響翰铡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讽坏,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一锭魔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧路呜,春花似錦迷捧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抵屿,卻和暖如春庆锦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轧葛。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工搂抒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尿扯。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓求晶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衷笋。 傳聞我的和親對象是個殘疾皇子芳杏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,985評論 3 119
  • f43ad14dd74b閱讀 213評論 2 1
  • 《關(guān)鍵期關(guān)鍵幫助》第三章 P278-291 (4-5歲)孩子需要探索他人心智 這個時期的孩子在跟別人的互動中會發(fā)現(xiàn)...
    羅小太陽閱讀 534評論 0 0