はじめに
本記事は、Qiitaに投稿した記事を移行したものです。
先日、WebRTCを使ったアプリケーションを開発しているときに、Videoタグにautoplay属性を書き忘れたら変な挙動をしたので、何が起こっているのか調べました。
環境
- Google Chrome 56.0.2924.76
- FireFox 50.1.0
概要
以下のようなコードを書き、コンソールに表示される内容を見てみました。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>WebRTCVideoAutoPlay</title> </head> <body> <div> <video id="myVideo-autoplay" style="width: 320px;height: 240px;" autoplay></video> <video id="myVideo-noautoplay" style="width: 320px;height: 240px;"></video> </div> <script type="text/javascript"> var autoplay=document.getElementById('myVideo-autoplay'); var noautoplay=document.getElementById('myVideo-noautoplay'); navigator.mediaDevices.getUserMedia({video: true, audio: false}) .then(function (stream){ autoplay.src=window.URL.createObjectURL(stream); noautoplay.src=window.URL.createObjectURL(stream); autoplay.addEventListener('loadstart',function(){console.log('autoplay:loadstart');}); autoplay.addEventListener('progress',function(){console.log('autoplay:progress');}); autoplay.addEventListener('suspend',function(){console.log('autoplay:suspend');}); autoplay.addEventListener('load',function(){console.log('autoplay:load');}); autoplay.addEventListener('abort',function(){console.log('autoplay:abort');}); autoplay.addEventListener('error',function(){console.log('autoplay:error');}); autoplay.addEventListener('emptied',function(){console.log('autoplay:emptied');}); autoplay.addEventListener('stalled',function(){console.log('autoplay:stalled');}); autoplay.addEventListener('play',function(){console.log('autoplay:play');}); autoplay.addEventListener('pause',function(){console.log('autoplay:pause');}); autoplay.addEventListener('loadedmetadata',function(){console.log('autoplay:loadedmetadata');}); autoplay.addEventListener('loadeddata',function(){console.log('autoplay:loadeddata');}); autoplay.addEventListener('waiting',function(){console.log('autoplay:waiting');}); autoplay.addEventListener('playing',function(){console.log('autoplay:playing');}); autoplay.addEventListener('canplay',function(){console.log('autoplay:canplay');}); autoplay.addEventListener('canplaythrough',function(){console.log('autoplay:canplaythrough');}); autoplay.addEventListener('seeking',function(){console.log('autoplay:seeking');}); autoplay.addEventListener('seeked',function(){console.log('autoplay:seeked');}); autoplay.addEventListener('timeupdate',function(){console.log('autoplay:timeupdate');}); autoplay.addEventListener('ended',function(){console.log('autoplay:ended');}); autoplay.addEventListener('ratechange',function(){console.log('autoplay:ratechange');}); autoplay.addEventListener('durationchange',function(){console.log('autoplay:durationchange');}); autoplay.addEventListener('volumechange',function(){console.log('autoplay:volumechange');}); noautoplay.addEventListener('loadstart',function(){console.log('noautoplay:loadstart');}); noautoplay.addEventListener('progress',function(){console.log('noautoplay:progress');}); noautoplay.addEventListener('suspend',function(){console.log('noautoplay:suspend');}); noautoplay.addEventListener('load',function(){console.log('noautoplay:load');}); noautoplay.addEventListener('abort',function(){console.log('noautoplay:abort');}); noautoplay.addEventListener('error',function(){console.log('noautoplay:error');}); noautoplay.addEventListener('emptied',function(){console.log('noautoplay:emptied');}); noautoplay.addEventListener('stalled',function(){console.log('noautoplay:stalled');}); noautoplay.addEventListener('play',function(){console.log('noautoplay:play');}); noautoplay.addEventListener('pause',function(){console.log('noautoplay:pause');}); noautoplay.addEventListener('loadedmetadata',function(){console.log('noautoplay:loadedmetadata');}); noautoplay.addEventListener('loadeddata',function(){console.log('noautoplay:loadeddata');}); noautoplay.addEventListener('waiting',function(){console.log('noautoplay:waiting');}); noautoplay.addEventListener('playing',function(){console.log('noautoplay:playing');}); noautoplay.addEventListener('canplay',function(){console.log('noautoplay:canplay');}); noautoplay.addEventListener('canplaythrough',function(){console.log('noautoplay:canplaythrough');}); noautoplay.addEventListener('seeking',function(){console.log('noautoplay:seeking');}); noautoplay.addEventListener('seeked',function(){console.log('noautoplay:seeked');}); noautoplay.addEventListener('timeupdate',function(){console.log('noautoplay:timeupdate');}); noautoplay.addEventListener('ended',function(){console.log('noautoplay:ended');}); noautoplay.addEventListener('ratechange',function(){console.log('noautoplay:ratechange');}); noautoplay.addEventListener('durationchange',function(){console.log('noautoplay:durationchange');}); noautoplay.addEventListener('volumechange',function(){console.log('noautoplay:volumechange');}); }).catch(function (error){ console.error('could not get user media:', error); return; }); </script> </body> </html>
結果
Google Chrome
autoplayの有無に関わらず、映像が表示されました。
しかし、autoplay無しの方は、カクカクとした動きになったり、時々止まったりしました。
コンソールのログを見てみると、autoplay有の方ではprogress
とtimeupdate
が交互に発生していました。
間隔は、約400msくらいでした。
一方、autoplay無しの方ではprogress
のみが発生していました。
間隔は、こちらも約400msくらいでした。
FireFox
autoplay有の方は映像が表示されましたが、無しの方は何も表示されませんでした。
コンソールのログを見てみるとautoplay有の方ではtimeupdate
のみが連続して発生していました。
一方、無しの方ではprogress
もtimeupdate
も発生していませんでした。
まとめ
progress
は、読み込み中に発生するイベントで、timeupdate
は再生時間は変化したときに発生するイベントです。
今回の結果から、getUserMediaで映像を取得すると、数百msほどの映像として分割されて取得されているということが予想できます。(getUserMediaの挙動に関しては要調査ですね...)
autoplayを指定すると、分割された映像が連続して再生されているようです。
また、ブラウザによって挙動が違う件ですが、
Google Chrome→映像ストリームの読み込みまでを行う。
FireFox→読み込みは行わない
ということなのでしょう。
WebRTCはブラウザによって動作が違うのでめんどくさいおもしろいですね。
Edgeはどうなるんでしょうか...