Amazon Alexa show 踩坑指南

引言

本文由zlmediakit核心開發(fā)者 monktan(老衲不出家)編寫,夏楚審閱修訂;文章主要記錄了作者在對接亞馬遜Alexa設(shè)備時遇到的一些經(jīng)驗教訓(xùn)术辐,希望前人趟過的坑后人無需再趟。

一、背景

因業(yè)務(wù)發(fā)展陵究,需要在亞馬遜Alexa設(shè)備上實現(xiàn)與訪客視頻對講;調(diào)研發(fā)現(xiàn)亞馬遜Lambad Alexa Skill平臺(以下簡稱亞馬遜平臺)支持WebRTCRTSP兩種方式接入奥帘,由于需要實現(xiàn)雙向?qū)χv铜邮,只能采用WebRTC方式與Alexa設(shè)備對接;至于門鈴設(shè)備端寨蹋,硬件資源有限且不帶屏幕松蒜,我們采用的私有協(xié)議方式接入。為了便于讀者理解钥庇,我們省去了發(fā)現(xiàn)牍鞠、認(rèn)證等流程,整體架構(gòu)流程圖如下:

圖片.png

二评姨、開始趟坑

研究Alexa WebRTC接入相關(guān)文檔难述,發(fā)現(xiàn)其視頻支持H264編碼格式萤晴,音頻則支持Opus/PCMU/PCMA/AAC

圖片.png

由于WebRTC協(xié)議通常不支持AAC,為了節(jié)省時間胁后,我們直接采用更簡單的PCMU(而不是Opus)來測試店读,然而測試發(fā)現(xiàn)Alexa設(shè)備竟然無法播放,于是我們對比了之前對接過的web demo攀芯,發(fā)現(xiàn)竟然是通的屯断,其架構(gòu)方式也基本一致:

圖片.png

三、趟坑之路

由于Alexa設(shè)備死活無法播放門鈴的音視頻流而web demo卻一切正常侣诺,我做了大量的努力和嘗試殖演,包括sdp的分析對比,rtp的分析對比年鸳、變換音頻編碼格式(因為單視頻模式有播放成功的案例趴久,原因是單視頻模式請求鏈路時間不一樣,時間更短)搔确、音頻編碼切片長度彼棍、音視頻時間戳同步、分析設(shè)備日志等工作膳算。

