Bug 652475 - Add media.volume_scale pref to scale output volume without changing reported volume. r=roc
authorChris Pearce <chris@pearce.org.nz>
Thu, 19 May 2011 09:12:25 +1200
changeset 69675 4567d5e86898e19921e508bd85e7b52eea8a48ba
parent 69674 1f3777d4ed8bae7a987e07b8a735681261a4c29b
child 69676 666ae6b488a75cf6506a455ef1269ccfada3de25
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs652475
milestone6.0a1
Bug 652475 - Add media.volume_scale pref to scale output volume without changing reported volume. r=roc
content/media/nsAudioStream.cpp
modules/libpref/src/init/all.js
--- a/content/media/nsAudioStream.cpp
+++ b/content/media/nsAudioStream.cpp
@@ -42,20 +42,23 @@
 #include "mozilla/dom/AudioChild.h"
 #include "nsXULAppAPI.h"
 using namespace mozilla::dom;
 
 #include <stdio.h>
 #include <math.h>
 #include "prlog.h"
 #include "prmem.h"
+#include "prdtoa.h"
 #include "nsAutoPtr.h"
 #include "nsAudioStream.h"
 #include "nsAlgorithm.h"
 #include "VideoUtils.h"
+#include "nsContentUtils.h"
+#include "mozilla/Mutex.h"
 extern "C" {
 #include "sydneyaudio/sydney_audio.h"
 }
 #include "mozilla/TimeStamp.h"
 #include "nsThreadUtils.h"
 
 #if defined(XP_MACOSX)
 #define SA_PER_STREAM_VOLUME 1
@@ -308,26 +311,57 @@ class AudioShutdownEvent : public nsRunn
     if (mAudioChild->IsIPCOpen())
       mAudioChild->SendShutdown();
     return NS_OK;
   }
   
   nsRefPtr<AudioChild> mAudioChild;
 };
 
+static mozilla::Mutex* gVolumeScaleLock = nsnull;
+
+static double gVolumeScale = 1.0;
+
+static int VolumeScaleChanged(const char* aPref, void *aClosure) {
+  mozilla::MutexAutoLock lock(*gVolumeScaleLock);
+  nsAdoptingString value =
+    nsContentUtils::GetStringPref("media.volume_scale");
+  if (value.IsEmpty()) {
+    gVolumeScale = 1.0;
+  } else {
+    NS_ConvertUTF16toUTF8 utf8(value);
+    gVolumeScale = PR_MAX(0, PR_strtod(utf8.get(), nsnull));
+  }
+  return 0;
+}
+
+static double GetVolumeScale() {
+  mozilla::MutexAutoLock lock(*gVolumeScaleLock);
+  return gVolumeScale;
+}
 
 void nsAudioStream::InitLibrary()
 {
 #ifdef PR_LOGGING
   gAudioStreamLog = PR_NewLogModule("nsAudioStream");
 #endif
+  gVolumeScaleLock = new mozilla::Mutex("nsAudioStream::gVolumeScaleLock");
+  VolumeScaleChanged(nsnull, nsnull);
+  nsContentUtils::RegisterPrefCallback("media.volume_scale",
+                                       VolumeScaleChanged,
+                                       nsnull);
 }
 
 void nsAudioStream::ShutdownLibrary()
 {
+  nsContentUtils::UnregisterPrefCallback("media.volume_scale",
+                                         VolumeScaleChanged,
+                                         nsnull);
+  delete gVolumeScaleLock;
+  gVolumeScaleLock = nsnull;
 }
 
 nsIThread *
 nsAudioStream::GetThread()
 {
   if (!mAudioPlaybackThread) {
     NS_NewThread(getter_AddRefs(mAudioPlaybackThread));
   }
@@ -434,41 +468,42 @@ nsresult nsAudioStreamLocal::Write(const
   nsAutoArrayPtr<short> s_data(new short[count]);
 
   if (s_data) {
     for (PRUint32 i=0; i < offset; ++i) {
       s_data[i] = mBufferOverflow.ElementAt(i);
     }
     mBufferOverflow.Clear();
 
+    double scaled_volume = GetVolumeScale() * mVolume;
     switch (mFormat) {
       case FORMAT_U8: {
         const PRUint8* buf = static_cast<const PRUint8*>(aBuf);
-        PRInt32 volume = PRInt32((1 << 16) * mVolume);
+        PRInt32 volume = PRInt32((1 << 16) * scaled_volume);
         for (PRUint32 i = 0; i < aCount; ++i) {
           s_data[i + offset] = short(((PRInt32(buf[i]) - 128) * volume) >> 8);
         }
         break;
       }
       case FORMAT_S16_LE: {
         const short* buf = static_cast<const short*>(aBuf);
-        PRInt32 volume = PRInt32((1 << 16) * mVolume);
+        PRInt32 volume = PRInt32((1 << 16) * scaled_volume);
         for (PRUint32 i = 0; i < aCount; ++i) {
           short s = buf[i];
 #if defined(IS_BIG_ENDIAN)
           s = ((s & 0x00ff) << 8) | ((s & 0xff00) >> 8);
 #endif
           s_data[i + offset] = short((PRInt32(s) * volume) >> 16);
         }
         break;
       }
       case FORMAT_FLOAT32: {
         const float* buf = static_cast<const float*>(aBuf);
         for (PRUint32 i = 0; i <  aCount; ++i) {
-          float scaled_value = floorf(0.5 + 32768 * buf[i] * mVolume);
+          float scaled_value = floorf(0.5 + 32768 * buf[i] * scaled_volume);
           if (buf[i] < 0.0) {
             s_data[i + offset] = (scaled_value < -32768.0) ?
               -32768 :
               short(scaled_value);
           } else {
             s_data[i+offset] = (scaled_value > 32767.0) ?
               32767 :
               short(scaled_value);
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -164,16 +164,19 @@ pref("browser.triple_click_selects_parag
 
 // When loading <video> or <audio>, check for Access-Control-Allow-Origin
 // header, and disallow the connection if not present or permitted.
 pref("media.enforce_same_site_origin", false);
 
 // Media cache size in kilobytes
 pref("media.cache_size", 512000);
 
+// Master HTML5 media volume scale.
+pref("media.volume_scale", "1.0");
+
 #ifdef MOZ_RAW
 pref("media.raw.enabled", true);
 #endif
 #ifdef MOZ_OGG
 pref("media.ogg.enabled", true);
 #endif
 #ifdef MOZ_WAVE
 pref("media.wave.enabled", true);