Long have WebRTC developers waited for the day Apple would come around to WebRTC. It has not been simple for web developers and Apple due to their policy that requires web browsing functionality to use the WebKit engine along with Safari. This meant no WebRTC in Safari; no Firefox or Chrome WebRTC on iOS, no native WebView with WebRTC or iOS API’s (but plenty of 3rd party ones). Despite community efforts and active development inside the WebKit project, it was not entirely clear when there would be at launch. That changed earlier this month when Apple announced a WebRTC-enabled WebKit based on the Google-backed webrtc.org engine was coming to both High Sierra – the next version of OSX – and iOS 11. Even better, WebRTC is available today as part of the free Safari Technology Preview.
As this is a key milestone for WebRTC, there have been many posts on it. We wanted to dig into more detail on what exactly was in Safari’s WebRTC and what isn’t. I started by running test.webrtc.org and WebRTC Experiment’s DetectRTC, which provide a good starting point. Safari is still in a Beta state with updates coming every 2 weeks, so much of this will change, but we try to provide a good baseline against the major API’s and features below.
Thanks to Philipp Hancke (Fippo) for his technical inputs and review and to Tsahi Levent-Levi for editing.
Summary
Here is the TL;DR version of what we found in Safari Technology Preview 33 (STP 33). Note these are just high-level notes based on an initial analysis. In addition, there were already some improvements over STP 32 (see the 33 release notes), so expect this to change often. Please see the next section for a lot more details.
Version | Safari Technology Preview
Release 33 (Safari 11.0, WebKit 12604.1.25.0.2) |
getUserMedia |
|
Camera use notification | Tab, URL bar, and system menu bar |
Permissions UI | Default ask; user can manually persist permissions |
Secure origins | Https only (even on localhost); no iFrames |
Supported video resolutions | 1280×720, 960×540, 640×480, 320×240 |
Screenshare | No |
Stream Manipulation |
|
MediaRecorder | No |
Media to peerConnection | No |
Device Selection |
|
Input enumeration | Yes |
Output enumeration | No |
mediaDevices events | Some – addEventListener but no ondevicechange |
RTCPeerConnection |
|
Audio Codecs | Opus, ISAC, G722, iLBC, and G.711 |
Video Codes | H.264 (No VP8 or VP9) |
Fingerprinting Policy | Fairly protective |
Constraints | Yes |
ICE | Trickle, Restarts, TURN-TCP, but maybe not TURN/TLS |
RTCDataChannel | Yes |
getStats | Some – inbound-rtp , outbound-rtp , track , local-candidate , remote-candidate |
SDP Munging | Yes |
Multi-stream SDP | Plan B (no Unified Plan support) |
Object Model | Some – RTPSender, RTPReceiver |
Developer Tools |
|
adapter.js | Mostly supported |
Debug tools | Some, but not official |
Details
getUserMedia
Camera use notification
Safari makes it very clear when you use the camera or microphone. Camera icon shows strong red in URL bar (even when tab isn’t active), on active tab, and in the menu. Clicking on the icon bar notification allows you to pause the stream.
Permissions UI
An alert dialog asks every time by default. To persist permission, you need to click on the red browser notification icon.
You can change previously set permissions and change the global default for camera and microphone (independently) if you go to the Safari menu, then Preferences->Websites->Camera/Microphone.
Note that the tab must be active to give permission – this is true even if you give a site fill permissions ahead of time.
Secure origins
getUserMedia only works on https; no exception for local host (i.e http://localhost). Safari also does not ever seem to allow getUserMedia from within an iFrame. I always get a “Trying to call getUserMedia from a document with a different security origin than its top-level frame” error. This makes using sites like codepen and jsfiddle impossible.
Supported video resolutions
I ran the Camera Resolution Finder (see our article on this here) and was only able to get the following resolutions:
- 1280×720
- 960×540
- 640×480
352×264- 320×240
This appears to be more like the original Chrome release and the current Firefox and Edge implementation where only a fix set of resolutions is supported. In the case of Safari Technical Preview Release 33, this is a small subset in comparison.
Screenshare
Firefox allows screenshare using
1 |
var constraints = {"video": {"mediaSource": "window"}}; //”window”, “screen”,” application”, “browser”, etc.. |
This did not work for me. Perhaps screenshare is implemented via a browser extension like Chrome. Safari does support browser extensions, but I did not try making one to check this feature.
Stream Capture
Nothing really worked for me here:
- MediaRecorder – the ability to record a stream using this API did not work for me.
- Sending streams from other elements – the official capture stream samples where you try to take a getUserMedia stream and send it somewhere else did not work for me.
- Canvas streams into a peerConnection – sending a canvas stream to a peerConnection did not work.
- WebAudio into a peerConnection also did not work, but sending a peerConnection to WebAudio was fine
These are typically second order implementation items, so nothing too surprising here.
Device selection
Input device enumeration
This seems to be ok. My USB video device did not enumerate the first time I tried, but it was ok after I reset so likely a bug. Amusingly, Safari still has a minor bug when you try to use JSON.stringify on the resulting MediaDeviceInfo object, i.e. this behaves differently across browsers:
1 |
navigator.mediaDevices.enumerateDevices().then(devices => console.log(JSON.stringify(devices)) |
Thankfully this is not too relevant in practice.
Also of note, if you reject permissions Safari will only show a single audio and video device as “Microphone 1” and “Camera 1”.
Device labels
Defaults to Camera/Microphone until you give permission. The label – i.e. “FaceTime HD Camera” shows every time after you give permission once.
Audio output device enumeration
Audio output device selection and setting is not available. Like in Firefox, support can be checked by using sinkId in HTMLMediaElement.prototype
Events
navigator.mediaDevices.addEventListener does not work. navigator.mediaDevices.ondevicechange does.
RTCPeerConnection
Audio Codecs
On the audio side Safari looks a lot like like Chrome, supporting Opus, ISAC, G722, iLBC, and G.711 (a and Mu law), along with comfort noise and DTMF options. Interestingly, Chrome does not offer iLBC.
1 2 3 4 5 6 |
//***Safari TP33***// m=audio 9 UDP/<code>LS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126 //Note the addition of *102* for iLBC ^^^ //***Chrome 60***/// m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126 |
Video Codecs
On the more controversial side, Safari does not support VP8 or VP9, just H.264. The IETF specs say WebRTC Browsers must support VP8 and H.264, so this puts Safari out of spec here (not to mention causes some applications problems – follow this bug report for more info).
In addition, RTX, RED, and UPLFEC are included like Chrome for bandwidth adaptation.
Fingerprinting Policy
Safari only showed a single pair of audio & video devices for me vs. a long list in Chrome & Firefox. See the comments in RTCDataChannel section for more on Safari’s efforts to prevent sharing of IP addresses.
Constraints
These seems to work ok in my quick tests.
ICE
The ICE implementation appears to work the same as Chrome with Trickle. TURN/TLS seems unsupported. In addition the candidate gathering demo does not work as createOffer({offerToReceiveAudio}) has a bug and creates and offer without any m-lines.
ICE Restarts worked fine too.
RTCDataChannel
The data channel appears to work. Testing it on the WebRTC samples showed that Safari behaves different from Chrome when only the data channel is used. Safari fails to establish a connection here unless getUserMedia is called. This suggests that Safari is implementing the very strict “mode 3” candidate gathering policy described in the IP address handling draft. Since the samples don’t use a STUN or TURN server, Safari can not determine the default route and the connection fails.
getStats
Basic RTP stats are provided. Specifically the inbound-rtp, outbound-rtp , and track objects. Safari 33 added local-candidate and remote-candidate .
This is a small subset of the getStats specification.
Munging SDP
The Munge SDP sample gave a “readonly” error when we first tried it. This was a bug in the sample which has been fixed. While Safari still allows SDP munging, the attributes of the RTCSessionDescription object from createOffer are read-only.
Multi-stream SDP
For those of you that have been following WebRTC standards and likely doing a multi-party video implementation yourself, Safari uses the older Plan B SDP scheme implemented by Chrome instead of the newer Unified Plan.
Object Model
The WebRTC specs have evolved a few times and landed on the transceiver model with the move to newly manageable objects (see a good Mozilla post on this here). Safari is the first browser to natively implement the transceiver model, including RtpSender and RtpReceiver but not the DtlsTransport object inspired by ORTC.
In the transceiver model, the following snippet creates an RTCRtpReceiver :
1 2 3 4 5 |
navigator.mediaDevices.getUserMedia({video: true}) .then(stream => { pc.addTrack(stream.getVideoTracks()[0], stream); console.log(pc.getReceivers()); }); |
This returns an array with a receiver object in Safari. For comparison, Firefox allows this but returns an empty array.
Developer Tools
adapter.js supports legacy API’s
Apple Webkit developer and WebRTC lead, Youenn Fablet has been making sure the legacy streams API is shimmed in adapter.js. That way, things will work even if the native support for the legacy streams APIs such as addStream is turned off in Safari Technology Preview. Note this is expected to be the default mode at some point.
Debug Tools
This is not widespread knowledge, but Safari does had a debug menu. To get it to show you have been able to enable a debug menu in Safari for years by entering defaults write com.apple.Safari IncludeInternalDebugMenu 1 from the console. Swap SafariTechnologyPreview for Safari above and you’ll see a new Debug menu with some interesting Media Flag options:
I have not tried these yet, but they look useful for debugging. In particular the mock devices will be very useful for test automation. Frequent webrtcHacks guest author Alex Gouiallard talks a bit more about this on his blog here.
Other than this, we have yet to find anything equivalent to about:webrtc on Firefox or chrome://webrtc-internals on Chrome.
Test Automation
As I was finalizing this, Adam Ullman just made a pull request to Safari support inside Travis Check out Travis Multirunner out here on GitHub.
What Else
Beyond API implementation details, there are still many major questions to be answered. Some of the high-level ones I am most interested in, include:
- Will there be any official debugging tools for WebRTC or guides on the current unofficial ones?
- Can we expect feature parity between Safari on OSX and iOS?
- How does the UIWebView implementation compare with Safari’s?
Let’s hope that Apple and the larger WebRTC community gets to the bottom of these questions and more.
{“author”: “chad hart“}
Paul Gregoire says
Thanks for taking the time to do the discovery guys; Keep up the great work!
Octavian says
Regarding device selection…
There is no builtin device selection panel as there is in Chrome/Firefox which is why I believe ondevicechange is also missing. We’ll either have to build or own in HTML/JS or just rely on whatever is the *default*.
macOS does have a default microphone input selection in System Pref > Sound > input but there’s no such thing for webcams 🙂
Chad Hart says
Note Apple posted a note with some more details on the above items (like developer options, permission model, etc.) here in early July: https://webkit.org/blog/7763/a-closer-look-into-webrtc/
jonobr1 says
Do you have a live demo of this: “WebAudio into a peerConnection also did not work, but sending a peerConnection to WebAudio was fine” somewhere?
I’m playing around with the web audio api and webrtc and am running into an issue where I’m able to hear and analyze audio from a peer.., but not able to send audio out to a peer. To clarify audio sends, but not audio data is heard from the remote peer when trying to play Safari’s peer connection audio stream.
Chad Hart says
I used the “official” webrtc.org samples repo here for all my tests: https://webrtc.github.io/samples/
See these links and the linked source code:
https://webrtc.github.io/samples/src/content/peerconnection/webaudio-input/
https://webrtc.github.io/samples/src/content/peerconnection/webaudio-output/
Jianping Jianping says
Great Post! Did someone succeed to do screen sharing under Safari?