【Webkit Blog翻譯】深刻研究WebRTC

咱們在最近的一篇WebKit博客中宣佈了對High Sierra平臺和iOS中Safari的WebRTC支持。如今,咱們但願可以帶領你們深刻實現其中的一些細節,而且爲您網站中的WebRTC應用帶來一些建議。html

一個應用了WebRTC和媒體攝像頭的網站能夠獲取並傳播一些很是私人的信息。用戶必須顯式地對網站進行受權,並假設他們的圖片和聲音會被合理使用。WebKit爲了利用技術保護用戶的隱私權,要求網站知足一些特定的條件。除此以外,當用戶的攝像頭設備被使用時,Safari會提醒用戶,而且用戶能夠控制網站對攝像頭設備的訪問權限。對於在App中使用了WebKit的開發者發來講,RTCPeerConnectionRTCDataChannel能夠在任意網頁視圖中使用,但對攝像頭和麥克風的訪問目前受限於Safari。ios

開發菜單

Safari技術預覽版34向開發者展現了一些選項,能夠更容易的測試他們的WebRTC網站或將Safari集成到持續集成系統中,入口在開發>WebRTC子菜單中。git

f1

咱們將介紹每一個選項,並將在下方解釋它們是如何幫助你進行開發的。github

此外,WebKit將WebRTC的狀態做爲日誌記錄在了系統日誌中,包括SDP邀請和應答,ICE候選項,WebRCT狀態統計,傳入及傳出視頻幀計數器等。web

媒體攝像頭的安全源策略

但願訪問捕獲設備的網站須要知足兩個約束。macos

首先,請求須要使用攝像頭和麥克風的文檔須要來自HTTPS域。因爲在本地開發和測試時可能會很麻煩,所以能夠經過在開發>WebRTC*菜單中選中"在不安全的站點上容許使用媒體攝像頭"來旁路HTTPS限制。canvas

其次,當子幀請求使用攝像頭設備時,通向主幀的幀鏈須要來自相同的安全源。用戶可能沒法識別與主幀相關的子幀的第三方來源,所以該約束避免了混淆用戶授予其訪問權限的用戶。promise

模擬網頁攝像頭

開發>WebRTC菜單中,能夠選擇"使用模擬攝像頭設備"來替代真實的攝像頭設備。以下所示,模擬循環一個bip-bop AV流。當用做傳入流時,模擬的可預測數據能夠輕鬆評估流媒體播放的各個方面,包括同步,延遲和輸入設備的選擇。瀏覽器

f2

模擬對於在持續集成系統中運行自動化測試也頗有用。若是您正在使用而且想要避免來自getUserMedia的提示,能夠經過Safari首選項...>網站面板將網站的攝像頭和麥克風策略設置爲容許。安全

ICE候選項限制

ICE候選項在WebRTC鏈接的早期階段進行信息交換,以識別兩個對等鏈接之間的全部可能的網絡路徑。爲此,WebKit必須將每一個對等鏈接的ICE候選項暴露給網站並共享它們。ICE候選項公開IP地址,特別是那些能夠用於跟蹤的主機IP地址。

可是,在許多網絡拓撲中,主機ICE候選項沒必要進行鏈接。不管是否用於交換視頻或任意數據,Server Reflexive和TURN ICE候選項一般都足以確保鏈接。若是不訪問攝像頭設備,WebKit只會公開Server Reflexive和TURN ICE候選項,這些候選者會公開可能已經被網站收集的IP。授予訪問權限後,WebKit將公開主機ICE候選項,從而最大限度地提升鏈接成功的可能性。咱們作出此例外的緣由是:咱們認爲用戶經過授予對其攝像流的訪問權限來表達對網站的高度信任。

一些測試頁面可能會對主機ICE候選項的可用性做出假設。要對此進行測試,請從開發>WebRTC菜單中啓用"禁用ICE候選限制",而後從新加載頁面。

