Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "CubebUtils.h"
8 :
9 : #include "MediaInfo.h"
10 : #include "mozilla/Logging.h"
11 : #include "mozilla/Preferences.h"
12 : #include "mozilla/Services.h"
13 : #include "mozilla/Sprintf.h"
14 : #include "mozilla/StaticMutex.h"
15 : #include "mozilla/StaticPtr.h"
16 : #include "mozilla/Telemetry.h"
17 : #include "nsAutoRef.h"
18 : #include "nsDebug.h"
19 : #include "nsIStringBundle.h"
20 : #include "nsString.h"
21 : #include "nsThreadUtils.h"
22 : #include "prdtoa.h"
23 : #include <algorithm>
24 : #include <stdint.h>
25 :
26 : #define PREF_VOLUME_SCALE "media.volume_scale"
27 : #define PREF_CUBEB_BACKEND "media.cubeb.backend"
28 : #define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
29 : #define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
30 : #define PREF_CUBEB_LOG_LEVEL "media.cubeb.log_level"
31 :
32 : #define MASK_MONO (1 << AudioConfig::CHANNEL_MONO)
33 : #define MASK_MONO_LFE (MASK_MONO | (1 << AudioConfig::CHANNEL_LFE))
34 : #define MASK_STEREO ((1 << AudioConfig::CHANNEL_LEFT) | (1 << AudioConfig::CHANNEL_RIGHT))
35 : #define MASK_STEREO_LFE (MASK_STEREO | (1 << AudioConfig::CHANNEL_LFE))
36 : #define MASK_3F (MASK_STEREO | (1 << AudioConfig::CHANNEL_CENTER))
37 : #define MASK_3F_LFE (MASK_3F | (1 << AudioConfig::CHANNEL_LFE))
38 : #define MASK_2F1 (MASK_STEREO | (1 << AudioConfig::CHANNEL_RCENTER))
39 : #define MASK_2F1_LFE (MASK_2F1 | (1 << AudioConfig::CHANNEL_LFE))
40 : #define MASK_3F1 (MASK_3F | (1 < AudioConfig::CHANNEL_RCENTER))
41 : #define MASK_3F1_LFE (MASK_3F1 | (1 << AudioConfig::CHANNEL_LFE))
42 : #define MASK_2F2 (MASK_STEREO | (1 << AudioConfig::CHANNEL_LS) | (1 << AudioConfig::CHANNEL_RS))
43 : #define MASK_2F2_LFE (MASK_2F2 | (1 << AudioConfig::CHANNEL_LFE))
44 : #define MASK_3F2 (MASK_3F | (1 << AudioConfig::CHANNEL_LS) | (1 << AudioConfig::CHANNEL_RS))
45 : #define MASK_3F2_LFE (MASK_3F2 | (1 << AudioConfig::CHANNEL_LFE))
46 : #define MASK_3F3R_LFE (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RCENTER))
47 : #define MASK_3F4_LFE (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RLS) | (1 << AudioConfig::CHANNEL_RRS))
48 :
49 : namespace mozilla {
50 :
51 : namespace {
52 :
53 : LazyLogModule gCubebLog("cubeb");
54 :
55 0 : void CubebLogCallback(const char* aFmt, ...)
56 : {
57 : char buffer[256];
58 :
59 : va_list arglist;
60 0 : va_start(arglist, aFmt);
61 0 : VsprintfLiteral (buffer, aFmt, arglist);
62 0 : MOZ_LOG(gCubebLog, LogLevel::Error, ("%s", buffer));
63 0 : va_end(arglist);
64 0 : }
65 :
66 : // This mutex protects the variables below.
67 3 : StaticMutex sMutex;
68 : enum class CubebState {
69 : Uninitialized = 0,
70 : Initialized,
71 : Shutdown
72 : } sCubebState = CubebState::Uninitialized;
73 : cubeb* sCubebContext;
74 : double sVolumeScale;
75 : uint32_t sCubebPlaybackLatencyInMilliseconds;
76 : uint32_t sCubebMSGLatencyInFrames;
77 : bool sCubebPlaybackLatencyPrefSet;
78 : bool sCubebMSGLatencyPrefSet;
79 : bool sAudioStreamInitEverSucceeded = false;
80 3 : StaticAutoPtr<char> sBrandName;
81 3 : StaticAutoPtr<char> sCubebBackendName;
82 :
83 : const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
84 :
85 : const char* AUDIOSTREAM_BACKEND_ID_STR[] = {
86 : "jack",
87 : "pulse",
88 : "alsa",
89 : "audiounit",
90 : "audioqueue",
91 : "wasapi",
92 : "winmm",
93 : "directsound",
94 : "sndio",
95 : "opensl",
96 : "audiotrack",
97 : "kai"
98 : };
99 : /* Index for failures to create an audio stream the first time. */
100 : const int CUBEB_BACKEND_INIT_FAILURE_FIRST =
101 : ArrayLength(AUDIOSTREAM_BACKEND_ID_STR);
102 : /* Index for failures to create an audio stream after the first time */
103 : const int CUBEB_BACKEND_INIT_FAILURE_OTHER = CUBEB_BACKEND_INIT_FAILURE_FIRST + 1;
104 : /* Index for an unknown backend. */
105 : const int CUBEB_BACKEND_UNKNOWN = CUBEB_BACKEND_INIT_FAILURE_FIRST + 2;
106 :
107 :
108 : // Prefered samplerate, in Hz (characteristic of the hardware, mixer, platform,
109 : // and API used).
110 : //
111 : // sMutex protects *initialization* of this, which must be performed from each
112 : // thread before fetching, after which it is safe to fetch without holding the
113 : // mutex because it is only written once per process execution (by the first
114 : // initialization to complete). Since the init must have been called on a
115 : // given thread before fetching the value, it's guaranteed (via the mutex) that
116 : // sufficient memory barriers have occurred to ensure the correct value is
117 : // visible on the querying thread/CPU.
118 : uint32_t sPreferredSampleRate;
119 :
120 : // We only support SMPTE layout in cubeb for now. If the value is
121 : // CUBEB_LAYOUT_UNDEFINED, then it implies that the preferred layout is
122 : // non-SMPTE format.
123 : cubeb_channel_layout sPreferredChannelLayout;
124 :
125 : } // namespace
126 :
127 : extern LazyLogModule gAudioStreamLog;
128 :
129 : static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
130 : // Consevative default that can work on all platforms.
131 : static const uint32_t CUBEB_NORMAL_LATENCY_FRAMES = 1024;
132 :
133 : namespace CubebUtils {
134 :
135 15 : void PrefChanged(const char* aPref, void* aClosure)
136 : {
137 15 : if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
138 6 : nsAdoptingString value = Preferences::GetString(aPref);
139 6 : StaticMutexAutoLock lock(sMutex);
140 3 : if (value.IsEmpty()) {
141 0 : sVolumeScale = 1.0;
142 : } else {
143 6 : NS_ConvertUTF16toUTF8 utf8(value);
144 3 : sVolumeScale = std::max<double>(0, PR_strtod(utf8.get(), nullptr));
145 : }
146 12 : } else if (strcmp(aPref, PREF_CUBEB_LATENCY_PLAYBACK) == 0) {
147 : // Arbitrary default stream latency of 100ms. The higher this
148 : // value, the longer stream volume changes will take to become
149 : // audible.
150 3 : sCubebPlaybackLatencyPrefSet = Preferences::HasUserValue(aPref);
151 3 : uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
152 6 : StaticMutexAutoLock lock(sMutex);
153 3 : sCubebPlaybackLatencyInMilliseconds = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
154 9 : } else if (strcmp(aPref, PREF_CUBEB_LATENCY_MSG) == 0) {
155 3 : sCubebMSGLatencyPrefSet = Preferences::HasUserValue(aPref);
156 3 : uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_FRAMES);
157 6 : StaticMutexAutoLock lock(sMutex);
158 : // 128 is the block size for the Web Audio API, which limits how low the
159 : // latency can be here.
160 : // We don't want to limit the upper limit too much, so that people can
161 : // experiment.
162 3 : sCubebMSGLatencyInFrames = std::min<uint32_t>(std::max<uint32_t>(value, 128), 1e6);
163 6 : } else if (strcmp(aPref, PREF_CUBEB_LOG_LEVEL) == 0) {
164 6 : nsAdoptingString value = Preferences::GetString(aPref);
165 6 : NS_ConvertUTF16toUTF8 utf8(value);
166 3 : LogModule* cubebLog = LogModule::Get("cubeb");
167 3 : if (strcmp(utf8.get(), "verbose") == 0) {
168 0 : cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
169 0 : cubebLog->SetLevel(LogLevel::Verbose);
170 3 : } else if (strcmp(utf8.get(), "normal") == 0) {
171 0 : cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
172 0 : cubebLog->SetLevel(LogLevel::Error);
173 3 : } else if (utf8.IsEmpty()) {
174 3 : cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
175 3 : cubebLog->SetLevel(LogLevel::Disabled);
176 : }
177 3 : } else if (strcmp(aPref, PREF_CUBEB_BACKEND) == 0) {
178 6 : nsAdoptingString value = Preferences::GetString(aPref);
179 3 : if (value.IsEmpty()) {
180 3 : sCubebBackendName = nullptr;
181 : } else {
182 0 : NS_LossyConvertUTF16toASCII ascii(value);
183 0 : sCubebBackendName = new char[ascii.Length() + 1];
184 0 : PodCopy(sCubebBackendName.get(), ascii.get(), ascii.Length());
185 0 : sCubebBackendName[ascii.Length()] = 0;
186 : }
187 : }
188 15 : }
189 :
190 0 : bool GetFirstStream()
191 : {
192 : static bool sFirstStream = true;
193 :
194 0 : StaticMutexAutoLock lock(sMutex);
195 0 : bool result = sFirstStream;
196 0 : sFirstStream = false;
197 0 : return result;
198 : }
199 :
200 0 : double GetVolumeScale()
201 : {
202 0 : StaticMutexAutoLock lock(sMutex);
203 0 : return sVolumeScale;
204 : }
205 :
206 0 : cubeb* GetCubebContext()
207 : {
208 0 : StaticMutexAutoLock lock(sMutex);
209 0 : return GetCubebContextUnlocked();
210 : }
211 :
212 0 : bool InitPreferredSampleRate()
213 : {
214 0 : StaticMutexAutoLock lock(sMutex);
215 0 : if (sPreferredSampleRate != 0) {
216 0 : return true;
217 : }
218 0 : cubeb* context = GetCubebContextUnlocked();
219 0 : if (!context) {
220 0 : return false;
221 : }
222 0 : if (cubeb_get_preferred_sample_rate(context,
223 : &sPreferredSampleRate) != CUBEB_OK) {
224 :
225 0 : return false;
226 : }
227 0 : MOZ_ASSERT(sPreferredSampleRate);
228 0 : return true;
229 : }
230 :
231 0 : uint32_t PreferredSampleRate()
232 : {
233 0 : if (!InitPreferredSampleRate()) {
234 0 : return 44100;
235 : }
236 0 : MOZ_ASSERT(sPreferredSampleRate);
237 0 : return sPreferredSampleRate;
238 : }
239 :
240 0 : bool InitPreferredChannelLayout()
241 : {
242 : {
243 0 : StaticMutexAutoLock lock(sMutex);
244 0 : if (sPreferredChannelLayout != 0) {
245 0 : return true;
246 : }
247 : }
248 :
249 0 : cubeb* context = GetCubebContext();
250 0 : if (!context) {
251 0 : return false;
252 : }
253 :
254 : // Favor calling cubeb api with the mutex unlock, potential deadlock.
255 : cubeb_channel_layout layout;
256 0 : if (cubeb_get_preferred_channel_layout(context, &layout) != CUBEB_OK) {
257 0 : return false;
258 : }
259 :
260 0 : StaticMutexAutoLock lock(sMutex);
261 0 : sPreferredChannelLayout = layout;
262 0 : return true;
263 : }
264 :
265 0 : uint32_t PreferredChannelMap(uint32_t aChannels)
266 : {
267 : // The first element of the following mapping table is channel counts,
268 : // and the second one is its bit mask. It will be used in many times,
269 : // so we shoule avoid to allocate it in stack, or it will be created
270 : // and removed repeatedly. Use static to allocate this local variable
271 : // in data space instead of stack.
272 : static uint32_t layoutInfo[CUBEB_LAYOUT_MAX][2] = {
273 : { 0, 0 }, // CUBEB_LAYOUT_UNDEFINED
274 : { 2, MASK_STEREO }, // CUBEB_LAYOUT_DUAL_MONO
275 : { 3, MASK_STEREO_LFE }, // CUBEB_LAYOUT_DUAL_MONO_LFE
276 : { 1, MASK_MONO }, // CUBEB_LAYOUT_MONO
277 : { 2, MASK_MONO_LFE }, // CUBEB_LAYOUT_MONO_LFE
278 : { 2, MASK_STEREO }, // CUBEB_LAYOUT_STEREO
279 : { 3, MASK_STEREO_LFE }, // CUBEB_LAYOUT_STEREO_LFE
280 : { 3, MASK_3F }, // CUBEB_LAYOUT_3F
281 : { 4, MASK_3F_LFE }, // CUBEB_LAYOUT_3F_LFE
282 : { 3, MASK_2F1 }, // CUBEB_LAYOUT_2F1
283 : { 4, MASK_2F1_LFE }, // CUBEB_LAYOUT_2F1_LFE
284 : { 4, MASK_3F1 }, // CUBEB_LAYOUT_3F1
285 : { 5, MASK_3F1_LFE }, // CUBEB_LAYOUT_3F1_LFE
286 : { 4, MASK_2F2 }, // CUBEB_LAYOUT_2F2
287 : { 5, MASK_2F2_LFE }, // CUBEB_LAYOUT_2F2_LFE
288 : { 5, MASK_3F2 }, // CUBEB_LAYOUT_3F2
289 : { 6, MASK_3F2_LFE }, // CUBEB_LAYOUT_3F2_LFE
290 : { 7, MASK_3F3R_LFE }, // CUBEB_LAYOUT_3F3R_LFE
291 : { 8, MASK_3F4_LFE }, // CUBEB_LAYOUT_3F4_LFE
292 : };
293 :
294 : // Use SMPTE default channel map if we can't get preferred layout
295 : // or the channel counts of preferred layout is different from input's one
296 0 : if (!InitPreferredChannelLayout()
297 0 : || layoutInfo[sPreferredChannelLayout][0] != aChannels) {
298 0 : AudioConfig::ChannelLayout smpteLayout(aChannels);
299 0 : return smpteLayout.Map();
300 : }
301 :
302 0 : return layoutInfo[sPreferredChannelLayout][1];
303 : }
304 :
305 3 : void InitBrandName()
306 : {
307 3 : if (sBrandName) {
308 0 : return;
309 : }
310 6 : nsXPIDLString brandName;
311 : nsCOMPtr<nsIStringBundleService> stringBundleService =
312 6 : mozilla::services::GetStringBundleService();
313 3 : if (stringBundleService) {
314 6 : nsCOMPtr<nsIStringBundle> brandBundle;
315 6 : nsresult rv = stringBundleService->CreateBundle(kBrandBundleURL,
316 6 : getter_AddRefs(brandBundle));
317 3 : if (NS_SUCCEEDED(rv)) {
318 6 : rv = brandBundle->GetStringFromName(u"brandShortName",
319 6 : getter_Copies(brandName));
320 3 : NS_WARNING_ASSERTION(
321 : NS_SUCCEEDED(rv), "Could not get the program name for a cubeb stream.");
322 : }
323 : }
324 6 : NS_LossyConvertUTF16toASCII ascii(brandName);
325 6 : sBrandName = new char[ascii.Length() + 1];
326 3 : PodCopy(sBrandName.get(), ascii.get(), ascii.Length());
327 3 : sBrandName[ascii.Length()] = 0;
328 : }
329 :
330 0 : cubeb* GetCubebContextUnlocked()
331 : {
332 0 : sMutex.AssertCurrentThreadOwns();
333 0 : if (sCubebState != CubebState::Uninitialized) {
334 : // If we have already passed the initialization point (below), just return
335 : // the current context, which may be null (e.g., after error or shutdown.)
336 0 : return sCubebContext;
337 : }
338 :
339 0 : if (!sBrandName && NS_IsMainThread()) {
340 0 : InitBrandName();
341 : } else {
342 0 : NS_WARNING_ASSERTION(
343 : sBrandName, "Did not initialize sbrandName, and not on the main thread?");
344 : }
345 :
346 0 : int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
347 0 : NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
348 0 : sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
349 :
350 0 : if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
351 0 : cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
352 0 : } else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
353 0 : cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
354 : }
355 :
356 0 : return sCubebContext;
357 : }
358 :
359 0 : void ReportCubebBackendUsed()
360 : {
361 0 : StaticMutexAutoLock lock(sMutex);
362 :
363 0 : sAudioStreamInitEverSucceeded = true;
364 :
365 0 : bool foundBackend = false;
366 0 : for (uint32_t i = 0; i < ArrayLength(AUDIOSTREAM_BACKEND_ID_STR); i++) {
367 0 : if (!strcmp(cubeb_get_backend_id(sCubebContext), AUDIOSTREAM_BACKEND_ID_STR[i])) {
368 0 : Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED, i);
369 0 : foundBackend = true;
370 : }
371 : }
372 0 : if (!foundBackend) {
373 : Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED,
374 0 : CUBEB_BACKEND_UNKNOWN);
375 : }
376 0 : }
377 :
378 0 : void ReportCubebStreamInitFailure(bool aIsFirst)
379 : {
380 0 : StaticMutexAutoLock lock(sMutex);
381 0 : if (!aIsFirst && !sAudioStreamInitEverSucceeded) {
382 : // This machine has no audio hardware, or it's in really bad shape, don't
383 : // send this info, since we want CUBEB_BACKEND_INIT_FAILURE_OTHER to detect
384 : // failures to open multiple streams in a process over time.
385 0 : return;
386 : }
387 0 : Telemetry::Accumulate(Telemetry::AUDIOSTREAM_BACKEND_USED,
388 : aIsFirst ? CUBEB_BACKEND_INIT_FAILURE_FIRST
389 0 : : CUBEB_BACKEND_INIT_FAILURE_OTHER);
390 : }
391 :
392 0 : uint32_t GetCubebPlaybackLatencyInMilliseconds()
393 : {
394 0 : StaticMutexAutoLock lock(sMutex);
395 0 : return sCubebPlaybackLatencyInMilliseconds;
396 : }
397 :
398 0 : bool CubebPlaybackLatencyPrefSet()
399 : {
400 0 : StaticMutexAutoLock lock(sMutex);
401 0 : return sCubebPlaybackLatencyPrefSet;
402 : }
403 :
404 0 : bool CubebMSGLatencyPrefSet()
405 : {
406 0 : StaticMutexAutoLock lock(sMutex);
407 0 : return sCubebMSGLatencyPrefSet;
408 : }
409 :
410 0 : Maybe<uint32_t> GetCubebMSGLatencyInFrames()
411 : {
412 0 : StaticMutexAutoLock lock(sMutex);
413 0 : if (!sCubebMSGLatencyPrefSet) {
414 0 : return Maybe<uint32_t>();
415 : }
416 0 : MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
417 0 : return Some(sCubebMSGLatencyInFrames);
418 : }
419 :
420 3 : void InitLibrary()
421 : {
422 3 : Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
423 3 : Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
424 3 : Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
425 3 : Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
426 3 : Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LOG_LEVEL);
427 : #ifndef MOZ_WIDGET_ANDROID
428 6 : NS_DispatchToMainThread(
429 9 : NS_NewRunnableFunction("CubebUtils::InitLibrary", &InitBrandName));
430 : #endif
431 3 : }
432 :
433 0 : void ShutdownLibrary()
434 : {
435 0 : Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
436 0 : Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
437 0 : Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
438 0 : Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
439 0 : Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOG_LEVEL);
440 :
441 0 : StaticMutexAutoLock lock(sMutex);
442 0 : if (sCubebContext) {
443 0 : cubeb_destroy(sCubebContext);
444 0 : sCubebContext = nullptr;
445 : }
446 0 : sBrandName = nullptr;
447 0 : sCubebBackendName = nullptr;
448 : // This will ensure we don't try to re-create a context.
449 0 : sCubebState = CubebState::Shutdown;
450 0 : }
451 :
452 0 : uint32_t MaxNumberOfChannels()
453 : {
454 0 : cubeb* cubebContext = GetCubebContext();
455 : uint32_t maxNumberOfChannels;
456 0 : if (cubebContext &&
457 0 : cubeb_get_max_channel_count(cubebContext,
458 : &maxNumberOfChannels) == CUBEB_OK) {
459 0 : return maxNumberOfChannels;
460 : }
461 :
462 0 : return 0;
463 : }
464 :
465 0 : cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap)
466 : {
467 0 : switch(aChannelMap) {
468 0 : case MASK_MONO: return CUBEB_LAYOUT_MONO;
469 0 : case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
470 0 : case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
471 0 : case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
472 0 : case MASK_3F: return CUBEB_LAYOUT_3F;
473 0 : case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
474 0 : case MASK_2F1: return CUBEB_LAYOUT_2F1;
475 0 : case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
476 0 : case MASK_3F1: return CUBEB_LAYOUT_3F1;
477 0 : case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
478 0 : case MASK_2F2: return CUBEB_LAYOUT_2F2;
479 0 : case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
480 0 : case MASK_3F2: return CUBEB_LAYOUT_3F2;
481 0 : case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
482 0 : case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
483 0 : case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
484 : default:
485 0 : NS_ERROR("The channel map is unsupported");
486 0 : return CUBEB_LAYOUT_UNDEFINED;
487 : }
488 : }
489 :
490 : #if defined(__ANDROID__) && defined(MOZ_B2G)
491 : cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
492 : {
493 : switch(aChannel) {
494 : case dom::AudioChannel::Normal:
495 : /* FALLTHROUGH */
496 : case dom::AudioChannel::Content:
497 : return CUBEB_STREAM_TYPE_MUSIC;
498 : case dom::AudioChannel::Notification:
499 : return CUBEB_STREAM_TYPE_NOTIFICATION;
500 : case dom::AudioChannel::Alarm:
501 : return CUBEB_STREAM_TYPE_ALARM;
502 : case dom::AudioChannel::Telephony:
503 : return CUBEB_STREAM_TYPE_VOICE_CALL;
504 : case dom::AudioChannel::Ringer:
505 : return CUBEB_STREAM_TYPE_RING;
506 : case dom::AudioChannel::System:
507 : return CUBEB_STREAM_TYPE_SYSTEM;
508 : case dom::AudioChannel::Publicnotification:
509 : return CUBEB_STREAM_TYPE_SYSTEM_ENFORCED;
510 : default:
511 : NS_ERROR("The value of AudioChannel is invalid");
512 : return CUBEB_STREAM_TYPE_MAX;
513 : }
514 : }
515 : #endif
516 :
517 0 : void GetCurrentBackend(nsAString& aBackend)
518 : {
519 0 : cubeb* cubebContext = GetCubebContext();
520 0 : if (cubebContext) {
521 0 : const char* backend = cubeb_get_backend_id(cubebContext);
522 0 : if (backend) {
523 0 : aBackend.AssignASCII(backend);
524 0 : return;
525 : }
526 : }
527 0 : aBackend.AssignLiteral("unknown");
528 : }
529 :
530 : } // namespace CubebUtils
531 : } // namespace mozilla
|