LCOV - code coverage report
Current view: top level - dom/media - CubebUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 59 215 27.4 %
Date: 2017-07-14 16:53:18 Functions: 3 22 13.6 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13