1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
---
title: MediaDevices.ondevicechange
slug: Web/API/MediaDevices/ondevicechange
translation_of: Web/API/MediaDevices/ondevicechange
---
<p>{{APIRef("Media Capture and Streams")}}</p>
<p><span class="seoSummary"><strong><code>MediaDevices.ondevicechange</code></strong></span>プロパティは<span class="seoSummary">{{event("Event_handlers", "event handler")}}であり、{{domxref("MediaDevices")}}インスタンスで{{event("devicechange")}}が発生した時に呼び出される関数です。このイベントは、{{Glossary("user agent")}}、Webサイト、アプリケーションによって利用可能なメディアデバイスの一覧が変更された時に発生します。更新された利用可能デバイスの一覧は{{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}}によっていつでも取得することができます。</span></p>
<h2 id="文法">文法</h2>
<pre class="syntaxbox"><em>MediaDevices</em>.ondevicechange = <em>eventHandler</em>;
</pre>
<h3 id="値">値</h3>
<p>{{event("devicechange")}}イベントが発生したことを示す{{domxref("Event")}}オブジェクトを入力として受け付ける関数を指定してください。このイベントオブジェクトには、変更に関する情報が含まれていませんので、更新されたデバイスの一覧を取得したい場合は、{{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}}を呼び出してください。</p>
<h2 id="Example" name="Example">例</h2>
<p>この例では、<code>updateDeviceList()</code>という関数があり、この関数は{{domxref("MediaDevices.getUserMedia()")}}が成功して、ストリームを取得できた時に一度だけ呼び出され、その後デバイスの一覧に変更があった場合も複数回呼び出されます。この関数は、ブラウザウィンドウに2つの一覧を出力します。1つは、オーディオデバイスの一覧であり、もう1つはビデオデバイスの一覧です。これら2つのリストは、デバイスラベル (名前)とこのデバイスが入力か出力であるかを示すものです。この例では、{{event("devicechange")}}イベントのハンドラを設定しているので、実行中にデバイスが接続または接続を解除されるたびに一覧が更新されます。</p>
<div class="hidden">
<h3 id="HTML">HTML</h3>
<pre class="brush: html"><p>Click the start button below to begin the demonstration.</p>
<div id="startButton" class="button">
Start
</div>
<video id="video" width="160" height="120" autoplay></video><br>
<div class="left">
<h2>Audio devices:</h2>
<ul class="deviceList" id="audioList"></ul>
</div>
<div class="right">
<h2>Video devices:</h2>
<ul class="deviceList" id="videoList"></ul>
</div>
<div id="log"></div></pre>
<h3 id="CSS">CSS</h3>
<pre class="brush: css">body {
font: 14px "Open Sans", "Arial", sans-serif;
}
video {
margin-top: 20px;
border: 1px solid black;
}
.button {
cursor: pointer;
width: 160px;
border: 1px solid black;
font-size: 16px;
text-align: center;
padding-top: 2px;
padding-bottom: 4px;
color: white;
background-color: darkgreen;
}
h2 {
margin-bottom: 4px;
}
.left {
float:left;
width: 48%;
margin-right: 2%
}
.right {
float:right;
width: 48%;
margin-left: 2%
}
.deviceList {
border: 1px solid black;
list-style-type: none;
margin-top: 2px;
padding: 6px;
}</pre>
<h3 id="JavaScript">JavaScript</h3>
<h4 id="他のコード">他のコード</h4>
<p>下のコードは、<code>ondevicechange</code>と直接関係がないため詳細を省きます。</p>
<pre class="brush: js">let videoElement = document.getElementById("video");
let logElement = document.getElementById("log");
function log(msg) {
logElement.innerHTML += msg + "<br>";
}
document.getElementById("startButton").addEventListener("click", function() {
navigator.mediaDevices.getUserMedia({
video: {
width: 160,
height: 120,
frameRate: 30
},
audio: {
sampleRate: 44100,
sampleSize: 16,
volume: 0.25
}
}).then(stream => {
videoElement.srcObject = stream;
updateDeviceList();
})
.catch(err => log(err.name + ": " + err.message));
}, false);</pre>
</div>
<p>オーディオとビデオデバイスの一覧に使用される{{HTMLElement("ul")}}要素への参照を保持するためのグローバル変数を用意します。</p>
<pre class="brush: js">let audioList = document.getElementById("audioList");
let videoList = document.getElementById("videoList");</pre>
<h4 id="デバイス一覧_の取得と描画">デバイス一覧 の取得と描画</h4>
<p><code>updateDeviceList()</code>メソッドでは、現在のメディアデバイスの一覧を取得した後、先ほど用意したグローバル変数を用いて、表示されているオーディオとビデオのデバイス一覧を更新します。</p>
<pre class="brush: js">function updateDeviceList() {
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
audioList.innerHTML = "";
videoList.innerHTML = "";
devices.forEach(function(device) {
let elem = document.createElement("li");
let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i);
elem.innerHTML = "<strong>" + device.label + "</strong> (" + direction + ")";
if (type === "audio") {
audioList.appendChild(elem);
} else if (type === "video") {
videoList.appendChild(elem);
}
});
});
}</pre>
<p><code>updateDeviceList()</code>は、{{domxref("navigator.mediaDevices")}}プロパティから参照できる{{domxref("MediaDevices")}}オブジェクトにある{{domxref("MediaDevices.enumerateDevices", "enumerateDevices()")}}関数の呼び出しから構成されます。コードが実行されるのは、<code>enumerateDevices()</code>によって返された{{jsxref("promise")}}が完了した時です。デバイス一覧の準備ができると、完了ハンドラが呼び出されます。このデバイス一覧は、完了ハンドラの引数として{{domxref("MediaDeviceInfo")}}オブジェクトの配列で渡されます。この配列のそれぞれの要素は、1つのメディア入力デバイスまたは出力デバイスについての情報を含みます。</p>
<p>すべてのデバイスの情報を出力するために、{{jsxref("Array.forEach", "forEach()")}}ループを使用します。それぞれのデバイスで、ユーザへこのデバイス情報を見せるために新しい{{HTMLElement("li")}}オブジェクトを作成します。</p>
<p><code>let [kind, type, direction] = device.kind.match(/(\w+)(input|output)/i);</code>の行について詳しく説明します。ここでは<a href="/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">分割代入</a> (<a href="/ja/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla">ECMAScript 6</a>の新しい機能)を使用しており、{{jsxref("String.match()")}}によって返された配列の値を<code>kind</code>、<code>type</code>、<code>direction</code>の変数へ代入しています。なぜこのようなことをするのかというと、{{domxref("MediaDeviceInfo.kind")}}の文字列は、"audioinput"や"videooutput"のように、メディアタイプとメディアフローの向きの2つの情報を含んでいるためです。この行で、タイプ("audio"または"video")と方向("input"と"output")を取り出すことで、リストに表示する文字列を作成することができます。</p>
<p>太字のデバイス名と括弧で囲まれた方向を含む文字列が作成されると、デバイスタイプに基づいて<code>audioList</code>または<code>videoList</code>対応する一覧へ{{domxref("Node.appendChild", "appendChild()")}}の呼び出しによって追加されます。</p>
<h4 id="デバイス一覧の変更を扱う">デバイス一覧の変更を扱う</h4>
<p><code>updateDeviceList()</code>は2箇所から呼び出されます。1箇所目は{{domxref("MediaDevices.getUserMedia", "getUserMedia()")}}のpromiseの完了ハンドラであり、ストリームが開かれた時に最初に一覧を埋めます。2箇所目は{{event("devicechange")}}のイベントハンドラからです。</p>
<pre class="brush: js">navigator.mediaDevices.ondevicechange = function(event) {
updateDeviceList();
}</pre>
<p>このコードでは、ユーザがカメラ、マイク、他のメディアデバイスを接続したり、電源を入れたり、電源を切ったりする度に、<code>updateDeviceList()</code>を呼び出し接続されたデバイス一覧を再描画します。</p>
<h3 id="結果">結果</h3>
<p>{{ EmbedLiveSample('Example', 600, 460) }}</p>
<h2 id="仕様">仕様</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">仕様</th>
<th scope="col">状況</th>
<th scope="col">コメント</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ SpecName('Media Capture', '#dom-mediadevices-ondevicechange', 'ondevicechange') }}</td>
<td>{{ Spec2('Media Capture') }}</td>
<td>初版</td>
</tr>
</tbody>
</table>
<h2 id="ブラウザ互換性">ブラウザ互換性</h2>
<p>{{Compat("api.MediaDevices.ondevicechange")}}</p>
<h2 id="関連項目">関連項目</h2>
<ul>
<li>The {{event("devicechange")}}イベントとその型である{{domxref("Event")}}</li>
<li>{{domxref("MediaDevices.enumerateDevices()")}}</li>
<li>{{domxref("MediaDeviceInfo")}}</li>
</ul>
|