зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170117 - Separate volume control. r=baku
This commit is contained in:
Родитель
6412945feb
Коммит
0c8e7b7e06
|
@ -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"
|
||||
|
@ -459,47 +457,7 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
mWindows.Clear();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
#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")) {
|
||||
} else if (!strcmp(aTopic, "outer-window-destroyed")) {
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
||||
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
|
||||
|
||||
|
@ -538,9 +496,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");
|
||||
|
|
|
@ -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 uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
5, // voice call
|
||||
15, // system
|
||||
15, // ring
|
||||
|
@ -93,6 +94,47 @@ static bool sA2dpSwitchDone = true;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace gonk {
|
||||
static 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:
|
||||
|
@ -102,7 +144,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;
|
||||
|
@ -114,10 +156,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);
|
||||
}
|
||||
|
@ -151,31 +193,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;
|
||||
}
|
||||
|
||||
|
@ -303,17 +336,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());
|
||||
|
@ -322,6 +359,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);
|
||||
|
@ -387,24 +425,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");
|
||||
|
@ -439,9 +480,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.
|
||||
|
@ -471,7 +514,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];
|
||||
|
@ -479,6 +522,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 =
|
||||
|
@ -489,11 +533,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.
|
||||
|
@ -710,114 +752,204 @@ 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 < 0 || 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);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return status;
|
||||
}
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
|
||||
break;
|
||||
case AudioChannel::Notification:
|
||||
case VOLUME_NOTIFICATION:
|
||||
status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
|
||||
NS_ENSURE_SUCCESS(status, status);
|
||||
if (NS_WARN_IF(NS_FAILED(status))) {
|
||||
return 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:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
mCurrentStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
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:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
|
||||
return sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC];
|
||||
case VOLUME_NOTIFICATION:
|
||||
MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
|
||||
sMaxStreamVolumeTbl[AUDIO_STREAM_RING]);
|
||||
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:
|
||||
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:
|
||||
*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:
|
||||
*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) {
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) {
|
||||
if (aIndex < 0 || aIndex > sMaxStreamVolumeTbl[aStream]) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mCurrentStreamVolumeTbl[aStream] = aIndex;
|
||||
status_t status;
|
||||
#if ANDROID_VERSION < 17
|
||||
|
@ -826,53 +958,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;
|
||||
}
|
||||
|
@ -885,3 +1014,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 (uint32_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);
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче