mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1183925 - Part 2: Clean up the AudioChannelService shutdown; r=baku (22c57eaadd) - Bug 1170117 - Separate volume control. r=baku (ac7560f899) - Bug 1185422 - Fix -Wtype-limits warnings-as-errors in gonk/AudioManager.cpp. r=alwu (54666877a6) - Bug 1142933 - New audio channel type for system usages. r=baku (bdb1137600)
This commit is contained in:
@@ -348,6 +348,12 @@ this.PermissionsTable = { geolocation: {
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"audio-channel-system": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"audio-channel-telephony": {
|
||||
app: DENY_ACTION,
|
||||
trusted: DENY_ACTION,
|
||||
|
||||
@@ -72,6 +72,7 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
int(AUDIO_AGENT_CHANNEL_ALARM) == int(AudioChannel::Alarm) &&
|
||||
int(AUDIO_AGENT_CHANNEL_TELEPHONY) == int(AudioChannel::Telephony) &&
|
||||
int(AUDIO_AGENT_CHANNEL_RINGER) == int(AudioChannel::Ringer) &&
|
||||
int(AUDIO_AGENT_CHANNEL_SYSTEM) == int(AudioChannel::System) &&
|
||||
int(AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION) == int(AudioChannel::Publicnotification),
|
||||
"Enum of channel on nsIAudioChannelAgent.idl should be the same with AudioChannelBinding.h");
|
||||
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
@@ -205,8 +203,7 @@ NS_IMPL_ADDREF(AudioChannelService)
|
||||
NS_IMPL_RELEASE(AudioChannelService)
|
||||
|
||||
AudioChannelService::AudioChannelService()
|
||||
: mDisabled(false)
|
||||
, mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
: mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
, mTelephonyChannel(false)
|
||||
, mContentOrNormalChannel(false)
|
||||
, mAnyChannel(false)
|
||||
@@ -236,10 +233,6 @@ void
|
||||
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
AudioChannel aChannel)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t windowID = aAgent->WindowID();
|
||||
AudioChannelWindow* winData = GetWindowData(windowID);
|
||||
if (!winData) {
|
||||
@@ -270,10 +263,6 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
void
|
||||
AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
|
||||
if (!winData) {
|
||||
return;
|
||||
@@ -463,49 +452,9 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
mDisabled = true;
|
||||
mWindows.Clear();
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// To process the volume control on each audio channel according to
|
||||
// change of settings
|
||||
else if (!strcmp(aTopic, "mozsettings-changed")) {
|
||||
RootedDictionary<SettingChangeNotification> setting(nsContentUtils::RootingCxForThread());
|
||||
if (!WrappedJSToDictionary(aSubject, setting)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!StringBeginsWith(setting.mKey, NS_LITERAL_STRING("audio.volume."))) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!setting.mValue.isNumber()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
int32_t index = setting.mValue.toNumber();
|
||||
if (setting.mKey.EqualsLiteral("audio.volume.content")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content, index);
|
||||
} else if (setting.mKey.EqualsLiteral("audio.volume.notification")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification, index);
|
||||
} else if (setting.mKey.EqualsLiteral("audio.volume.alarm")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm, index);
|
||||
} else if (setting.mKey.EqualsLiteral("audio.volume.telephony")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Telephony, index);
|
||||
} else if (!setting.mKey.EqualsLiteral("audio.volume.bt_sco")) {
|
||||
// bt_sco is not a valid audio channel so we manipulate it in
|
||||
// AudioManager.cpp. And the others should not be used.
|
||||
// We didn't use MOZ_CRASH or MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE here
|
||||
// because any web content who has permission of mozSettings can set any
|
||||
// names then it can be easy to crash the B2G.
|
||||
NS_WARNING("unexpected audio channel for volume control");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (!strcmp(aTopic, "outer-window-destroyed")) {
|
||||
Shutdown();
|
||||
} else if (!strcmp(aTopic, "outer-window-destroyed")) {
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
|
||||
|
||||
@@ -544,9 +493,7 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
mSpeakerManager[i]->SetAudioChannelActive(active);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (!strcmp(aTopic, "ipc:content-shutdown")) {
|
||||
} else if (!strcmp(aTopic, "ipc:content-shutdown")) {
|
||||
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
|
||||
if (!props) {
|
||||
NS_WARNING("ipc:content-shutdown message without property bag as subject");
|
||||
|
||||
@@ -43,11 +43,6 @@ public:
|
||||
*/
|
||||
static already_AddRefed<AudioChannelService> GetOrCreate();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
static bool IsAudioChannelMutedByDefault();
|
||||
|
||||
/**
|
||||
@@ -144,6 +139,11 @@ private:
|
||||
AudioChannelService();
|
||||
~AudioChannelService();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
void MaybeSendStatusUpdate();
|
||||
|
||||
bool ContentOrNormalChannelIsActive();
|
||||
@@ -212,8 +212,6 @@ private:
|
||||
nsTArray<SpeakerManagerService*> mSpeakerManager;
|
||||
#endif
|
||||
|
||||
bool mDisabled;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
uint64_t mDefChannelChildID;
|
||||
|
||||
@@ -34,7 +34,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
|
||||
* 1. Changes to the playable status of this channel.
|
||||
*/
|
||||
|
||||
[uuid(e28e1569-2a44-4f71-9cd0-216874b05d57)]
|
||||
[uuid(ee39a34b-a5c7-4b30-b1ac-cd64ceedef67)]
|
||||
interface nsIAudioChannelAgent : nsISupports
|
||||
{
|
||||
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
|
||||
@@ -44,6 +44,7 @@ interface nsIAudioChannelAgent : nsISupports
|
||||
const long AUDIO_AGENT_CHANNEL_TELEPHONY = 4;
|
||||
const long AUDIO_AGENT_CHANNEL_RINGER = 5;
|
||||
const long AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION = 6;
|
||||
const long AUDIO_AGENT_CHANNEL_SYSTEM = 7;
|
||||
|
||||
const long AUDIO_AGENT_CHANNEL_ERROR = 1000;
|
||||
|
||||
|
||||
@@ -181,6 +181,8 @@ cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
|
||||
return CUBEB_STREAM_TYPE_VOICE_CALL;
|
||||
case dom::AudioChannel::Ringer:
|
||||
return CUBEB_STREAM_TYPE_RING;
|
||||
case dom::AudioChannel::System:
|
||||
return CUBEB_STREAM_TYPE_SYSTEM;
|
||||
case dom::AudioChannel::Publicnotification:
|
||||
return CUBEB_STREAM_TYPE_SYSTEM_ENFORCED;
|
||||
default:
|
||||
|
||||
+377
-110
@@ -62,11 +62,12 @@ using namespace mozilla::dom::bluetooth;
|
||||
#define MOZ_SETTINGS_CHANGE_ID "mozsettings-changed"
|
||||
#define AUDIO_CHANNEL_PROCESS_CHANGED "audio-channel-process-changed"
|
||||
#define AUDIO_POLICY_SERVICE_NAME "media.audio_policy"
|
||||
#define SETTINGS_SERVICE "@mozilla.org/settingsService;1"
|
||||
|
||||
static void BinderDeadCallback(status_t aErr);
|
||||
static void InternalSetAudioRoutes(SwitchState aState);
|
||||
// Refer AudioService.java from Android
|
||||
static int sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
5, // voice call
|
||||
15, // system
|
||||
15, // ring
|
||||
@@ -89,6 +90,47 @@ static bool sA2dpSwitchDone = true;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace gonk {
|
||||
static const VolumeData gVolumeData[VOLUME_TOTAL_NUMBER] = {
|
||||
{"audio.volume.content", VOLUME_MEDIA},
|
||||
{"audio.volume.notification", VOLUME_NOTIFICATION},
|
||||
{"audio.volume.alarm", VOLUME_ALARM},
|
||||
{"audio.volume.telephony", VOLUME_TELEPHONY},
|
||||
{"audio.volume.bt_sco", VOLUME_BLUETOOTH_SCO}
|
||||
};
|
||||
|
||||
class AudioProfileData final
|
||||
{
|
||||
public:
|
||||
explicit AudioProfileData(AudioOutputProfiles aProfile)
|
||||
: mProfile(aProfile)
|
||||
, mActive(false)
|
||||
{
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
mVolumeTable.AppendElement(0);
|
||||
}
|
||||
};
|
||||
|
||||
AudioOutputProfiles GetProfile() const
|
||||
{
|
||||
return mProfile;
|
||||
}
|
||||
|
||||
void SetActive(bool aActive)
|
||||
{
|
||||
mActive = aActive;
|
||||
}
|
||||
|
||||
bool GetActive() const
|
||||
{
|
||||
return mActive;
|
||||
}
|
||||
|
||||
nsTArray<uint32_t> mVolumeTable;
|
||||
private:
|
||||
const AudioOutputProfiles mProfile;
|
||||
bool mActive;
|
||||
};
|
||||
|
||||
class RecoverTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@@ -98,7 +140,7 @@ public:
|
||||
NS_ENSURE_TRUE(amService, NS_OK);
|
||||
AudioManager *am = static_cast<AudioManager *>(amService.get());
|
||||
|
||||
int attempt;
|
||||
uint32_t attempt;
|
||||
for (attempt = 0; attempt < 50; attempt++) {
|
||||
if (defaultServiceManager()->checkService(String16(AUDIO_POLICY_SERVICE_NAME)) != 0) {
|
||||
break;
|
||||
@@ -110,10 +152,10 @@ public:
|
||||
|
||||
MOZ_RELEASE_ASSERT(attempt < 50);
|
||||
|
||||
for (int loop = 0; loop < AUDIO_STREAM_CNT; loop++) {
|
||||
for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) {
|
||||
AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0,
|
||||
sMaxStreamVolumeTbl[loop]);
|
||||
int32_t index;
|
||||
uint32_t index;
|
||||
am->GetStreamVolumeIndex(loop, &index);
|
||||
am->SetStreamVolumeIndex(loop, index);
|
||||
}
|
||||
@@ -147,31 +189,22 @@ public:
|
||||
|
||||
NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
|
||||
{
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(aResult.isInt32(), NS_OK);
|
||||
|
||||
int32_t volIndex = aResult.toInt32();
|
||||
if (aName.EqualsLiteral("audio.volume.content")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content,
|
||||
volIndex);
|
||||
} else if (aName.EqualsLiteral("audio.volume.notification")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification,
|
||||
volIndex);
|
||||
} else if (aName.EqualsLiteral("audio.volume.alarm")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm,
|
||||
volIndex);
|
||||
} else if (aName.EqualsLiteral("audio.volume.telephony")) {
|
||||
audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Telephony,
|
||||
volIndex);
|
||||
} else if (aName.EqualsLiteral("audio.volume.bt_sco")) {
|
||||
static_cast<AudioManager *>(audioManager.get())->SetStreamVolumeIndex(
|
||||
AUDIO_STREAM_BLUETOOTH_SCO, volIndex);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected audio channel for initializing "
|
||||
"volume control");
|
||||
nsRefPtr<AudioManager> audioManager = AudioManager::GetInstance();
|
||||
MOZ_ASSERT(audioManager);
|
||||
uint32_t volIndex = aResult.toInt32();
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
if (aName.EqualsASCII(gVolumeData[idx].mChannelName)) {
|
||||
uint32_t category = gVolumeData[idx].mCategory;
|
||||
nsresult rv = audioManager->ValidateVolumeIndex(category, volIndex);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
audioManager->InitProfilesVolume(gVolumeData[idx].mCategory, volIndex);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARNING("unexpected event name for initializing volume control");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -294,17 +327,21 @@ AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject,
|
||||
cmd.appendFormat("bt_samplerate=%d", kBtSampleRate);
|
||||
AudioSystem::setParameters(0, cmd);
|
||||
SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_BT_SCO);
|
||||
SwitchProfileData(DEVICE_BLUETOOTH, true);
|
||||
} else {
|
||||
int32_t force;
|
||||
GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &force);
|
||||
if (force == nsIAudioManager::FORCE_BT_SCO)
|
||||
if (force == nsIAudioManager::FORCE_BT_SCO) {
|
||||
SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE);
|
||||
}
|
||||
SwitchProfileData(DEVICE_BLUETOOTH, false);
|
||||
}
|
||||
} else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) {
|
||||
if (audioState == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE && sA2dpSwitchDone) {
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE, NewRunnableFunction(&ProcessDelayedA2dpRoute, audioState, aAddress), 1000);
|
||||
sA2dpSwitchDone = false;
|
||||
SwitchProfileData(DEVICE_BLUETOOTH, false);
|
||||
} else {
|
||||
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
|
||||
audioState, aAddress.get());
|
||||
@@ -313,6 +350,7 @@ AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject,
|
||||
cmd.setTo("A2dpSuspended=false");
|
||||
AudioSystem::setParameters(0, cmd);
|
||||
sA2dpSwitchDone = true;
|
||||
SwitchProfileData(DEVICE_BLUETOOTH, true);
|
||||
#if ANDROID_VERSION >= 17
|
||||
if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
|
||||
SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
|
||||
@@ -390,24 +428,27 @@ AudioManager::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// To process the volume control on each audio channel according to
|
||||
// To process the volume control on each volume categories according to
|
||||
// change of settings
|
||||
else if (!strcmp(aTopic, MOZ_SETTINGS_CHANGE_ID)) {
|
||||
RootedDictionary<dom::SettingChangeNotification> setting(nsContentUtils::RootingCxForThread());
|
||||
if (!WrappedJSToDictionary(aSubject, setting)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!setting.mKey.EqualsASCII("audio.volume.bt_sco")) {
|
||||
if (!StringBeginsWith(setting.mKey, NS_LITERAL_STRING("audio.volume."))) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!setting.mValue.isNumber()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t index = setting.mValue.toNumber();
|
||||
SetStreamVolumeIndex(AUDIO_STREAM_BLUETOOTH_SCO, index);
|
||||
|
||||
return NS_OK;
|
||||
uint32_t volIndex = setting.mValue.toNumber();
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
if (setting.mKey.EqualsASCII(gVolumeData[idx].mChannelName)) {
|
||||
SetVolumeByCategory(gVolumeData[idx].mCategory, volIndex);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARNING("Unexpected topic in AudioManager");
|
||||
@@ -442,9 +483,11 @@ public:
|
||||
if (aEvent.status() == SWITCH_STATE_OFF && sSwitchDone) {
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE, NewRunnableFunction(&ProcessDelayedAudioRoute, SWITCH_STATE_OFF), 1000);
|
||||
mAudioManager->SwitchProfileData(DEVICE_HEADSET, false);
|
||||
sSwitchDone = false;
|
||||
} else if (aEvent.status() != SWITCH_STATE_OFF) {
|
||||
InternalSetAudioRoutes(aEvent.status());
|
||||
mAudioManager->SwitchProfileData(DEVICE_HEADSET, true);
|
||||
sSwitchDone = true;
|
||||
}
|
||||
// Handle the coexistence of a2dp / headset device, latest one wins.
|
||||
@@ -474,7 +517,7 @@ AudioManager::AudioManager()
|
||||
InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
|
||||
NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
|
||||
|
||||
for (int loop = 0; loop < AUDIO_STREAM_CNT; loop++) {
|
||||
for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) {
|
||||
AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0,
|
||||
sMaxStreamVolumeTbl[loop]);
|
||||
mCurrentStreamVolumeTbl[loop] = sMaxStreamVolumeTbl[loop];
|
||||
@@ -482,6 +525,7 @@ AudioManager::AudioManager()
|
||||
// Force publicnotification to output at maximal volume
|
||||
SetStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE,
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_ENFORCED_AUDIBLE]);
|
||||
CreateAudioProfilesData();
|
||||
|
||||
// Get the initial volume index from settings DB during boot up.
|
||||
nsCOMPtr<nsISettingsService> settingsService =
|
||||
@@ -492,11 +536,9 @@ AudioManager::AudioManager()
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsCOMPtr<nsISettingsServiceCallback> callback = new AudioChannelVolInitCallback();
|
||||
NS_ENSURE_TRUE_VOID(callback);
|
||||
lock->Get("audio.volume.content", callback);
|
||||
lock->Get("audio.volume.notification", callback);
|
||||
lock->Get("audio.volume.alarm", callback);
|
||||
lock->Get("audio.volume.telephony", callback);
|
||||
lock->Get("audio.volume.bt_sco", callback);
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
lock->Get(gVolumeData[idx].mChannelName, callback);
|
||||
}
|
||||
|
||||
// Gecko only control stream volume not master so set to default value
|
||||
// directly.
|
||||
@@ -719,114 +761,207 @@ AudioManager::SetFmRadioAudioEnabled(bool aFmRadioAudioEnabled)
|
||||
InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
|
||||
// sync volume with music after powering on fm radio
|
||||
if (aFmRadioAudioEnabled) {
|
||||
int32_t volIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
uint32_t volIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
SetStreamVolumeIndex(AUDIO_STREAM_FM, volIndex);
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_FM] = volIndex;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::SetAudioChannelVolume(int32_t aChannel, int32_t aIndex) {
|
||||
nsresult status;
|
||||
nsresult
|
||||
AudioManager::ValidateVolumeIndex(uint32_t aCategory, uint32_t aIndex) const
|
||||
{
|
||||
uint32_t maxIndex = GetMaxVolumeByCategory(aCategory);
|
||||
if (aIndex > maxIndex) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (static_cast<AudioChannel>(aChannel)) {
|
||||
case AudioChannel::Content:
|
||||
nsresult
|
||||
AudioManager::SetVolumeByCategory(uint32_t aCategory, uint32_t aIndex)
|
||||
{
|
||||
nsresult status;
|
||||
switch (static_cast<AudioVolumeCategories>(aCategory)) {
|
||||
case VOLUME_MEDIA:
|
||||
// sync FMRadio's volume with content channel.
|
||||
if (IsDeviceOn(AUDIO_DEVICE_OUT_FM)) {
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_FM, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_MUSIC, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
break;
|
||||
case VOLUME_NOTIFICATION:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
break;
|
||||
case AudioChannel::Notification:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
case VOLUME_ALARM:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_ALARM, aIndex);
|
||||
break;
|
||||
case AudioChannel::Telephony:
|
||||
case VOLUME_TELEPHONY:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_VOICE_CALL, aIndex);
|
||||
case VOLUME_BLUETOOTH_SCO:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_BLUETOOTH_SCO, aIndex);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AudioManager::GetVolumeByCategory(uint32_t aCategory) const
|
||||
{
|
||||
switch (static_cast<AudioVolumeCategories>(aCategory)) {
|
||||
case VOLUME_MEDIA:
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
|
||||
case VOLUME_ALARM:
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_ALARM];
|
||||
case VOLUME_TELEPHONY:
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_VOICE_CALL];
|
||||
case VOLUME_BLUETOOTH_SCO:
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_BLUETOOTH_SCO];
|
||||
default:
|
||||
NS_WARNING("Can't get volume from error volume category.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AudioManager::GetMaxVolumeByCategory(uint32_t aCategory) const
|
||||
{
|
||||
switch (static_cast<AudioVolumeCategories>(aCategory)) {
|
||||
case VOLUME_MEDIA:
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
|
||||
case VOLUME_ALARM:
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_ALARM];
|
||||
case VOLUME_TELEPHONY:
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_VOICE_CALL];
|
||||
case VOLUME_BLUETOOTH_SCO:
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_BLUETOOTH_SCO];
|
||||
default:
|
||||
NS_WARNING("Can't get max volume from error volume category.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::SetAudioChannelVolume(uint32_t aChannel, uint32_t aIndex)
|
||||
{
|
||||
nsresult status;
|
||||
AudioVolumeCategories category = (mPresentProfile == DEVICE_BLUETOOTH) ?
|
||||
VOLUME_BLUETOOTH_SCO : VOLUME_TELEPHONY;
|
||||
switch (static_cast<AudioChannel>(aChannel)) {
|
||||
case AudioChannel::Normal:
|
||||
case AudioChannel::Content:
|
||||
status = SetVolumeByCategory(VOLUME_MEDIA, aIndex);
|
||||
break;
|
||||
case AudioChannel::Notification:
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
status = SetVolumeByCategory(VOLUME_NOTIFICATION, aIndex);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
status = SetVolumeByCategory(VOLUME_ALARM, aIndex);
|
||||
break;
|
||||
case AudioChannel::Telephony:
|
||||
status = SetVolumeByCategory(category, aIndex);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::GetAudioChannelVolume(int32_t aChannel, int32_t* aIndex) {
|
||||
AudioManager::GetAudioChannelVolume(uint32_t aChannel, uint32_t* aIndex)
|
||||
{
|
||||
if (!aIndex) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
AudioVolumeCategories category = (mPresentProfile == DEVICE_BLUETOOTH) ?
|
||||
VOLUME_BLUETOOTH_SCO : VOLUME_TELEPHONY;
|
||||
switch (static_cast<AudioChannel>(aChannel)) {
|
||||
case AudioChannel::Normal:
|
||||
case AudioChannel::Content:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
*aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
*aIndex = GetVolumeByCategory(VOLUME_MEDIA);
|
||||
break;
|
||||
case AudioChannel::Notification:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
*aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
*aIndex = GetVolumeByCategory(VOLUME_NOTIFICATION);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
*aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_ALARM];
|
||||
*aIndex = GetVolumeByCategory(VOLUME_ALARM);
|
||||
break;
|
||||
case AudioChannel::Telephony:
|
||||
*aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_VOICE_CALL];
|
||||
*aIndex = GetVolumeByCategory(category);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::GetMaxAudioChannelVolume(int32_t aChannel, int32_t* aMaxIndex) {
|
||||
AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex)
|
||||
{
|
||||
if (!aMaxIndex) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
int32_t stream;
|
||||
AudioVolumeCategories category = (mPresentProfile == DEVICE_BLUETOOTH) ?
|
||||
VOLUME_BLUETOOTH_SCO : VOLUME_TELEPHONY;
|
||||
switch (static_cast<AudioChannel>(aChannel)) {
|
||||
case AudioChannel::Normal:
|
||||
case AudioChannel::Content:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
stream = AUDIO_STREAM_MUSIC;
|
||||
*aMaxIndex = GetMaxVolumeByCategory(VOLUME_MEDIA);
|
||||
break;
|
||||
case AudioChannel::Notification:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
stream = AUDIO_STREAM_NOTIFICATION;
|
||||
case AudioChannel::Ringer:
|
||||
case AudioChannel::Publicnotification:
|
||||
case AudioChannel::System:
|
||||
*aMaxIndex = GetMaxVolumeByCategory(VOLUME_NOTIFICATION);
|
||||
break;
|
||||
case AudioChannel::Alarm:
|
||||
stream = AUDIO_STREAM_ALARM;
|
||||
*aMaxIndex = GetMaxVolumeByCategory(VOLUME_ALARM);
|
||||
break;
|
||||
case AudioChannel::Telephony:
|
||||
stream = AUDIO_STREAM_VOICE_CALL;
|
||||
*aMaxIndex = GetMaxVolumeByCategory(category);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aMaxIndex = sMaxStreamVolumeTbl[stream];
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
if (aIndex < 0 || aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) {
|
||||
if (aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mCurrentStreamVolumeTbl[aStream] = aIndex;
|
||||
status_t status;
|
||||
#if ANDROID_VERSION < 17
|
||||
@@ -835,53 +970,50 @@ AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
aIndex);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
#else
|
||||
int device = 0;
|
||||
|
||||
if (aStream == AUDIO_STREAM_BLUETOOTH_SCO) {
|
||||
device = AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
|
||||
} else if (aStream == AUDIO_STREAM_FM) {
|
||||
device = AUDIO_DEVICE_OUT_FM;
|
||||
}
|
||||
|
||||
if (device != 0) {
|
||||
if (aStream == AUDIO_STREAM_FM) {
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
device);
|
||||
AUDIO_DEVICE_OUT_FM);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_SPEAKER);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
if (mPresentProfile == DEVICE_PRIMARY) {
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_SPEAKER);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_EARPIECE);
|
||||
} else if (mPresentProfile == DEVICE_HEADSET) {
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_WIRED_HEADSET);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_EARPIECE);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
} else if (mPresentProfile == DEVICE_BLUETOOTH) {
|
||||
status = AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
|
||||
status += AudioSystem::setStreamVolumeIndex(
|
||||
static_cast<audio_stream_type_t>(aStream),
|
||||
aIndex,
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
|
||||
|
||||
} else {
|
||||
NS_WARNING("Can't set stream volume on error profile!");
|
||||
}
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioManager::GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex) {
|
||||
AudioManager::GetStreamVolumeIndex(int32_t aStream, uint32_t *aIndex) {
|
||||
if (!aIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@@ -894,3 +1026,138 @@ AudioManager::GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex) {
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AudioProfileData*
|
||||
AudioManager::FindAudioProfileData(AudioOutputProfiles aProfile)
|
||||
{
|
||||
uint32_t profilesNum = mAudioProfiles.Length();
|
||||
MOZ_ASSERT(profilesNum == DEVICE_TOTAL_NUMBER, "Error profile numbers!");
|
||||
for (uint32_t idx = 0; idx < profilesNum; ++idx) {
|
||||
if (mAudioProfiles[idx]->GetProfile() == aProfile) {
|
||||
return mAudioProfiles[idx];
|
||||
}
|
||||
}
|
||||
NS_WARNING("Can't find audio profile data");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::SendVolumeChangeNotification(AudioProfileData* aProfileData)
|
||||
{
|
||||
MOZ_ASSERT(aProfileData);
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISettingsService> service = do_GetService(SETTINGS_SERVICE, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISettingsServiceLock> lock;
|
||||
rv = service->CreateLock(nullptr, getter_AddRefs(lock));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send events to update the Gaia volume
|
||||
mozilla::AutoSafeJSContext cx;
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
value.setInt32(aProfileData->mVolumeTable[gVolumeData[idx].mCategory]);
|
||||
lock->Set(gVolumeData[idx].mChannelName, value, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::CreateAudioProfilesData()
|
||||
{
|
||||
MOZ_ASSERT(mAudioProfiles.IsEmpty(), "mAudioProfiles should be empty!");
|
||||
for (uint32_t idx = 0; idx < DEVICE_TOTAL_NUMBER; ++idx) {
|
||||
AudioProfileData* profile = new AudioProfileData(static_cast<AudioOutputProfiles>(idx));
|
||||
mAudioProfiles.AppendElement(profile);
|
||||
}
|
||||
UpdateProfileState(DEVICE_PRIMARY, true);
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::InitProfilesVolume(uint32_t aCategory, uint32_t aIndex)
|
||||
{
|
||||
uint32_t profilesNum = mAudioProfiles.Length();
|
||||
MOZ_ASSERT(profilesNum == DEVICE_TOTAL_NUMBER, "Error profile numbers!");
|
||||
for (uint32_t idx = 0; idx < profilesNum; ++idx) {
|
||||
mAudioProfiles[idx]->mVolumeTable[aCategory] = aIndex;
|
||||
}
|
||||
SetVolumeByCategory(aCategory, aIndex);
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::SwitchProfileData(AudioOutputProfiles aProfile,
|
||||
bool aActive)
|
||||
{
|
||||
MOZ_ASSERT(DEVICE_PRIMARY <= aProfile &&
|
||||
aProfile < DEVICE_TOTAL_NUMBER, "Error profile type!");
|
||||
|
||||
// Save the present profile volume data.
|
||||
AudioOutputProfiles oldProfile = mPresentProfile;
|
||||
AudioProfileData* profileData = FindAudioProfileData(oldProfile);
|
||||
MOZ_ASSERT(profileData);
|
||||
UpdateVolumeToProfile(profileData);
|
||||
UpdateProfileState(aProfile, aActive);
|
||||
|
||||
AudioOutputProfiles newProfile = mPresentProfile;
|
||||
if (oldProfile == newProfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update new profile volume data and send the changing event.
|
||||
profileData = FindAudioProfileData(newProfile);
|
||||
MOZ_ASSERT(profileData);
|
||||
UpdateVolumeFromProfile(profileData);
|
||||
SendVolumeChangeNotification(profileData);
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::UpdateProfileState(AudioOutputProfiles aProfile, bool aActive)
|
||||
{
|
||||
MOZ_ASSERT(DEVICE_PRIMARY <= aProfile && aProfile < DEVICE_TOTAL_NUMBER,
|
||||
"Error profile type!");
|
||||
if (aProfile == DEVICE_PRIMARY && !aActive) {
|
||||
NS_WARNING("Can't turn off the primary profile!");
|
||||
return;
|
||||
}
|
||||
|
||||
mAudioProfiles[aProfile]->SetActive(aActive);
|
||||
if (aActive) {
|
||||
mPresentProfile = aProfile;
|
||||
return;
|
||||
}
|
||||
|
||||
// The primary profile has the lowest priority. We will check whether there
|
||||
// are other profiles. The bluetooth and headset have the same priotity.
|
||||
uint32_t profilesNum = mAudioProfiles.Length();
|
||||
MOZ_ASSERT(profilesNum == DEVICE_TOTAL_NUMBER, "Error profile numbers!");
|
||||
for (int32_t idx = profilesNum - 1; idx >= 0; --idx) {
|
||||
if (mAudioProfiles[idx]->GetActive()) {
|
||||
mPresentProfile = static_cast<AudioOutputProfiles>(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::UpdateVolumeToProfile(AudioProfileData* aProfileData)
|
||||
{
|
||||
MOZ_ASSERT(aProfileData);
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
uint32_t volume = GetVolumeByCategory(gVolumeData[idx].mCategory);
|
||||
aProfileData->mVolumeTable[gVolumeData[idx].mCategory] = volume;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioManager::UpdateVolumeFromProfile(AudioProfileData* aProfileData)
|
||||
{
|
||||
MOZ_ASSERT(aProfileData);
|
||||
for (uint32_t idx = 0; idx < VOLUME_TOTAL_NUMBER; ++idx) {
|
||||
SetVolumeByCategory(gVolumeData[idx].mCategory,
|
||||
aProfileData->mVolumeTable[gVolumeData[idx].mCategory]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,47 @@ typedef Observer<SwitchEvent> SwitchObserver;
|
||||
|
||||
namespace dom {
|
||||
namespace gonk {
|
||||
|
||||
/**
|
||||
* FxOS can remeber the separate volume settings on difference output profiles.
|
||||
* (1) Primary : speaker, receiver
|
||||
* (2) Headset : wired headphone/headset
|
||||
* (3) Bluetooth : BT SCO/A2DP devices
|
||||
**/
|
||||
enum AudioOutputProfiles {
|
||||
DEVICE_PRIMARY = 0,
|
||||
DEVICE_HEADSET = 1,
|
||||
DEVICE_BLUETOOTH = 2,
|
||||
DEVICE_TOTAL_NUMBER = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* We have five sound volume settings from UX spec,
|
||||
* You can see more informations in Bug1068219.
|
||||
* (1) Media : music, video, FM ...
|
||||
* (2) Notification : ringer, notification ...
|
||||
* (3) Alarm : alarm
|
||||
* (4) Telephony : GSM call, WebRTC call
|
||||
* (5) Bluetooth SCO : SCO call
|
||||
**/
|
||||
enum AudioVolumeCategories {
|
||||
VOLUME_MEDIA = 0,
|
||||
VOLUME_NOTIFICATION = 1,
|
||||
VOLUME_ALARM = 2,
|
||||
VOLUME_TELEPHONY = 3,
|
||||
VOLUME_BLUETOOTH_SCO = 4,
|
||||
VOLUME_TOTAL_NUMBER = 5,
|
||||
};
|
||||
|
||||
struct VolumeData {
|
||||
const char* mChannelName;
|
||||
uint32_t mCategory;
|
||||
};
|
||||
|
||||
class RecoverTask;
|
||||
class AudioChannelVolInitCallback;
|
||||
class AudioProfileData;
|
||||
|
||||
class AudioManager final : public nsIAudioManager
|
||||
, public nsIObserver
|
||||
{
|
||||
@@ -53,12 +92,18 @@ public:
|
||||
friend class RecoverTask;
|
||||
friend class AudioChannelVolInitCallback;
|
||||
|
||||
// Open or close the specific profile
|
||||
void SwitchProfileData(AudioOutputProfiles aProfile, bool aActive);
|
||||
|
||||
// Validate whether the volume index is within the range
|
||||
nsresult ValidateVolumeIndex(uint32_t aCategory, uint32_t aIndex) const;
|
||||
|
||||
protected:
|
||||
int32_t mPhoneState;
|
||||
int mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT];
|
||||
uint32_t mCurrentStreamVolumeTbl[AUDIO_STREAM_CNT];
|
||||
|
||||
nsresult SetStreamVolumeIndex(int32_t aStream, int32_t aIndex);
|
||||
nsresult GetStreamVolumeIndex(int32_t aStream, int32_t *aIndex);
|
||||
nsresult SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex);
|
||||
nsresult GetStreamVolumeIndex(int32_t aStream, uint32_t *aIndex);
|
||||
|
||||
private:
|
||||
nsAutoPtr<mozilla::hal::SwitchObserver> mObserver;
|
||||
@@ -68,12 +113,38 @@ private:
|
||||
// mIsMicMuted is only used for toggling mute call to RIL.
|
||||
bool mIsMicMuted;
|
||||
#endif
|
||||
nsTArray<nsAutoPtr<AudioProfileData>> mAudioProfiles;
|
||||
AudioOutputProfiles mPresentProfile;
|
||||
|
||||
void HandleBluetoothStatusChanged(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const nsCString aAddress);
|
||||
void HandleAudioChannelProcessChanged();
|
||||
|
||||
void CreateAudioProfilesData();
|
||||
|
||||
// Init the volume setting from the init setting callback
|
||||
void InitProfilesVolume(uint32_t aCatogory, uint32_t aIndex);
|
||||
|
||||
// Update volume data of profiles
|
||||
void UpdateVolumeToProfile(AudioProfileData* aProfileData);
|
||||
|
||||
// Apply the volume data to device
|
||||
void UpdateVolumeFromProfile(AudioProfileData* aProfileData);
|
||||
|
||||
// Send the volume changing event to Gaia
|
||||
void SendVolumeChangeNotification(AudioProfileData* aProfileData);
|
||||
|
||||
// Update the mPresentProfile and profiles active status
|
||||
void UpdateProfileState(AudioOutputProfiles aProfile, bool aActive);
|
||||
|
||||
// Volume control functions
|
||||
nsresult SetVolumeByCategory(uint32_t aCategory, uint32_t aIndex);
|
||||
uint32_t GetVolumeByCategory(uint32_t aCategory) const;
|
||||
uint32_t GetMaxVolumeByCategory(uint32_t aCategory) const;
|
||||
|
||||
AudioProfileData* FindAudioProfileData(AudioOutputProfiles aProfile);
|
||||
|
||||
AudioManager();
|
||||
~AudioManager();
|
||||
};
|
||||
|
||||
@@ -239,7 +239,7 @@ typedef enum {
|
||||
|
||||
#if ANDROID_VERSION < 17
|
||||
typedef enum {
|
||||
/* output devices */
|
||||
/* output devices */
|
||||
AUDIO_DEVICE_OUT_EARPIECE = 0x1,
|
||||
AUDIO_DEVICE_OUT_SPEAKER = 0x2,
|
||||
AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4,
|
||||
@@ -299,7 +299,7 @@ typedef enum {
|
||||
AUDIO_DEVICE_IN_FM_RX = 0x20000000,
|
||||
AUDIO_DEVICE_IN_FM_RX_A2DP = 0x40000000,
|
||||
AUDIO_DEVICE_IN_DEFAULT = 0x80000000,
|
||||
|
||||
|
||||
AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION |
|
||||
AUDIO_DEVICE_IN_AMBIENT |
|
||||
AUDIO_DEVICE_IN_BUILTIN_MIC |
|
||||
@@ -550,7 +550,7 @@ typedef uint32_t audio_devices_t;
|
||||
typedef enum {
|
||||
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
|
||||
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
|
||||
|
||||
|
||||
AUDIO_POLICY_DEVICE_STATE_CNT,
|
||||
AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1,
|
||||
} audio_policy_dev_state_t;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(60da41b4-cdc2-11e2-8a91-10bf48d64bd4)]
|
||||
[scriptable, builtinclass, uuid(df31c280-1ef1-11e5-867f-0800200c9a66)]
|
||||
interface nsIAudioManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -52,8 +52,12 @@ interface nsIAudioManager : nsISupports
|
||||
void setForceForUse(in long usage, in long force);
|
||||
long getForceForUse(in long usage);
|
||||
|
||||
/* The range of volume index is from 0 to N. Ex: 0 ~ 15 */
|
||||
void setAudioChannelVolume(in long channel, in long index);
|
||||
long getAudioChannelVolume(in long channel);
|
||||
long getMaxAudioChannelVolume(in long channel);
|
||||
/**
|
||||
* These functions would be used when we enable the new volume control API
|
||||
* (mozAudioChannelManager). The range of volume index is from 0 to N.
|
||||
* More details on : https://gist.github.com/evanxd/41d8e2d91c5201a42bfa
|
||||
*/
|
||||
void setAudioChannelVolume(in unsigned long channel, in unsigned long index);
|
||||
unsigned long getAudioChannelVolume(in unsigned long channel);
|
||||
unsigned long getMaxAudioChannelVolume(in unsigned long channel);
|
||||
};
|
||||
|
||||
@@ -46,4 +46,5 @@ enum AudioChannel {
|
||||
"telephony",
|
||||
"ringer",
|
||||
"publicnotification",
|
||||
"system"
|
||||
};
|
||||
|
||||
@@ -427,8 +427,6 @@ nsLayoutStatics::Shutdown()
|
||||
nsHyphenationManager::Shutdown();
|
||||
nsDOMMutationObserver::Shutdown();
|
||||
|
||||
AudioChannelService::Shutdown();
|
||||
|
||||
DataStoreService::Shutdown();
|
||||
|
||||
ContentParent::ShutDown();
|
||||
|
||||
Reference in New Issue
Block a user