舊版WebRTC及媒體流API

隨着WebRTC標準化過程的推動(免費下載W3C推薦標準WebRTC 1.0: Real-time Communication Between Browsers中文版),RTCPeerConnection API以各類方式逐步改進。API從最初基於回調,到變爲徹底基於promise,從最初專一於將MediaStream,移動到專一於MediaStreamTrack。感謝WebRTC in WebKit團隊的努力,RTCPeerConnection API的改進與這兩個主要變化保持一致。

咱們已經在Safari技術預覽版34上默認關閉了舊版WebRTC API,並計劃在沒有這些API的狀況下在macOS High Sierra和iOS 11上發佈Safari 11。保留遺留API限制了咱們在WebRTC上更快推動的能力。任何但願爲Safari提供支持的網站均可能須要進行其餘調整,所以這是擺脫這些遺留API的好時機。現有網站仍然能夠依賴這些遺留API,您能夠經過在開發>WebRTC菜單中啓用"啓用舊版WebRTC API"來達到目的。

更準確地說,如下API僅在打開舊版API開關時可用,並提供了有關如何更新的建議:

partial interface Navigator {
    // Switch to navigator.mediaDevices.getUserMedia
    void getUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback);
};

partial interface RTCPeerConnection {
    // Switch to getSenders, and look at RTCRtpSender.track
    sequence<MediaStream> getLocalStreams();
    // Switch to getReceivers, and look at RTCRtpReceiver.track
    sequence<MediaStream> getRemoteStreams();

    // Switch to getSenders/getReceivers
    MediaStream getStreamById(DOMString streamId);
    // Switch to addTrack
    void addStream(MediaStream stream);
    // Switch to removeTrack
    void removeStream(MediaStream stream);

    // Listen to ontrack event
    attribute EventHandler onaddstream;

