Bug 652475 - Add media.volume_scale pref to scale output volume without changing reported volume. r=roc
--- 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);