audio_buffer_queue_unittest.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/basictypes.h"
6#include "base/logging.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/stringprintf.h"
9#include "base/time/time.h"
10#include "media/base/audio_buffer.h"
11#include "media/base/audio_buffer_queue.h"
12#include "media/base/audio_bus.h"
13#include "media/base/buffers.h"
14#include "media/base/test_helpers.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace media {
18
19const int kSampleRate = 44100;
20
21static void VerifyResult(float* channel_data,
22                         int frames,
23                         float start,
24                         float increment) {
25  for (int i = 0; i < frames; ++i) {
26    SCOPED_TRACE(base::StringPrintf(
27        "i=%d/%d start=%f, increment=%f", i, frames, start, increment));
28    ASSERT_EQ(start, channel_data[i]);
29    start += increment;
30  }
31}
32
33template <typename T>
34static scoped_refptr<AudioBuffer> MakeTestBuffer(SampleFormat format,
35                                                 ChannelLayout channel_layout,
36                                                 T start,
37                                                 T end,
38                                                 int frames) {
39  const base::TimeDelta kNoTime = kNoTimestamp();
40  return MakeAudioBuffer<T>(format,
41                            channel_layout,
42                            ChannelLayoutToChannelCount(channel_layout),
43                            kSampleRate,
44                            start,
45                            end,
46                            frames,
47                            kNoTime,
48                            kNoTime);
49}
50
51TEST(AudioBufferQueueTest, AppendAndClear) {
52  const ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
53  AudioBufferQueue buffer;
54  EXPECT_EQ(0, buffer.frames());
55  buffer.Append(
56      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
57  EXPECT_EQ(8, buffer.frames());
58  buffer.Clear();
59  EXPECT_EQ(0, buffer.frames());
60  buffer.Append(
61      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 20, 1, 8));
62  EXPECT_EQ(8, buffer.frames());
63}
64
65TEST(AudioBufferQueueTest, MultipleAppend) {
66  const ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
67  AudioBufferQueue buffer;
68  buffer.Append(
69      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
70  EXPECT_EQ(8, buffer.frames());
71  buffer.Append(
72      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
73  EXPECT_EQ(16, buffer.frames());
74  buffer.Append(
75      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
76  EXPECT_EQ(24, buffer.frames());
77  buffer.Append(
78      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
79  EXPECT_EQ(32, buffer.frames());
80  buffer.Append(
81      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 10, 1, 8));
82  EXPECT_EQ(40, buffer.frames());
83}
84
85TEST(AudioBufferQueueTest, IteratorCheck) {
86  const ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
87  const int channels = ChannelLayoutToChannelCount(channel_layout);
88  AudioBufferQueue buffer;
89  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
90
91  // Append 40 frames in 5 buffers. Intersperse ReadFrames() to make the
92  // iterator is pointing to the correct position.
93  buffer.Append(MakeTestBuffer<float>(
94      kSampleFormatF32, channel_layout, 10.0f, 1.0f, 8));
95  EXPECT_EQ(8, buffer.frames());
96
97  EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
98  EXPECT_EQ(4, buffer.frames());
99  VerifyResult(bus->channel(0), 4, 10.0f, 1.0f);
100
101  buffer.Append(MakeTestBuffer<float>(
102      kSampleFormatF32, channel_layout, 20.0f, 1.0f, 8));
103  EXPECT_EQ(12, buffer.frames());
104  buffer.Append(MakeTestBuffer<float>(
105      kSampleFormatF32, channel_layout, 30.0f, 1.0f, 8));
106  EXPECT_EQ(20, buffer.frames());
107
108  buffer.SeekFrames(16);
109  EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
110  EXPECT_EQ(0, buffer.frames());
111  VerifyResult(bus->channel(0), 4, 34.0f, 1.0f);
112
113  buffer.Append(MakeTestBuffer<float>(
114      kSampleFormatF32, channel_layout, 40.0f, 1.0f, 8));
115  EXPECT_EQ(8, buffer.frames());
116  buffer.Append(MakeTestBuffer<float>(
117      kSampleFormatF32, channel_layout, 50.0f, 1.0f, 8));
118  EXPECT_EQ(16, buffer.frames());
119
120  EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
121  VerifyResult(bus->channel(0), 4, 40.0f, 1.0f);
122
123  // Read off the end of the buffer.
124  EXPECT_EQ(12, buffer.frames());
125  buffer.SeekFrames(8);
126  EXPECT_EQ(4, buffer.ReadFrames(100, 0, bus.get()));
127  VerifyResult(bus->channel(0), 4, 54.0f, 1.0f);
128}
129
130TEST(AudioBufferQueueTest, Seek) {
131  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
132  AudioBufferQueue buffer;
133
134  // Add 6 frames of data.
135  buffer.Append(MakeTestBuffer<float>(
136      kSampleFormatF32, channel_layout, 1.0f, 1.0f, 6));
137  EXPECT_EQ(6, buffer.frames());
138
139  // Seek past 2 frames.
140  buffer.SeekFrames(2);
141  EXPECT_EQ(4, buffer.frames());
142
143  // Seek to end of data.
144  buffer.SeekFrames(4);
145  EXPECT_EQ(0, buffer.frames());
146
147  // At end, seek now fails unless 0 specified.
148  buffer.SeekFrames(0);
149}
150
151TEST(AudioBufferQueueTest, ReadF32) {
152  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
153  const int channels = ChannelLayoutToChannelCount(channel_layout);
154  AudioBufferQueue buffer;
155
156  // Add 76 frames of data.
157  buffer.Append(
158      MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 1.0f, 1.0f, 6));
159  buffer.Append(
160      MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 13.0f, 1.0f, 10));
161  buffer.Append(
162      MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 33.0f, 1.0f, 60));
163  EXPECT_EQ(76, buffer.frames());
164
165  // Read 3 frames from the buffer. F32 is interleaved, so ch[0] should be
166  // 1, 3, 5, and ch[1] should be 2, 4, 6.
167  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
168  EXPECT_EQ(3, buffer.ReadFrames(3, 0, bus.get()));
169  EXPECT_EQ(73, buffer.frames());
170  VerifyResult(bus->channel(0), 3, 1.0f, 2.0f);
171  VerifyResult(bus->channel(1), 3, 2.0f, 2.0f);
172
173  // Now read 5 frames, which will span buffers. Append the data into AudioBus.
174  EXPECT_EQ(5, buffer.ReadFrames(5, 3, bus.get()));
175  EXPECT_EQ(68, buffer.frames());
176  VerifyResult(bus->channel(0), 8, 1.0f, 2.0f);
177  VerifyResult(bus->channel(1), 8, 2.0f, 2.0f);
178
179  // Now skip into the third buffer.
180  buffer.SeekFrames(20);
181  EXPECT_EQ(48, buffer.frames());
182
183  // Now read 2 frames, which are in the third buffer.
184  EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get()));
185  VerifyResult(bus->channel(0), 2, 57.0f, 2.0f);
186  VerifyResult(bus->channel(1), 2, 58.0f, 2.0f);
187}
188
189TEST(AudioBufferQueueTest, ReadU8) {
190  const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0;
191  const int channels = ChannelLayoutToChannelCount(channel_layout);
192  AudioBufferQueue buffer;
193
194  // Add 4 frames of data.
195  buffer.Append(
196      MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 128, 1, 4));
197
198  // Read all 4 frames from the buffer. Data is interleaved, so ch[0] should be
199  // 128, 132, 136, 140, other channels similar. However, values are converted
200  // from [0, 255] to [-1.0, 1.0] with a bias of 128. Thus the first buffer
201  // value should be 0.0, then 1/127, 2/127, etc.
202  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
203  EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get()));
204  EXPECT_EQ(0, buffer.frames());
205  VerifyResult(bus->channel(0), 4, 0.0f, 4.0f / 127.0f);
206  VerifyResult(bus->channel(1), 4, 1.0f / 127.0f, 4.0f / 127.0f);
207  VerifyResult(bus->channel(2), 4, 2.0f / 127.0f, 4.0f / 127.0f);
208  VerifyResult(bus->channel(3), 4, 3.0f / 127.0f, 4.0f / 127.0f);
209}
210
211TEST(AudioBufferQueueTest, ReadS16) {
212  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
213  const int channels = ChannelLayoutToChannelCount(channel_layout);
214  AudioBufferQueue buffer;
215
216  // Add 24 frames of data.
217  buffer.Append(
218      MakeTestBuffer<int16>(kSampleFormatS16, channel_layout, 1, 1, 4));
219  buffer.Append(
220      MakeTestBuffer<int16>(kSampleFormatS16, channel_layout, 9, 1, 20));
221  EXPECT_EQ(24, buffer.frames());
222
223  // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be
224  // 1, 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12.
225  // Data is converted to float from -1.0 to 1.0 based on int16 range.
226  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
227  EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get()));
228  EXPECT_EQ(18, buffer.frames());
229  VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 2.0f / kint16max);
230  VerifyResult(bus->channel(1), 6, 2.0f / kint16max, 2.0f / kint16max);
231}
232
233TEST(AudioBufferQueueTest, ReadS32) {
234  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
235  const int channels = ChannelLayoutToChannelCount(channel_layout);
236  AudioBufferQueue buffer;
237
238  // Add 24 frames of data.
239  buffer.Append(
240      MakeTestBuffer<int32>(kSampleFormatS32, channel_layout, 1, 1, 4));
241  buffer.Append(
242      MakeTestBuffer<int32>(kSampleFormatS32, channel_layout, 9, 1, 20));
243  EXPECT_EQ(24, buffer.frames());
244
245  // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be
246  // 1, 3, 5, 7, 100, 106, and ch[1] should be 2, 4, 6, 8, 103, 109.
247  // Data is converted to float from -1.0 to 1.0 based on int32 range.
248  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
249  EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get()));
250  EXPECT_EQ(18, buffer.frames());
251  VerifyResult(bus->channel(0), 6, 1.0f / kint32max, 2.0f / kint32max);
252  VerifyResult(bus->channel(1), 6, 2.0f / kint32max, 2.0f / kint32max);
253
254  // Read the next 2 frames.
255  EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get()));
256  EXPECT_EQ(16, buffer.frames());
257  VerifyResult(bus->channel(0), 2, 13.0f / kint32max, 2.0f / kint32max);
258  VerifyResult(bus->channel(1), 2, 14.0f / kint32max, 2.0f / kint32max);
259}
260
261TEST(AudioBufferQueueTest, ReadF32Planar) {
262  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
263  const int channels = ChannelLayoutToChannelCount(channel_layout);
264  AudioBufferQueue buffer;
265
266  // Add 14 frames of data.
267  buffer.Append(MakeTestBuffer<float>(
268      kSampleFormatPlanarF32, channel_layout, 1.0f, 1.0f, 4));
269  buffer.Append(MakeTestBuffer<float>(
270      kSampleFormatPlanarF32, channel_layout, 50.0f, 1.0f, 10));
271  EXPECT_EQ(14, buffer.frames());
272
273  // Read 6 frames from the buffer. F32 is planar, so ch[0] should be
274  // 1, 2, 3, 4, 50, 51, and ch[1] should be 5, 6, 7, 8, 60, 61.
275  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
276  EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get()));
277  EXPECT_EQ(8, buffer.frames());
278  VerifyResult(bus->channel(0), 4, 1.0f, 1.0f);
279  VerifyResult(bus->channel(0) + 4, 2, 50.0f, 1.0f);
280  VerifyResult(bus->channel(1), 4, 5.0f, 1.0f);
281  VerifyResult(bus->channel(1) + 4, 2, 60.0f, 1.0f);
282}
283
284TEST(AudioBufferQueueTest, ReadS16Planar) {
285  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
286  const int channels = ChannelLayoutToChannelCount(channel_layout);
287  AudioBufferQueue buffer;
288
289  // Add 24 frames of data.
290  buffer.Append(
291      MakeTestBuffer<int16>(kSampleFormatPlanarS16, channel_layout, 1, 1, 4));
292  buffer.Append(MakeTestBuffer<int16>(
293      kSampleFormatPlanarS16, channel_layout, 100, 5, 20));
294  EXPECT_EQ(24, buffer.frames());
295
296  // Read 6 frames from the buffer. Data is planar, so ch[0] should be
297  // 1, 2, 3, 4, 100, 105, and ch[1] should be 5, 6, 7, 8, 200, 205.
298  // Data is converted to float from -1.0 to 1.0 based on int16 range.
299  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
300  EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get()));
301  EXPECT_EQ(18, buffer.frames());
302  VerifyResult(bus->channel(0), 4, 1.0f / kint16max, 1.0f / kint16max);
303  VerifyResult(bus->channel(0) + 4, 2, 100.0f / kint16max, 5.0f / kint16max);
304  VerifyResult(bus->channel(1), 4, 5.0f / kint16max, 1.0f / kint16max);
305  VerifyResult(bus->channel(1) + 4, 2, 200.0f / kint16max, 5.0f / kint16max);
306}
307
308TEST(AudioBufferQueueTest, ReadManyChannels) {
309  const ChannelLayout channel_layout = CHANNEL_LAYOUT_OCTAGONAL;
310  const int channels = ChannelLayoutToChannelCount(channel_layout);
311  AudioBufferQueue buffer;
312
313  // Add 76 frames of data.
314  buffer.Append(
315      MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 0.0f, 1.0f, 6));
316  buffer.Append(MakeTestBuffer<float>(
317      kSampleFormatF32, channel_layout, 6.0f * channels, 1.0f, 10));
318  buffer.Append(MakeTestBuffer<float>(
319      kSampleFormatF32, channel_layout, 16.0f * channels, 1.0f, 60));
320  EXPECT_EQ(76, buffer.frames());
321
322  // Read 3 frames from the buffer. F32 is interleaved, so ch[0] should be
323  // 1, 17, 33, and ch[1] should be 2, 18, 34. Just check a few channels.
324  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
325  EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus.get()));
326  EXPECT_EQ(46, buffer.frames());
327  for (int i = 0; i < channels; ++i) {
328    VerifyResult(bus->channel(i), 30, static_cast<float>(i), 8.0f);
329  }
330}
331
332TEST(AudioBufferQueueTest, Peek) {
333  const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0;
334  const int channels = ChannelLayoutToChannelCount(channel_layout);
335  AudioBufferQueue buffer;
336
337  // Add 60 frames of data.
338  buffer.Append(
339      MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 0.0f, 1.0f, 60));
340  EXPECT_EQ(60, buffer.frames());
341
342  // Peek at the first 30 frames.
343  scoped_ptr<AudioBus> bus1 = AudioBus::Create(channels, 100);
344  EXPECT_EQ(60, buffer.frames());
345  EXPECT_EQ(60, buffer.PeekFrames(100, 0, 0, bus1.get()));
346  EXPECT_EQ(30, buffer.PeekFrames(30, 0, 0, bus1.get()));
347  EXPECT_EQ(60, buffer.frames());
348
349  // Now read the next 30 frames (which should be the same as those peeked at).
350  scoped_ptr<AudioBus> bus2 = AudioBus::Create(channels, 100);
351  EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus2.get()));
352  for (int i = 0; i < channels; ++i) {
353    VerifyResult(bus1->channel(i),
354                 30,
355                 static_cast<float>(i),
356                 static_cast<float>(channels));
357    VerifyResult(bus2->channel(i),
358                 30,
359                 static_cast<float>(i),
360                 static_cast<float>(channels));
361  }
362
363  // Peek 10 frames forward
364  EXPECT_EQ(5, buffer.PeekFrames(5, 10, 0, bus1.get()));
365  for (int i = 0; i < channels; ++i) {
366    VerifyResult(bus1->channel(i),
367                 5,
368                 static_cast<float>(i + 40 * channels),
369                 static_cast<float>(channels));
370  }
371
372  // Peek to the end of the buffer.
373  EXPECT_EQ(30, buffer.frames());
374  EXPECT_EQ(30, buffer.PeekFrames(100, 0, 0, bus1.get()));
375  EXPECT_EQ(30, buffer.PeekFrames(30, 0, 0, bus1.get()));
376}
377
378TEST(AudioBufferQueueTest, Time) {
379  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
380  const int channels = ChannelLayoutToChannelCount(channel_layout);
381  const base::TimeDelta start_time1;
382  const base::TimeDelta start_time2 = base::TimeDelta::FromSeconds(30);
383  const base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
384  AudioBufferQueue buffer;
385  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
386
387  // Add two buffers (second one added later):
388  //   first:  start=0s,  duration=10s
389  //   second: start=30s, duration=10s
390  buffer.Append(MakeAudioBuffer<int16>(kSampleFormatS16,
391                                       channel_layout,
392                                       channels,
393                                       kSampleRate,
394                                       1,
395                                       1,
396                                       10,
397                                       start_time1,
398                                       duration));
399  EXPECT_EQ(10, buffer.frames());
400
401  // Check starting time.
402  EXPECT_EQ(start_time1, buffer.current_time());
403
404  // Read 2 frames, should be 2s in (since duration is 1s per sample).
405  EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get()));
406  EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(2),
407            buffer.current_time());
408
409  // Skip 2 frames.
410  buffer.SeekFrames(2);
411  EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(4),
412            buffer.current_time());
413
414  // Add second buffer for more data.
415  buffer.Append(MakeAudioBuffer<int16>(kSampleFormatS16,
416                                       channel_layout,
417                                       channels,
418                                       kSampleRate,
419                                       1,
420                                       1,
421                                       10,
422                                       start_time2,
423                                       duration));
424  EXPECT_EQ(16, buffer.frames());
425
426  // Read until almost the end of buffer1.
427  EXPECT_EQ(5, buffer.ReadFrames(5, 0, bus.get()));
428  EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(9),
429            buffer.current_time());
430
431  // Read 1 value, so time moved to buffer2.
432  EXPECT_EQ(1, buffer.ReadFrames(1, 0, bus.get()));
433  EXPECT_EQ(start_time2, buffer.current_time());
434
435  // Read all 10 frames in buffer2, timestamp should be last time from buffer2.
436  EXPECT_EQ(10, buffer.ReadFrames(10, 0, bus.get()));
437  EXPECT_EQ(start_time2 + base::TimeDelta::FromSeconds(10),
438            buffer.current_time());
439
440  // Try to read more frames (which don't exist), timestamp should remain.
441  EXPECT_EQ(0, buffer.ReadFrames(5, 0, bus.get()));
442  EXPECT_EQ(start_time2 + base::TimeDelta::FromSeconds(10),
443            buffer.current_time());
444}
445
446TEST(AudioBufferQueueTest, NoTime) {
447  const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
448  const int channels = ChannelLayoutToChannelCount(channel_layout);
449  const base::TimeDelta kNoTime = kNoTimestamp();
450  AudioBufferQueue buffer;
451  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
452
453  // Add two buffers with no timestamps. Time should always be unknown.
454  buffer.Append(
455      MakeTestBuffer<int16>(kSampleFormatS16, channel_layout, 1, 1, 10));
456  buffer.Append(
457      MakeTestBuffer<int16>(kSampleFormatS16, channel_layout, 1, 1, 10));
458  EXPECT_EQ(20, buffer.frames());
459
460  // Check starting time.
461  EXPECT_EQ(kNoTime, buffer.current_time());
462
463  // Read 2 frames.
464  EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get()));
465  EXPECT_EQ(kNoTime, buffer.current_time());
466
467  // Skip 2 frames.
468  buffer.SeekFrames(2);
469  EXPECT_EQ(kNoTime, buffer.current_time());
470
471  // Read until almost the end of buffer1.
472  EXPECT_EQ(5, buffer.ReadFrames(5, 0, bus.get()));
473  EXPECT_EQ(kNoTime, buffer.current_time());
474
475  // Read 1 value, so time moved to buffer2.
476  EXPECT_EQ(1, buffer.ReadFrames(1, 0, bus.get()));
477  EXPECT_EQ(kNoTime, buffer.current_time());
478
479  // Read all 10 frames in buffer2.
480  EXPECT_EQ(10, buffer.ReadFrames(10, 0, bus.get()));
481  EXPECT_EQ(kNoTime, buffer.current_time());
482
483  // Try to read more frames (which don't exist), timestamp should remain.
484  EXPECT_EQ(0, buffer.ReadFrames(5, 0, bus.get()));
485  EXPECT_EQ(kNoTime, buffer.current_time());
486}
487
488}  // namespace media
489