3.1 趟坑之路一座硕,分析對比SDP

  • Alexa設(shè)備Offer
    v=0
    o=- 3889820441 3889820441 IN IP4 0.0.0.0
    s=a 2 z
    c=IN IP4 0.0.0.0
    t=0 0
    a=group:BUNDLE audio0 video0
    m=audio 1 UDP/TLS/RTP/SAVPF 96 0 8
    a=candidate:1 1 UDP 2013266431 **** 53179 typ host
    a=candidate:2 1 TCP 1015021823 **** 9 typ host tcptype active
    a=candidate:3 1 TCP 1010827519 **** 58004 typ host tcptype passive
    a=candidate:1 2 UDP 2013266430 **** 49423 typ host
    a=candidate:2 2 TCP 1015021822 **** 9 typ host tcptype active
    a=candidate:3 2 TCP 1010827518 **** 51167 typ host tcptype passive
    a=setup:actpass
    a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
    a=rtpmap:96 opus/48000/2
    a=rtcp:9 IN IP4 0.0.0.0
    a=rtcp-mux
    a=sendrecv
    a=mid:audio0
    a=ssrc:724561565 cname:user2420442903@host-e8501a47
    a=ice-ufrag:E9vw
    a=ice-pwd:CWbMx5SvmNls7LJ23gJJUk
    a=fingerprint:sha-256 2D:A0:F3:7D:0A:58:7E:B9:CC:79:C7:10:FB:BB:F9:F7:7D:EE:92:84:F5:08:D2:BC:25:76:C7:75:FF:8B:DB:75
    m=video 1 UDP/TLS/RTP/SAVPF 99
    a=candidate:1 1 UDP 2013266431 **** 53179 typ host
    a=candidate:3 1 TCP 1010827519 **** 58004 typ host tcptype passive
    a=candidate:2 1 TCP 1015021823 **** 9 typ host tcptype active
    a=candidate:1 2 UDP 2013266430 **** 49423 typ host
    a=candidate:2 2 TCP 1015021822 **** 9 typ host tcptype active
    a=candidate:3 2 TCP 1010827518 **** 51167 typ host tcptype passive
    b=AS:2500
    a=setup:actpass
    a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
    a=rtpmap:99 H264/90000
    a=rtcp:9 IN IP4 0.0.0.0
    a=rtcp-mux
    a=sendrecv
    a=mid:video0
    a=rtcp-fb:99 nack
    a=rtcp-fb:99 nack pli
    a=rtcp-fb:99 ccm fir
    a=ssrc:3568304867 cname:user2420442903@host-e8501a47
    a=ice-ufrag:E9vw
    a=ice-pwd:CWbMx5SvmNls7LJ23gJJUk
    a=fingerprint:sha-256 2D:A0:F3:7D:0A:58:7E:B9:CC:79:C7:10:FB:BB:F9:F7:7D:EE:92:84:F5:08:D2:BC:25:76:C7:75:FF:8B:DB:75
  • 平臺回復(fù)Answer
    v=0
    o=- 0 0 IN IP4 127.0.0.1
    s=webrtc_core
    t=0 0
    a=ice-lite
    a=group:BUNDLE audio0 video0
    a=rtcp-mux
    a=msid-semantic: WMS alexa_test
    m=audio 9 UDP/TLS/RTP/SAVPF 0
    a=rtcp:9 IN IP4 0.0.0.0
    c=IN IP4 0.0.0.0
    a=ice-ufrag:93b7543b756a8408
    a=ice-pwd:b97ec11486ce7a693d060e80
    a=fingerprint:sha-256 4D:1A:F7:3D:CD:5E:E3:24:E5:30:40:F5:E4:1A:9B:E4:14:C6:83:A8:B3:EE:33:0D:D7:62:84:CE:14:DA:C0:8C
    a=setup:passive
    a=sendrecv
    a=mid:audio0
    a=msid:alexa_test MainAudio
    a=rtcp-mux
    a=rtpmap:0 PCMU/8000
    a=ssrc:2159555873 cname:webrtccore
    a=ssrc:2159555873 msid:alexa_test MainAudio
    a=ssrc:2159555873 mslabel:alexa_test
    a=ssrc:2159555873 label:MainAudio
    a=candidate:foundation 1 udp 100 **** 8000 typ srflx raddr **** rport 8000 generation 0
    m=video 9 UDP/TLS/RTP/SAVPF 99
    a=rtcp:9 IN IP4 0.0.0.0
    c=IN IP4 0.0.0.0
    a=ice-ufrag:93b7543b756a8408
    a=ice-pwd:b97ec11486ce7a693d060e80
    a=fingerprint:sha-256 4D:1A:F7:3D:CD:5E:E3:24:E5:30:40:F5:E4:1A:9B:E4:14:C6:83:A8:B3:EE:33:0D:D7:62:84:CE:14:DA:C0:8C
    a=setup:passive
    a=sendrecv
    a=mid:video0
    a=msid:alexa_test MainVideo
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:99 H264/90000
    a=rtcp-fb:99 nack
    a=rtcp-fb:99 nack pli
    a=rtcp-fb:99 ccm fir
    a=fmtp:99 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=420015
    a=ssrc-group:FID 28521173 3056259
    a=ssrc:28521173 cname:webrtccore
    a=ssrc:28521173 msid:alexa_test MainVideo
    a=ssrc:28521173 mslabel:alexa_test
    a=ssrc:28521173 label:MainVideo
    a=ssrc:3056259 cname:webrtccore
    a=ssrc:3056259 msid:alexa_test MainVideo
    a=ssrc:3056259 mslabel:alexa_test
    a=ssrc:3056259 label:MainVideo
    a=candidate:foundation 1 udp 100 101.33.240.139 8000 typ srflx raddr 101.33.240.139 rport 8000 generation 0

這里咋一看好像沒啥問題;仔細(xì)發(fā)現(xiàn)涕蜂,Alexa PCMU和PCMA在SDP中沒有出現(xiàn)a=rtpmap华匾,可能導(dǎo)致協(xié)商不成功,于是我修改了SDP宇葱,添加了:a=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\n,然而發(fā)現(xiàn)并沒什么用瘦真,還是對接Alexa設(shè)備無輸出。

3.2 趟坑之路二黍瞧,抓包分析

web demo推流诸尽,Alexa設(shè)備可以正常播放,但是拉取門鈴設(shè)備流無法播放印颤,分別對起流進(jìn)行抓包分析對比:

圖片.png

對比發(fā)現(xiàn)兩個流同樣都是PCMU數(shù)據(jù)您机,但是數(shù)據(jù)長度不一樣,上面的能播放年局,下面的無法播放語音际看,導(dǎo)致我初步懷疑是因為上面啟用了RTP擴展導(dǎo)致可以播放,分析SRTP包發(fā)現(xiàn)矢否,web端推流確實多了RTP擴展仲闽,所以長度多了8個字節(jié)

圖片.png