    // Update to promise-only version of createOffer
    Promise<void> createOffer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional RTCOfferOptions options);
    // Update to promise-only version of setLocalDescription
    Promise<void> setLocalDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of createAnswer
    Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of setRemoteDescription
    Promise<void> setRemoteDescription(RTCSessionDescriptionInit description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
    // Update to promise-only version of addIceCandidate
    Promise<void> addIceCandidate((RTCIceCandidateInit or RTCIceCandidate) candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
};
複製代碼

許多站點經過開源的adapter.js項目支持polyfill API。更新到最新版本是彌補API差別的一種方法,但咱們建議切換到規範中列出的API。

如下是如何使用最新API的幾個示例。典型的僅接收/在線研討的WebRTC調用能夠像這樣完成:

var pc = new RTCPeerConnection();
pc.addTransceiver('audio');
pc.addTransceiver('video');
var offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// send offer to the other party
...
複製代碼

典型的音頻-視頻WebRTC調用也能夠像如下方式完成:

var stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
var pc = new RTCPeerConnection();
var audioSender = pc.addTrack(stream.getAudioTracks()[0], stream);
var videoSender = pc.addTrack(stream.getVideoTracks()[0], stream);
var offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// send offer to the other party
...
複製代碼

基於MediaStreamTrack的API頗有意義,由於大多數處理都是在這一層完成的。假設捕獲視頻軌的640×480默認分辨率不夠好,繼續前面的示例,動態更改它能夠按以下方式完成:

videoSender.track.applyConstraints({width: 1280, height: 720});
複製代碼

或者咱們可能想要視頻靜音但保持音頻流動:

videoSender.track.enabled = false;
複製代碼

等等,咱們實際上想要對當前的視頻軌應用一些很酷的濾鏡效果,就像在這個例子中同樣,所須要的只是一些不須要任何SDP從新協商的函數調用:

videoSender.track.enabled = true;
renderWithEffects(video, canvas);
videoSender.replaceTrack(canvas.captureStream().getVideoTracks()[0]);
複製代碼

訪問攝像流

Safari容許用戶徹底控制網站對其攝像設備的訪問權限。

首先,用戶首次調用getUserMedia時,系統會提示用戶授予網站訪問攝像設備的權限。但與其餘瀏覽器不一樣的是,Safari不要求用戶選擇特定設備; 相反,它提示請求訪問某一特定類型的設備,如全部相機或麥克風。這減小了屢次提示帶來的困擾,而且可避免用戶始終點擊"容許"。可能發生這種狀況的一種常見情形是在iOS設備的攝像頭在先後之間切換。getUserMedia中已解析的promise將返回知足約束條件的設備,而且後續對getUserMedia的調用將避免向用戶顯示提示。若是要容許用戶切換到其餘設備,請務必提供UI以執行此操做。

其次,用戶能夠決定經過Safari首選項始終容許或拒絕訪問攝像頭和麥克風。用戶能夠基於每一個來源執行此操做,甚至能夠爲全部網站設置通用策略。

第三,一旦網站爲設備建立MediaStream,Safari UI和系統菜單欄中就會顯示圖標,代表正在使用攝像設備。用戶能夠點擊或點擊該圖標以暫停使用中的攝像機和麥克風。在這裏,WebKit將發送靜音音頻和黑色視頻幀,您的網站能夠經過監聽MediaStreamTrack上的靜音取消靜音事件來展現合適的UI。

f4

最後,爲了不未經容許的攝像,WebKit只容許一個選項捕獲一次視頻或音頻。已使用的捕獲設備將看到他們的MediaStreamTracks靜音並在新選項卡得到訪問權限時接收靜音事件。

指紋

navigator.mediaDevices.enumerateDevices公開了可用的攝像設備列表,即便未授予對這些設備的訪問權限,也能夠經過網站查詢。對於具備自定義相機和麥克風設置的用戶,能夠添加到用戶的指紋表面。當訪問還沒有被請求或訪問沒有被明確拒絕時,WebKit經過返回與實際可用設備集不必定對應的默認設備列表,來避免暴露這些附加信息。此外,根據規範,設備缺乏標籤。一旦訪問權限被授予,便可得到完整的設備列表及其標籤。

媒體攝像頭和自動播放視頻

在以前的帖子中,咱們討論了macOS和iOS上視頻自動播放策略的變化。咱們調整了兩個平臺上的策略以適應WebRTC應用程序,在這些應用程序中,一般須要自動播放包含音頻的傳入媒體流。爲了解決這些問題,同時保留當前自動播放規則的好處,咱們進行了如下更改:

  • 若是網頁已在捕獲,則MediaStream支持的媒體將自動播放。
  • 若是網頁已播放音頻,則MediaStream支持的媒體將自動播放。但仍然須要用戶手勢來激活音頻回放。

性能

WebRTC是一個很是強大的特性,能夠衍生許多應用程序。咱們都知道,強大的力量帶來了巨大的責任。設計WebRTC應用程序須要從一開始就考慮到效率。 CPU,內存和網絡均可能嚴重影響用戶體驗。Web引擎和Web應用程序都應該解決此問題。在Web應用程序方面,已經有各類機制可供選擇:選擇正確的視頻分辨率和幀速率,選擇正確的視頻編解碼器配置文件,使用CVO,在源處將媒體軌靜音,以及在客戶端執行WebRTC統計數據的監視。

反饋

這就是咱們深刻研究WebRTC和媒體攝像的結果。咱們隨時歡迎您的反饋。提交錯誤,發送電子郵件至web-evangelist@apple.com,或發推並@webkit。

順便說一句,鼓勵你們閱讀STUNTURN的RFC規範,以及WebRTC自己的規範。這些文件可能有點難以理解,可是您能夠從理解甚至一小部份內容中學到不少東西,這將有助於您的生活更簡單。免費下載W3C推薦標準WebRTC 1.0: Real-time Communication Between Browsers中文版

相關文章
相關標籤/搜索