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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
|
---
title: 能力、制約、そして設定
slug: Web/API/Media_Streams_API/Constraints
tags:
- Advanced
- Audio
- Constraints
- Example
- Guide
- Media
- Media Capture and Streams API
- Media Streams API
- Settings
- Video
- WebRTC
- capabilities
translation_of: Web/API/Media_Streams_API/Constraints
---
<div>{{DefaultAPISidebar("Media Capture and Streams")}}</div>
<p>歴史的に、Web API と密接に連携するウェブ用のスクリプトを作成することには、よく知られた課題がありました。 多くの場合、コードは、API が存在するかどうか、存在する場合は、それを実行している{{Glossary("user agent","ユーザーエージェント")}}の制限を知る必要があります。 これを理解するのは難しい場合が多く、通常、実行している{{Glossary("user agent","ユーザーエージェント")}}(またはブラウザー)とそのバージョンの組み合わせを調べ、特定のオブジェクトが存在するかどうかを確認したり、さまざまなものが機能するかどうかを確認したり、どのエラーが発生したかを判断したりする必要がありました。 その結果、非常に脆弱なコードが大量に発生するか、このような問題を解決するライブラリに依存したり、{{Glossary("polyfill", "ポリフィル")}}を実装して実装の穴にパッチを当てたりしました。</p>
<p><span class="seoSummary"><strong>制約</strong>(constraints)と<strong>能力</strong>(capabilities)の双子の概念により、ブラウザーとウェブサイトまたはアプリは、ブラウザーの実装がサポートする<strong>制約可能なプロパティ</strong>(constrainable properties)と、それぞれに対してサポートする値に関する情報を交換できます。 この記事では、能力と制約およびメディアの設定について説明し、{{anch("Example Constraint exerciser", "制約エクササイザー")}}(Constraint Exerciser)と呼ばれる例を含みます。</span> 制約エクササイザーを使用すると、コンピューターの A/V 入力デバイス(ウェブカメラやマイクなど)からの音声トラックと動画トラックに適用されるさまざまな制約セットの結果を試すことができます。</p>
<h2 id="Overview" name="Overview">概要</h2>
<p>プロセスは次のように動作します(例として {{domxref("MediaStreamTrack")}} を使用)。</p>
<ol>
<li>必要に応じて、{{domxref("MediaDevices.getSupportedConstraints()")}} を呼び出して、<strong>サポートしている制約</strong>(supported constraints)のリストを取得します。 これにより、ブラウザーが知っている制約可能なプロパティがわかります。 これは必ずしも必要なわけではありません。 知らないものは指定すると単に無視されるためです。 ただし、それなしでは手に入らないものがある場合は、リストに載っていることを確認することから始めることができます。</li>
<li>使用したいプロパティをサポートしているかどうかをスクリプトが認識すると、トラックの <code>getCapabilities()</code> メソッドによって返されたオブジェクトを調べることにより、API とその実装の<strong>能力</strong>を確認できます。 このオブジェクトは、サポートしている各制約と、サポートしている値または値の範囲をリストします。</li>
<li>最後に、トラックの <code>applyConstraints()</code> メソッドを呼び出して、好みの制約可能なプロパティに使用する値または値の範囲を指定することにより、必要に応じて API を構成します。</li>
<li>トラックの <code>getConstraints()</code> メソッドは、<code>applyConstraints()</code> の最新の呼び出しに渡された制約セットを返します。 これは、要求された値を調整する必要があるプロパティと、プラットフォームのデフォルト値が表されていないため、トラックの実際の現在の状態を表していない場合があります。 トラックの現在の構成を完全に表現するには、<code>getSettings()</code> を使用します。</li>
</ol>
<p>Media Stream API では、{{domxref("MediaStream")}} と {{domxref("MediaStreamTrack")}} の両方に制約可能なプロパティがあります。</p>
<h2 id="Determining_if_a_constraint_is_supported" name="Determining_if_a_constraint_is_supported">制約をサポートしているかどうかの判断</h2>
<p>特定の制約をユーザーエージェントがサポートしているかどうかを知る必要がある場合は、次のように {{domxref("MediaDevices.getSupportedConstraints", "navigator.mediaDevices.getSupportedConstraints()")}} を呼び出して、ブラウザーが知っている制約可能なプロパティのリストを取得します。</p>
<pre class="brush: js">let supported = navigator.mediaDevices.getSupportedConstraints();
document.getElementById("frameRateSlider").disabled = !supported["frameRate"];</pre>
<p>この例では、サポートしている制約を取得し、<code>frameRate</code> 制約をサポートしていない場合、ユーザーがフレームレートを構成できるコントロールを無効にします。</p>
<h2 id="How_constraints_are_defined" name="How_constraints_are_defined">制約の定義方法</h2>
<p>単一の制約は、目的の値または値の範囲が指定されている制約可能なプロパティと名前が一致するオブジェクトです。 このオブジェクトには、0 個以上の個別の制約と、<code>advanced</code> というオプションのサブオブジェクトが含まれます。 このサブオブジェクトには、ユーザーエージェントが可能な限り満たす必要がある 0 個以上の制約の別のセットが含まれます。 ユーザーエージェントは、制約セットで指定された順序で制約を満たすことを試みます。</p>
<p>理解すべき最も重要なことは、ほとんどの制約は必要条件ではないということです。 それよりむしろ、それらは要求です。 例外があり、すぐにそれらに到達します。</p>
<h3 id="Requesting_a_specific_value_for_a_setting" name="Requesting_a_specific_value_for_a_setting">設定に特定の値を要求</h3>
<p>最も簡単には、各制約は、設定に必要な値を示す特定の値である場合があります。 例えば、次のようにです。</p>
<pre class="brush: js">let constraints = {
width: 1920,
height: 1080,
aspectRatio: 1.777777778
};
myTrack.applyConstraints(constraints);</pre>
<p>この場合、制約は、ほぼすべてのプロパティで任意の値が適切であることを示しますが、標準の 16:9 アスペクト比で標準の高解像度(HD)動画サイズが望ましいことを示します。 結果のトラックがこれらのいずれかに一致するという保証はありませんが、ユーザーエージェントは可能な限り一致するように最善を尽くす必要があります。</p>
<p>プロパティの優先順位付けは簡単です。 2つのプロパティの要求値が相互に排他的である場合、制約セットの最初にリストされている値を使用します。 例として、上記のコードを実行しているブラウザーは 1920x1080 のトラックを提供できないが、1920x900 を提供できる場合、それを提供します。</p>
<p>単一の値を指定するこれらのような単純な制約は、常に必須でないものとして扱われます。 ユーザーエージェントは、あなたが要求したものを提供しようとしますが、あなたが得るものが一致することを保証しません。 しかしながら、{{domxref("MediaStreamTrack.applyConstraints()")}} を呼び出すときにプロパティに単純な値を使用すると、これらの値は必要条件ではなく要求と見なされるため、要求は常に成功します。</p>
<h3 id="Specifying_a_range_of_values" name="Specifying_a_range_of_values">値の範囲の指定</h3>
<p>場合によっては、範囲内の任意の値がプロパティの値として受け入れられることがあります。 範囲は、最小値(<code>min</code>)と最大値(<code>max</code>)のいずれかまたは両方を指定でき、必要に応じて範囲内で理想的な値(<code>ideal</code>)を最終結果として指定できます。 理想的な値を指定すると、ブラウザーは、指定された他の制約に応じて、その値にできるだけ一致するように近づけようとします。</p>
<pre class="brush: js">let supports = navigator.mediaDevices.getSupportedConstraints();
if (!supports["width"] || !supports["height"] || !supports["frameRate"] || !supports["facingMode"]) {
// 必要なプロパティが不足しているため、そのエラーを処理します。
} else {
let constraints = {
width: { min: 640, ideal: 1920, max: 1920 },
height: { min: 400, ideal: 1080 },
aspectRatio: 1.777777778,
frameRate: { max: 30 },
facingMode: { exact: "user" }
};
myTrack.applyConstraints(constraints).then(function() => {
/* 制約が正常に適用されたら何かをする */
}).catch(function(reason) {
/* 制約を適用できませんでした。 reason が理由 */
});
}
</pre>
<p>ここでは、一致を見つける必要のある制約可能なプロパティ(<code>width</code>、<code>height</code>、<code>frameRate</code>、<code>facingMode</code>)がサポートされていることを確認した後、幅は 640 以上 1920 以下(できれば 1920)、高さは 400 以上(理想的には 1080)、アスペクト比は 16:9(1.777777778)、フレームレートは 30 フレーム/秒以下を要求する制約を設定します。 さらに、唯一の許容可能な入力デバイスは、ユーザーに面したカメラ(自撮りカメラ)です。 <code>width</code>、<code>height</code>、<code>frameRate</code>、または <code>facingMode</code> の制約が満たされない場合、<code>applyConstraints()</code> によって返された promise は拒否されます。</p>
<div class="note">
<p><code>max</code>、<code>min</code>、<code>exact</code> のいずれかまたはすべてを使用して指定された制約は、常に必須として扱われます。 <code>applyConstraints()</code> を呼び出して、使用する制約を1つ以上を満たすことができない場合、promise は拒否されます。</p>
</div>
<h3 id="Advanced_constraints" name="Advanced_constraints">高度な制約</h3>
<p><code>advanced</code> プロパティを制約セットに追加すると、いわゆる高度な制約が作成されます。 このプロパティの値は、オプションと見なされる追加の制約セットの配列です。 この機能のユースケースはほとんどなく、仕様から取り除くことに関心があるため、ここでは説明しません。 詳細については、<a href="https://www.w3.org/TR/mediacapture-streams/#idl-def-Constraints">Media Capture and Streams 仕様のセクション 11、過去の例 2</a> を参照してください。</p>
<h2 id="Checking_capabilities" name="Checking_capabilities">能力の確認</h2>
<p>{{domxref("MediaStreamTrack.getCapabilities()")}} を呼び出して、サポートしているすべての能力と、そのそれぞれが現在のプラットフォームとユーザーエージェントで受け入れられる値または値の範囲のリストを取得できます。 この関数は、ブラウザーがサポートしている各制約可能なプロパティと、それらのプロパティのそれぞれがサポートしている値または値の範囲をリストする {{domxref("MediaTrackCapabilities")}} オブジェクトを返します。</p>
<div class="note">
<p><strong>注</strong>: <code>getCapabilities()</code> は、まだすべての主要なブラウザーで実装されていません。 とりあえず、あなたは必要なものを手に入れようとする必要があり、もしそれができなければ、その時点で何をすべきかを決定します。 例えば、{{bug(1179084)}} を参照してください。</p>
</div>
<h2 id="Applying_constraints" name="Applying_constraints">制約の適用</h2>
<p>制約を使用する最初の最も一般的な方法は、次のように {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} を呼び出すときに制約を指定することです。</p>
<pre class="brush: js">navigator.mediaDevices.getUserMedia({
video: {
width: { min: 640, ideal: 1920 },
height: { min: 400, ideal: 1080 },
aspectRatio: { ideal: 1.7777777778 }
},
audio: {
sampleSize: 16,
channelCount: 2
}
}).then(stream => {
videoElement.srcObject = stream;
}).catch(handleError);
</pre>
<p>この例では、<code>getUserMedia()</code> の時点で制約が適用され、動画のためのフォールバックを備えた理想的なオプションのセットが要求されます。</p>
<div class="note">
<p>1つ以上のメディア入力デバイス ID を指定して、入力ソースが許可される制限を設定できます。 利用可能なデバイスのリストを収集するには、{{domxref("MediaDevices.enumerateDevices", "navigator.mediaDevices.enumerateDevices()")}} を呼び出してから、目的の条件を満たす各デバイスに対して、その <code>deviceId</code> を <code>MediaConstraints</code> オブジェクトに追加して、最終的に <code>getUserMedia()</code> に渡します。</p>
</div>
<p>次のようにトラックの {{domxref("MediaStreamTrack.applyConstraints", "applyConstraints()")}} メソッドを呼び出し、トラックに適用する制約を表すオブジェクトを渡すことで、既存の {{domxref("MediaStreamTrack")}} の制約を臨機応変に変更することもできます。</p>
<pre class="brush: js">videoTrack.applyConstraints({
width: 1920,
height: 1080
});
</pre>
<p>このスニペットでは、<code>videoTrack</code> が参照する動画トラックが更新され、その解像度が可能な限り 1920x1080 ピクセル(1080p 高解像度)に一致するようになります。</p>
<h2 id="Retrieving_current_constraints_and_settings" name="Retrieving_current_constraints_and_settings">現在の制約と設定の取得</h2>
<p><strong>制約</strong>と<strong>設定</strong>(settings)の違いを覚えておくことは重要です。 制約は、({{domxref("MediaTrackConstraints")}} のドキュメントで説明されているように)さまざまな制約可能なプロパティに必要な値、希望する値、および受け入れる値を指定する方法です。 一方、設定は現在の各制約可能なプロパティの実際の値です。</p>
<h3 id="Getting_the_constraints_in_effect" name="Getting_the_constraints_in_effect">実施されている制約の取得</h3>
<p>現在メディアに適用されている制約セットを取得する必要がある場合は、次の例に示すように、{{domxref("MediaStreamTrack.getConstraints()")}} を呼び出すことでその情報を取得できます。</p>
<pre class="brush: js">function switchCameras(track, camera) {
let constraints = track.getConstraints();
constraints.facingMode = camera;
track.applyConstraints(constraints);
}</pre>
<p>この関数は、{{domxref("MediaStreamTrack")}} と使用するカメラに面するモードを示す文字列を受け入れ、現在の制約を取得し、{{domxref("MediaTrackConstraints.facingMode")}} の値を指定された値に設定し、更新された制約セットを適用します。</p>
<h3 id="Getting_the_current_settings_for_a_track" name="Getting_the_current_settings_for_a_track">トラックの現在の設定の取得</h3>
<p>厳密な制約(<code>exact</code>)のみを使用しない限り(これは非常に制限的ですので、それの意味することを確認してください!)、制約が適用された後に実際に何が得られるかを保証するものではありません。 結果のメディアに実際に存在する制約可能なプロパティの値は、設定と呼ばれます。 メディアの実際の形式やその他のプロパティを知る必要がある場合は、{{domxref("MediaStreamTrack.getSettings()")}} を呼び出してこれらの設定を取得できます。 これは、ディクショナリ {{domxref("MediaTrackSettings")}} に基づくオブジェクトを返します。 例えば次のようにです。</p>
<pre class="brush: js">function whichCamera(track) {
return track.getSettings().facingMode;
}</pre>
<p>この関数は、<code>getSettings()</code> を使用して、トラックの制約可能なプロパティの現在使用中の値を取得し、{{domxref("MediaTrackSettings.facingMode", "facingMode")}} の値を返します。</p>
<h2 id="Example_Constraint_exerciser" name="Example_Constraint_exerciser">例: 制約エクササイザー</h2>
<p>この例では、音声トラックと動画トラックの制約セットを記述するソースコードを編集して、メディアの制約を試すことができるエクササイザーを作成します。 その後、これらの変更を適用して、ストリームの外観や、新しい制約を適用した後の実際のメディア設定の両方を含む結果を確認できます。</p>
<p>この例の HTML と CSS は非常に単純であり、ここには示されていません。 {{LiveSampleLink("Example_Constraint_exerciser", "ここをクリックする")}}と、完全な例を見ることができます。</p>
<div class="hidden">
<h3 id="HTML_content" name="HTML_content">HTML content</h3>
<pre class="brush: html"><p>メディアの制約を試してください! 左側の編集ボックスで動画トラックと音声トラックの制約セットを編集し、[制約の適用] ボタンをクリックして試してください。 ブラウザーが選択して使用している実際の設定は、右側のボックスに表示されます。 そのすべての下に、動画自体が表示されます。
</p>
<p>[動画の開始] ボタンをクリックして開始します。</p>
<h3>使用できる制約可能なプロパティ:</h3>
<ul id="supportedConstraints">
</ul>
<div id="startButton" class="button">
動画の開始
</div>
<div class="wrapper">
<div class="leftside">
<h3>要求した動画の制約:</h3>
<textarea id="videoConstraintEditor" cols=32 rows=8></textarea>
</div>
<div class="rightside">
<h3>実際の動画の設定:</h3>
<textarea id="videoSettingsText" cols=32 rows=8 disabled></textarea>
</div>
<div class="leftside">
<h3>要求した音声の制約:</h3>
<textarea id="audioConstraintEditor" cols=32 rows=8></textarea>
</div>
<div class="rightside">
<h3>実際の音声の設定:</h3>
<textarea id="audioSettingsText" cols=32 rows=8 disabled></textarea>
</div>
</div>
<div class="button" id="applyButton">
制約の適用
</div>
<video id="video" autoplay></video>
<div class="button" id="stopButton">
動画の停止
</div>
<div id="log">
</div></pre>
<h3 id="CSS_content" name="CSS_content">CSS content</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: 150px;
border: 1px solid black;
font-size: 16px;
text-align: center;
padding-top: 3px;
padding-bottom: 2px;
color: white;
background-color: darkgreen;
}
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
gap: 10px;
max-width: min-content;
margin-bottom: 10px;
}
textarea {
width : 270px;
padding: 8px;
}
h3 {
margin-bottom: 3px;
}
#supportedConstraints {
column-count: 2;
-moz-column-count: 2;
}
#log {
padding-top: 10px;
}</pre>
<h3 id="JavaScript_content" name="JavaScript_content">JavaScript content</h3>
<p>Now let's take a look at the JavaScript code that makes everything work.</p>
</div>
<h4 id="Defaults_and_variables" name="Defaults_and_variables">デフォルトと変数</h4>
<p>最初に、文字列としてデフォルトの制約セットがあります。 これらの文字列は編集可能な {{HTMLElement("textarea")}} に表示されますが、これはストリームの初期構成です。</p>
<pre class="brush: js">let videoDefaultConstraintString = '{\n "width": 320,\n "height": 240,\n "frameRate": 30\n}';
let audioDefaultConstraintString = '{\n "sampleSize": 16,\n "channelCount": 2,\n "echoCancellation": false\n}';
</pre>
<p>これらのデフォルトは、かなり一般的なカメラ構成を要求しますが、特に重要なプロパティであることを主張しません。 ブラウザーは、これらの設定に一致するように最善を尽くす必要がありますが、近い一致と見なされるものなら何でもそれで解決します。</p>
<p>次に、動画トラックおよび音声トラックの {{domxref("MediaTrackConstraints")}} オブジェクトを保持する変数と、動画トラックおよび音声トラック自体への参照を保持する変数を <code>null</code> に初期化します。</p>
<pre class="brush: js">let videoConstraints = null;
let audioConstraints = null;
let audioTrack = null;
let videoTrack = null;
</pre>
<p>そして、アクセスする必要のあるすべての要素への参照を取得します。</p>
<pre class="brush: js">let videoElement = document.getElementById("video");
let logElement = document.getElementById("log");
let supportedConstraintList = document.getElementById("supportedConstraints");
let videoConstraintEditor = document.getElementById("videoConstraintEditor");
let audioConstraintEditor = document.getElementById("audioConstraintEditor");
let videoSettingsText = document.getElementById("videoSettingsText");
let audioSettingsText = document.getElementById("audioSettingsText");
</pre>
<p>これらの要素は次のとおりです。</p>
<dl>
<dt><code>videoElement</code></dt>
<dd>ストリームを表示する {{HTMLElement("video")}} 要素。</dd>
<dt><code>logElement</code></dt>
<dd>エラーメッセージやその他のログの種類の出力が書き込まれる {{HTMLElement("div")}}。</dd>
<dt><code>supportedConstraintList</code></dt>
<dd>ユーザーのブラウザーがサポートしている各制約可能なプロパティの名前をプログラムで追加する {{HTMLElement("ul")}}(順序なしリスト)。</dd>
<dt><code>videoConstraintEditor</code></dt>
<dd>ユーザーが動画トラックの制約セットのコードを編集できるようにする {{HTMLElement("textarea")}} 要素。</dd>
<dt><code>audioConstraintEditor</code></dt>
<dd>ユーザーが音声トラックの制約セットのコードを編集できるようにする {{HTMLElement("textarea")}} 要素。</dd>
<dt><code>videoSettingsText</code></dt>
<dd> 動画トラックの制約可能なプロパティの現在の設定を表示する {{HTMLElement("textarea")}}(常に <code>disabled</code>)。</dd>
<dt><code>audioSettingsText</code></dt>
<dd>音声トラックの制約可能なプロパティの現在の設定を表示する {{HTMLElement("textarea")}}(常に <code>disabled</code>)。</dd>
</dl>
<p>最後に、2つの制約セットエディター要素の現在の内容をデフォルトに設定します。</p>
<pre class="brush: js">videoConstraintEditor.value = videoDefaultConstraintString;
audioConstraintEditor.value = audioDefaultConstraintString;</pre>
<h4 id="Updating_the_settings_display" name="Updating_the_settings_display">設定の表示の更新</h4>
<p>各制約セットエディターの右側には、トラックの構成可能なプロパティの現在の構成を表示するために使用する2番目のテキストボックスがあります。 この表示を関数 <code>getCurrentSettings()</code> で更新します。 この関数は、音声トラックと動画トラックの現在の設定を取得し、{{htmlattrxref("value", "textarea")}} を設定することで対応するコードをトラックの設定表示ボックスに挿入します。</p>
<pre class="brush: js">function getCurrentSettings() {
if (videoTrack) {
videoSettingsText.value = JSON.stringify(videoTrack.getSettings(), null, 2);
}
if (audioTrack) {
audioSettingsText.value = JSON.stringify(audioTrack.getSettings(), null, 2);
}
}
</pre>
<p>これは、以下に示すように、更新した制約を適用するときだけでなく、ストリームの最初の起動後にも呼び出されます。</p>
<h4 id="Building_the_track_constraint_set_objects" name="Building_the_track_constraint_set_objects">トラックの制約セットオブジェクトの構築</h4>
<p><code>buildConstraints()</code> 関数は、2つのトラックの制約セット編集ボックス内のコードを使用して、音声トラックと動画トラックの {{domxref("MediaTrackConstraints")}} オブジェクトを構築します。</p>
<pre class="brush: js">function buildConstraints() {
try {
videoConstraints = JSON.parse(videoConstraintEditor.value);
audioConstraints = JSON.parse(audioConstraintEditor.value);
} catch(error) {
handleError(error);
}
}
</pre>
<p>これは {{jsxref("JSON.parse()")}} を使用して、各エディター内のコードをオブジェクトに解析します。 <code>JSON.parse()</code> の呼び出しのどちらかが例外をスローした場合、<code>handleError()</code> が呼び出されてエラーメッセージがログに出力されます。</p>
<h4 id="Configuring_and_starting_the_stream" name="Configuring_and_starting_the_stream">ストリームの構成と開始</h4>
<p><code>startVideo()</code> メソッドは、動画ストリームのセットアップと開始を処理します。</p>
<ol>
</ol>
<pre class="brush: js">function startVideo() {
buildConstraints();
navigator.mediaDevices.getUserMedia({
video: videoConstraints,
audio: audioConstraints
}).then(function(stream) {
let audioTracks = stream.getAudioTracks();
let videoTracks = stream.getVideoTracks();
videoElement.srcObject = stream;
if (audioTracks.length) {
audioTrack = audioTracks[0];
}
if (videoTracks.length) {
videoTrack = videoTracks[0];
}
}).then(function() {
new Promise(function(resolve) {
videoElement.onloadedmetadata = resolve;
});
}).then(function() {
getCurrentSettings();
}).catch(handleError);
}
</pre>
<p>ここには、次のようないくつかの手順があります。</p>
<ol>
<li><code>buildConstraints()</code> を呼び出して、編集ボックス内のコードから2つのトラックの {{domxref("MediaTrackConstraints")}} オブジェクトを作成します。</li>
<li>{{domxref("MediaDevices.getUserMedia", "navigator.mediaDevices.getUserMedia()")}} を呼び出し、動画トラックおよび音声トラックの制約オブジェクトを渡します。 これにより、入力に一致するソースからの音声と動画を含む {{domxref("MediaStream")}} が返されます(通常はウェブカメラですが、適切な制約を指定すると他のソースからメディアを取得できます)。</li>
<li>ストリームを取得したら、画面に表示されるように {{HTMLElement("video")}} 要素に添付し、音声トラックと動画トラックを変数 <code>audioTrack</code> と <code>videoTrack</code> に取り込みます。</li>
<li>次に、動画要素で {{event("onloadedmetadata")}} イベントが発生したときに解決する promise を設定します。</li>
<li>それが起こると、動画の再生を開始したことがわかるので、<code>getCurrentSettings()</code> 関数(上記を参照)を呼び出して、制約とハードウェアの能力を考慮した後にブラウザーが決定した実際の設定を表示します。</li>
<li>エラーが発生した場合は、この記事のもっと下で説明する <code>handleError()</code> メソッドを使用してログに記録します。</li>
</ol>
<p>また、[動画の開始] ボタンがクリックされるのを監視するイベントリスナーを設定する必要があります。</p>
<pre class="brush: js">document.getElementById("startButton").addEventListener("click", function() {
startVideo();
}, false);
</pre>
<h4 id="Applying_constraint_set_updates" name="Applying_constraint_set_updates">制約セットの更新の適用</h4>
<p>次に、[制約の適用] ボタンのイベントリスナーを設定します。 クリックされ、まだ使用中のメディアがない場合は、<code>startVideo()</code> を呼び出し、指定された設定でストリームを開始する機能をその関数に処理させます。 それ以外の場合は、次の手順に従って、更新済みの制約を既にアクティブなストリームに適用します。</p>
<ol>
<li><code>buildConstraints()</code> を、音声トラック(<code>audioConstraints</code>)および動画トラック(<code>videoConstraints</code>)の更新された {{domxref("MediaTrackConstraints")}} オブジェクトを構築するために呼び出します。</li>
<li>{{domxref("MediaStreamTrack.applyConstraints()")}} を、新しい <code>videoConstraints</code> を適用するために動画トラック(存在する場合)で呼び出します。 これが成功したら、動画トラックの現在の設定ボックスの内容を、{{domxref("MediaStreamTrack.getSettings", "getSettings()")}} メソッドを呼び出した結果に基づいて更新します。</li>
<li>それが完了すると、新しい音声制約を適用するために、<code>applyConstraints()</code> を音声トラック(存在する場合)で呼び出します。 これが成功したら、音声トラックの現在の設定ボックスの内容を、{{domxref("MediaStreamTrack.getSettings", "getSettings()")}} メソッドを呼び出した結果に基づいて更新しす。</li>
<li>いずれかの制約セットを適用してエラーが発生した場合、<code>handleError()</code> を使用してメッセージをログに出力します。</li>
</ol>
<pre class="brush: js">document.getElementById("applyButton").addEventListener("click", function() {
if (!videoTrack && !audioTrack) {
startVideo();
} else {
buildConstraints();
if (videoTrack) {
videoTrack.applyConstraints(videoConstraints).then(function() {
videoSettingsText.value = JSON.stringify(videoTrack.getSettings(), null, 2);
}).catch(handleError);
}
if (audioTrack) {
audioTrack.applyConstraints(audioConstraints).then(function() {
audioSettingsText.value = JSON.stringify(audioTrack.getSettings(), null, 2);
}).catch(handleError);
}
}
}, false);
</pre>
<h4 id="Handling_the_stop_button" name="Handling_the_stop_button">停止ボタンの処理</h4>
<p>次に、[動画の停止] ボタンのハンドラーを設定します。</p>
<pre class="brush: js">document.getElementById("stopButton").addEventListener("click", function() {
if (videoTrack) {
videoTrack.stop();
}
if (audioTrack) {
audioTrack.stop();
}
videoTrack = audioTrack = null;
videoElement.srcObject = null;
});
</pre>
<p>これは単にアクティブなトラックを停止し、<code>videoTrack</code> 変数と <code>audioTrack</code> 変数を <code>null</code> に設定してそれらがなくなったことがわかるようにし、{{domxref("HTMLMediaElement.srcObject")}} を <code>null</code> に設定して {{HTMLElement("video")}} 要素からストリームを取り除きます。</p>
<h4 id="Simple_tab_support_in_the_editor" name="Simple_tab_support_in_the_editor">エディターでの単純な <kbd>tab</kbd> のサポート</h4>
<p>このコードは、いずれかの制約編集ボックスがフォーカスされているときに <kbd>tab</kbd> キーで2つのスペース文字を挿入することにより、{{HTMLElement("textarea")}} 要素に <kbd>tab</kbd> の単純なサポートを追加します。</p>
<pre class="brush: js">function keyDownHandler(event) {
if (event.key == "Tab") {
let elem = event.target;
let str = elem.value;
let position = elem.selectionStart;
let newStr = str.substring(0, position) + " " +
str.substring(position, str.length);
elem.value = newStr;
elem.selectionStart = elem.selectionEnd = position + 2;
event.preventDefault();
}
}
videoConstraintEditor.addEventListener("keydown", keyDownHandler, false);
audioConstraintEditor.addEventListener("keydown", keyDownHandler, false);
</pre>
<h4 id="Show_constrainable_properties_the_browser_supports" name="Show_constrainable_properties_the_browser_supports">ブラウザーがサポートする制約可能なプロパティの表示</h4>
<p>パズルの最後の重要な部分: ユーザーの参照用に、ブラウザーがサポートする制約可能なプロパティのリストを表示するコード。 各プロパティは、ユーザーの利便性のために MDN のドキュメントへのリンクです。 このコードの動作の詳細については、<a href="/ja/docs/Web/API/MediaDevices/getSupportedConstraints#Example"><code>MediaDevices.getSupportedConstraints()</code> の例</a>を参照してください。</p>
<div class="note">
<p>もちろん、このリストには非標準のプロパティが含まれている場合があります。 その場合、ドキュメントのリンクはあまり役に立たないでしょう。</p>
</div>
<pre class="brush: js">let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
for (let constraint in supportedConstraints) {
if (supportedConstraints.hasOwnProperty(constraint)) {
let elem = document.createElement("li");
elem.innerHTML = "<code><a href='https://developer.mozilla.org/docs/Web/API/MediaTrackSupportedConstraints/"
.concat(constraint) + "' target='_blank'>" + constraint + "</a></code>";
supportedConstraintList.appendChild(elem);
}
}
</pre>
<h4 id="Error_handling" name="Error_handling">エラー処理</h4>
<p>また、いくつかの簡単なエラー処理コードがあります。 <code>handleError()</code> は失敗したプロミスを処理するために呼び出され、<code>log()</code> 関数は動画の下の特別なロギング {{HTMLElement("div")}} ボックスにエラーメッセージを追加します。</p>
<pre class="brush: js">function log(msg) {
logElement.innerHTML += (msg + "<br>");
}
function handleError(reason) {
log("Error <code>" + reason.name +
"</code> in constraint <code>" + reason.constraint +
"</code>: " + reason.message);
}</pre>
<h3 id="Result" name="Result">結果</h3>
<p>ここで、実際の完全な例を見ることができます。</p>
<p>{{EmbedLiveSample("Example_Constraint_exerciser", 650, 800, "", "", "", "microphone; camera")}}</p>
<h2 id="Specifications" name="Specifications">仕様</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">仕様</th>
<th scope="col">状態</th>
<th scope="col">コメント</th>
</tr>
<tr>
<td>{{SpecName('Media Capture', '#constrainable-interface', 'Constrainable pattern')}}</td>
<td>{{Spec2('Media Capture')}}</td>
<td>初期定義</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2>
<h3 id="MediaDevices.getSupportedConstraints" name="MediaDevices.getSupportedConstraints"><code>MediaDevices.getSupportedConstraints</code></h3>
<div>
<p>{{Compat("api.MediaDevices.getSupportedConstraints")}}</p>
</div>
<h2 id="See_also" name="See_also">関連情報</h2>
<ul>
<li><a href="/ja/docs/Web/API/Media_Streams_API">Media Capture and Streams API</a></li>
<li>{{domxref("MediaTrackCapabilities")}}</li>
<li>{{domxref("MediaTrackConstraints")}}</li>
<li>{{domxref("MediaTrackSettings")}}</li>
<li>{{domxref("MediaDevices.getSupportedConstraints()")}}</li>
<li>{{domxref("MediaStreamTrack.applyConstraints()")}}</li>
<li>{{domxref("MediaStreamTrack.getSettings()")}}</li>
</ul>
|