多屏互動(dòng),AirPlay,無線投屏 AirplaySDK—Airplay鏡像傳輸破解示例
AirPlay版本繁多,協(xié)議也比較多:鏡像,非鏡像,圖片,視頻,音頻,第三方app等等各種協(xié)議之間都有差別,以后會(huì)慢慢給大家介紹的。
要實(shí)現(xiàn)AirPlay的第一步就是要實(shí)現(xiàn)ios與AirPlay之間的相互發(fā)現(xiàn),可以使用zeroconf,mdns等開源協(xié)議來實(shí)現(xiàn),下一章會(huì)詳細(xì)介紹介紹這幾種發(fā)現(xiàn)協(xié)議。
要實(shí)現(xiàn)airPlay的鏡像Server端功能,要從以下幾個(gè)方面來考慮
- 1.發(fā)現(xiàn)過程
- 2.協(xié)商過程
- 3.視頻傳輸
- 4.解密過程
發(fā)現(xiàn)過程
使用Bonjour,可以參考mDNSResponder,jmdns,注冊(cè)兩個(gè)服務(wù):airtunes和airplay,AirplayTxt以及RaopTxt照著demo填寫就可以了,也可以根據(jù)自己的要求修改其中的值,
需要注意的如下:
airtunes:?? “12345@wirelessdisplay” , ”_raop._tcp.”airplay:??? “wirelessdisplay” , ”_airplay._tcp.”
參數(shù)中”_airplay._tcp.”和’’_raop._tcp.”不可修改。
發(fā)布了服務(wù)之后,ios設(shè)備中應(yīng)該就可以搜索到Server端了
協(xié)商過程
c-s: pair-setup
s-c: xxx
c-s: pair-verify
s-c: xxx
c-s: fp-setup
s-c: xxx
c-s: fp-setup
s-c: xxx
setup
setup response
setup
setup respnose
pair-setup,pair-verify配對(duì)驗(yàn)證,Server端根據(jù)收到的信息進(jìn)行回復(fù),格式類似RTSP
fp-setup(第一次和第二次),Fairplay相關(guān)。
第一次setup階段會(huì)收到一大串?dāng)?shù)據(jù),是按照plist格式生成的,用相應(yīng)的方法進(jìn)行解析可以得到ekey和eiv等信息,用于后續(xù)的解密。
第二次setup階段獲得type,通過type來判斷視頻數(shù)據(jù)或音頻數(shù)據(jù),通知接收端建立傳輸通道準(zhǔn)備進(jìn)行音視頻數(shù)據(jù)的發(fā)送,加密過的屏幕鏡像數(shù)據(jù)通過指定的端口(一般為7100)發(fā)送到接收端。
接收端收到發(fā)送過來的數(shù)據(jù)后進(jìn)行解密,解密后的數(shù)據(jù)就可以進(jìn)行播放了。
中間也可能會(huì)有GET_PARAMETER,SET_PARAMETER來調(diào)整音量等信息。
解密部分目前主要有兩種方法:
1.從apptv或macOS獲取。
2.從市面上已有的可投屏產(chǎn)品中獲取。
AIRPLAY鏡像投屏過程中,音視頻數(shù)據(jù)都是加密過的,對(duì)于接收端來說,需要正確解密后才能對(duì)音視頻數(shù)據(jù)進(jìn)行處理,音頻和視頻的解密過程還不一樣。音頻相對(duì)簡單一點(diǎn),視頻會(huì)復(fù)雜一些。這一塊的解密過程是沒有公開的,是蘋果自身的Fairplay DRM協(xié)議部分?,F(xiàn)在市面上的第三方Airplay接收端無非都是通過逆向過程破解了相關(guān)部分。
本文針對(duì)音頻的處理做一個(gè)介紹,音頻部分的處理相對(duì)簡單一點(diǎn)。
解密過程:
1 音頻采用AES CBC128進(jìn)行加密,這一部分可以使用開源的openssl庫進(jìn)行處理
2 該算法需要解密的輸入?yún)?shù)包括aeskey,aeskiv,通過ANNOUNCE請(qǐng)求中攜帶,ANNOUNCE請(qǐng)求同時(shí)還會(huì)攜帶音頻的編碼信息。
通過解密過程后,我們會(huì)得到AAC編碼的音頻數(shù)據(jù),播放器播放AAC數(shù)據(jù)還需要對(duì)其進(jìn)行解碼。
在我們實(shí)現(xiàn)的接收端程序,協(xié)商出來的是AAC-ELD編碼。對(duì)于AAC的解碼,可以使用一些開源的庫,如fdk,ffmpeg等,也可以使用android提供的MediaCodec進(jìn)行解碼。
但筆者曾經(jīng)在某些Android手機(jī)上發(fā)現(xiàn),解碼AAC-ELD有問題。推薦大家用fdk進(jìn)行解碼。
使用fdk對(duì)aac進(jìn)行解碼,其實(shí)在網(wǎng)上也能找到很多例子,但筆者發(fā)現(xiàn)很多例子有一處錯(cuò)誤,在低版本的fdk上不會(huì)出現(xiàn)錯(cuò)誤,但是在高版本的fdk會(huì)出現(xiàn)crash這樣的問題。話不多說,直接通過部分代碼來說明過程。
初始化解碼器:
- UCHAReld_conf[]?=?{?0xF8,?0xE8,?0x50,?0x00?};??????????//44100,2channels,s16
- UCHAR*aac_eld_conf[]?=?{?eld_conf?};???????????????????//TODO?just?for?aac?eld?config
- staticUINT?aac_eld_conf_len?=?sizeof(eld_conf);
- decoder?=?aacDecoder_Open(TT_MP4_RAW,?1);
- AAC_DECODER_ERROR?ret?=?aacDecoder_ConfigRaw(decoder,?aac_eld_conf,?&aac_eld_conf_len);
- buffer?=?newINT_PCM[960];
- buffer_size?=?1920;
- pcm_size?=?960;
上述代碼中eld_conf這一塊的值對(duì)應(yīng)android MediaCodec aac,CSD buffer #0具體什么含義看規(guī)范吧。
每次編碼和發(fā)送的采用數(shù)為480,故下面申請(qǐng)對(duì)應(yīng)長度的Buffer
解碼過程:
- bytesValid?=?dataLen;
- while(bytesValid){??
- ret?=?aacDecoder_Fill(decoder,?reinterpret_cast<UCHAR**>(&p_frame),?(UINT*)&size,?&bytesValid);
- if?(ret?!=?AAC_DEC_OK)?{
- printf(“aacDecoder_Fill?return?%x.\r\n”,?ret);
- return;
- }
- for(;;)?{
- ret?=?aacDecoder_DecodeFrame(decoder,?buffer,?pcm_size,?0);
- if(ret?==?AAC_DEC_OK)?{
- dump_audio_data((unsigned?char*)buffer,buffer_size);
- }?elseif?(ret?==?AAC_DEC_NOT_ENOUGH_BITS)
- break;
- else{
- printf(“aacDecoder_DecodeFrame?return?%x.\r\n”,?ret);
- return;
- }
- }
- }
aacDecoder_DecodeFrame填入的參數(shù)為pcm_size,其單位為short,而不是byte。網(wǎng)上的例子很多都是在這里錯(cuò)誤。請(qǐng)各位務(wù)必注意。
必捷網(wǎng)絡(luò)現(xiàn)提供技術(shù)全國領(lǐng)先的Airpaly SDK蘋果無線投屏軟件開發(fā)工具包,支持同時(shí)多路,支持鏡像/視頻/圖片/音樂,支持MAC OS/iOS6/iOS7/iOS8/iOS9/iOS10/iOS11投屏,支持Linux/Android/Windows/X86/ARM/MIPS等,可根據(jù)需求定制開發(fā),通過電話或者在線咨詢聯(lián)系我們獲取更多無線投屏sdk(airplay sdk、miracast sdk)相關(guān)信息,歡迎咨詢!
?