此時的我雖然不太相信是由于RTP擴展引起Alexa設(shè)備無法播放語音僵朗,但是對于Alexa黑盒來說赖欣,只有盡力一試了屑彻,通過修改服務(wù)端代碼,終于做成與web推斷流數(shù)據(jù)包一模一樣了顶吮;然而社牲,結(jié)果并沒有什么不一樣,web端推流和設(shè)備推流到底問題在哪里悴了,分析了數(shù)據(jù)長度搏恤,數(shù)據(jù)發(fā)送頻率,音頻時間間隔湃交,時間戳增量熟空,甚至嘗試過NTP時間發(fā)送,都是沒有任何效果巡揍,依然是播放不出來的痛阻。

圖片.png

把數(shù)據(jù)分析數(shù)據(jù)發(fā)給其他WebRTC領(lǐng)域?qū)<覀兎治觯麄円部床怀鍪裁磫栴}腮敌,建議我使用opus編碼嘗試一下,畢竟它在Alexa官網(wǎng)是preferred codec俏扩,鑒于此決定先用opus嘗試糜工。

3.3 趟坑之路三,換Opus編碼

opus編碼在FFmpeg中直接采用AV_CODEC_ID_OPUS方式查找的解碼器录淡,找到的是內(nèi)置opus編碼器捌木,實測發(fā)現(xiàn)編碼延時很大,達(dá)到了普遍350ms~450ms的延遲(編碼機器linux cvm 8c16g主機)嫉戚,下面是FFmpeg內(nèi)部源碼:

AVCodec ff_opus_encoder = {
 .name           = "opus",
 .long_name      = NULL_IF_CONFIG_SMALL("Opus"),
 .type           = AVMEDIA_TYPE_AUDIO,
 .id             = AV_CODEC_ID_OPUS,
 .defaults       = opusenc_defaults,
 .priv_class     = &opusenc_class,
 .priv_data_size = sizeof(OpusEncContext),
 .init           = opus_encode_init,
 .encode2        = opus_encode_frame,
 .close          = opus_encode_end,
 .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
 .capabilities   = AV_CODEC_CAP_EXPERIMENTAL | AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
 .supported_samplerates = (const int []){ 48000, 0 },
 .channel_layouts = (const uint64_t []){ AV_CH_LAYOUT_MONO,
 AV_CH_LAYOUT_STEREO, 0 },
 .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
 AV_SAMPLE_FMT_NONE },
};

最后定位內(nèi)置的opusenc.c(注意, 不是libopusenc.c)設(shè)置的frame_size120幀, opus采樣率48000也就是2.5ms一幀刨裆,理論采樣延時大概300ms;從我測試的情況來看, 編碼延時很高(400+ms):

圖片.png

由于內(nèi)置opusenc.c編碼器延遲實在太大彬檀,顯然不適合WebRTC低延時場景帆啃,開始有點不知所以,后來在朋友的指導(dǎo)下窍帝,發(fā)現(xiàn)FFmpeg還有個libopus編碼器努潘,于是決定使用libopus來編碼,F(xiàn)Fmpeg中l(wèi)ibopus信息如下:

AVCodec ff_libopus_encoder = {
 .name            = "libopus",
 .long_name       = NULL_IF_CONFIG_SMALL("libopus Opus"),
 .type            = AVMEDIA_TYPE_AUDIO,
 .id              = AV_CODEC_ID_OPUS,
 .priv_data_size  = sizeof(LibopusEncContext),
 .init            = libopus_encode_init,
 .encode2         = libopus_encode,
 .close           = libopus_encode_close,
 .capabilities    = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME,
 .sample_fmts     = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
 AV_SAMPLE_FMT_FLT,
 AV_SAMPLE_FMT_NONE },
 .supported_samplerates = libopus_sample_rates,
 .priv_class      = &libopus_class,
 .defaults        = libopus_defaults,
 .wrapper_name    = "libopus",
};

替換libopus編碼后坤学,編碼延時在40~50ms內(nèi)疯坤,效果符合預(yù)期的;然而在做了音視頻同步后深浮,Alexa依然播放不出opus語音压怠,此時已經(jīng)快到了黔驢技窮的邊緣了。

3.4 趟坑之路四飞苇,分析Alexa日志

對于Alexa這個黑盒菌瘫,我們極度缺乏調(diào)試手段洋闽,只能通過給Amazon提交工單,很遺憾突梦,工單并未得到相應(yīng)回復(fù)诫舅,通過內(nèi)部關(guān)系找到Alexa中國區(qū)負(fù)責(zé)對接人,對方需要提供公司對接商務(wù)信息宫患,才能予以支持刊懈,且需要走商務(wù)流程;沒辦法娃闲,只能抓取Android端Alexa智能這個APP日志看能否找到相應(yīng)線索虚汛。

于是搭建Android adb環(huán)境,抓取com.amazon.dee.app:alexa包日志:

# 查看進(jìn)程號
adb shell ps
# 抓取日志皇帮, xxx為進(jìn)程號
adb logcat xxx 

不出意外卷哩,你將會得到一堆無用的日志信息:

圖片.png

3.5 趟坑之路五,柳暗花明

經(jīng)過長時間的嘗試属拾,始終無法攻克這個問題将谊,后續(xù)差點絕望到想放棄,實在沒辦法渐白,于是只能在逐字逐句的查看文檔尊浓,看看能不能得到點線索,看到這里:

圖片.png

終于頓悟纯衍!看描述本意是栋齿,Alexa設(shè)備發(fā)起offer請求后,需要在6s內(nèi)回復(fù)相應(yīng)的Answer SDP襟诸,然而最后實測發(fā)現(xiàn)這個6s是需要包含音視頻數(shù)據(jù)的瓦堵,如果6s內(nèi)沒有音視頻數(shù)據(jù)發(fā)送,Alexa建立連接失敗歌亲,但是 不會有任何提示菇用,不會有任何提示,不會有任何提示应结!刨疼。

  • 經(jīng)過一番調(diào)整,終于完美播放:


    圖片.png

    圖片.png

四鹅龄、總結(jié)

經(jīng)過這番折騰揩慕,最后復(fù)盤下事情的來龍去脈,開始死活不通的原因如下:

  • 亞馬遜的服務(wù)器部署在海外扮休,整個信令交互延時很高迎卤,大大降低了在6秒鐘內(nèi)完成交互的成功率,這也是一直失敗的最大原因玷坠。

  • 門鈴設(shè)備的喚醒蜗搔、控制延時較高劲藐,加大了整個鏈路的的延時。

  • 門鈴設(shè)備音頻采集樟凄、編碼聘芜、輸出時間比視頻晚幾百毫秒,導(dǎo)致單視頻成功率較高缝龄,但是復(fù)合流時成功率很低汰现,從而產(chǎn)生音頻數(shù)據(jù)是否有問題的誤導(dǎo),浪費很多時間花在排查音頻切片(確保20ms一個包)叔壤、編碼瞎饲、時間戳等問題上。

  • Alexa設(shè)備是個封閉的黑盒設(shè)備炼绘,無法獲取準(zhǔn)確的失敗原因嗅战;另外,其文檔描述也不準(zhǔn)確俺亮;這些坑必須一個一個趟出來驮捍,沒有前人指導(dǎo),很難注意到這些問題铅辞,而國內(nèi)在這方面的實踐較少厌漂,相關(guān)技術(shù)文章不多。

最后斟珊,感謝整個過程一直支持我的小伙伴們,感謝他們的悉心指導(dǎo)富纸,遇事不要氣餒囤踩,自己短期解決不了的問題,不要死磕牛角尖晓褪,盡量集思廣益堵漱,從不同角度去嘗試,最終你會發(fā)現(xiàn)涣仿,這可能根本就不是一個技術(shù)問題勤庐!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市好港,隨后出現(xiàn)的幾起案子愉镰,更是在濱河造成了極大的恐慌,老刑警劉巖钧汹,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丈探,死亡現(xiàn)場離奇詭異,居然都是意外死亡拔莱,警方通過查閱死者的電腦和手機碗降,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門隘竭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人讼渊,你說我怎么就攤上這事动看。” “怎么了爪幻?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵菱皆,是天一觀的道長。 經(jīng)常有香客問我笔咽,道長搔预,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任叶组,我火速辦了婚禮拯田,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甩十。我一直安慰自己船庇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布侣监。 她就那樣靜靜地躺著鸭轮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪橄霉。 梳的紋絲不亂的頭發(fā)上窃爷,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音姓蜂,去河邊找鬼按厘。 笑死,一個胖子當(dāng)著我的面吹牛钱慢,可吹牛的內(nèi)容都是我干的逮京。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼束莫,長吁一口氣:“原來是場噩夢啊……” “哼懒棉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起览绿,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤策严,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后挟裂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體享钞,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了栗竖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暑脆。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖狐肢,靈堂內(nèi)的尸體忽然破棺而出添吗,到底是詐尸還是另有隱情,我是刑警寧澤份名,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布碟联,位于F島的核電站,受9級特大地震影響僵腺,放射性物質(zhì)發(fā)生泄漏鲤孵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一辰如、第九天 我趴在偏房一處隱蔽的房頂上張望普监。 院中可真熱鬧,春花似錦琉兜、人聲如沸凯正。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽廊散。三九已至,卻和暖如春梧疲,著一層夾襖步出監(jiān)牢的瞬間允睹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工幌氮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留擂找,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓浩销,卻偏偏與公主長得像,于是被迫代替她去往敵國和親听哭。 傳聞我的和親對象是個殘疾皇子慢洋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

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