summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-09 20:25:53 +0000
committerhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-09 20:25:53 +0000
commit31d88a3e4311c9f075e0e24e186fa17d165feb75 (patch)
tree4fc8f7b322141d18904c575bfbb0f0dcc45a57c3 /media
parent28156413fcc8f1cee2fcd258a0370ce98f4c34b4 (diff)
downloadchromium_src-31d88a3e4311c9f075e0e24e186fa17d165feb75.zip
chromium_src-31d88a3e4311c9f075e0e24e186fa17d165feb75.tar.gz
chromium_src-31d88a3e4311c9f075e0e24e186fa17d165feb75.tar.bz2
Improves audio support for case when process lacks MODIFY_AUDIO_SETTINGS and/or RECORD_AUDIO permission.
This CL ensures that a process can use the AudioManager for Android without MODIFY_AUDIO_SETTINGS and RECORD_AUDIO permissions without crashing. logcat warnings are added and getAudioInputDeviceNames() and setDevice() APIs are disabled unless we hold both permissions. As a result, no input streams can be created. Output streams can still be created, hence WebAudio should not be affected. To summarize: AudioManager for Android will still work without all required permissions but with a limited functionality. BUG=NONE TEST=WebRTC demos (e.g. apprtc.com) with missing permissions. Review URL: https://codereview.chromium.org/305483004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275850 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/audio/android/audio_manager_android.cc5
-rw-r--r--media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java87
2 files changed, 70 insertions, 22 deletions
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
index 733ece6..48f203a 100644
--- a/media/audio/android/audio_manager_android.cc
+++ b/media/audio/android/audio_manager_android.cc
@@ -90,6 +90,11 @@ void AudioManagerAndroid::GetAudioInputDeviceNames(
ScopedJavaLocalRef<jobjectArray> j_device_array =
Java_AudioManagerAndroid_getAudioInputDeviceNames(
env, j_audio_manager_.obj());
+ if (j_device_array.is_null()) {
+ // Most probable reason for a NULL result here is that the process lacks
+ // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions.
+ return;
+ }
jsize len = env->GetArrayLength(j_device_array.obj());
AudioDeviceName device;
for (jsize i = 0; i < len; ++i) {
diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
index e675883..85baad0 100644
--- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
@@ -163,6 +163,13 @@ class AudioManagerAndroid {
private final Context mContext;
private final long mNativeAudioManagerAndroid;
+ // Enabled during initialization if MODIFY_AUDIO_SETTINGS permission is
+ // granted. Required to shift system-wide audio settings.
+ private boolean mHasModifyAudioSettingsPermission = false;
+
+ // Enabled during initialization if RECORD_AUDIO permission is granted.
+ private boolean mHasRecordAudioPermission = false;
+
// Enabled during initialization if BLUETOOTH permission is granted.
private boolean mHasBluetoothPermission = false;
@@ -237,6 +244,19 @@ class AudioManagerAndroid {
if (mIsInitialized)
return;
+ // Check if process has MODIFY_AUDIO_SETTINGS and RECORD_AUDIO
+ // permissions. Both are required for full functionality.
+ mHasModifyAudioSettingsPermission = hasPermission(
+ android.Manifest.permission.MODIFY_AUDIO_SETTINGS);
+ if (DEBUG && !mHasModifyAudioSettingsPermission) {
+ logd("MODIFY_AUDIO_SETTINGS permission is missing");
+ }
+ mHasRecordAudioPermission = hasPermission(
+ android.Manifest.permission.RECORD_AUDIO);
+ if (DEBUG && !mHasRecordAudioPermission) {
+ logd("RECORD_AUDIO permission is missing");
+ }
+
// Initialize audio device list with things we know is always available.
mAudioDevices[DEVICE_EARPIECE] = hasEarpiece();
mAudioDevices[DEVICE_WIRED_HEADSET] = hasWiredHeadset();
@@ -277,14 +297,23 @@ class AudioManagerAndroid {
* Saves current audio mode and sets audio mode to MODE_IN_COMMUNICATION
* if input parameter is true. Restores saved audio mode if input parameter
* is false.
+ * Required permission: android.Manifest.permission.MODIFY_AUDIO_SETTINGS.
*/
@CalledByNative
private void setCommunicationAudioModeOn(boolean on) {
if (DEBUG) logd("setCommunicationAudioModeOn(" + on + ")");
+ // The MODIFY_AUDIO_SETTINGS permission is required to allow an
+ // application to modify global audio settings.
+ if (!mHasModifyAudioSettingsPermission) {
+ Log.w(TAG, "MODIFY_AUDIO_SETTINGS is missing => client will run " +
+ "with reduced functionality");
+ return;
+ }
+
if (on) {
if (mSavedAudioMode != AudioManager.MODE_INVALID) {
- Log.wtf(TAG, "Audio mode has already been set!");
+ Log.wtf(TAG, "Audio mode has already been set");
return;
}
@@ -318,7 +347,7 @@ class AudioManagerAndroid {
} else {
if (mSavedAudioMode == AudioManager.MODE_INVALID) {
- Log.wtf(TAG, "Audio mode has not yet been set!");
+ Log.wtf(TAG, "Audio mode has not yet been set");
return;
}
@@ -346,12 +375,20 @@ class AudioManagerAndroid {
* @param deviceId Unique device ID (integer converted to string)
* representing the selected device. This string is empty if the so-called
* default device is requested.
+ * Required permissions: android.Manifest.permission.MODIFY_AUDIO_SETTINGS
+ * and android.Manifest.permission.RECORD_AUDIO.
*/
@CalledByNative
private boolean setDevice(String deviceId) {
if (DEBUG) logd("setDevice: " + deviceId);
if (!mIsInitialized)
return false;
+ if (!mHasModifyAudioSettingsPermission || !mHasRecordAudioPermission) {
+ Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO");
+ Log.w(TAG, "Selected device will not be available for recording");
+ return false;
+ }
+
int intDeviceId = deviceId.isEmpty() ?
DEVICE_DEFAULT : Integer.parseInt(deviceId);
@@ -383,12 +420,20 @@ class AudioManagerAndroid {
* @return the current list of available audio devices.
* Note that this call does not trigger any update of the list of devices,
* it only copies the current state in to the output array.
+ * Required permissions: android.Manifest.permission.MODIFY_AUDIO_SETTINGS
+ * and android.Manifest.permission.RECORD_AUDIO.
*/
@CalledByNative
private AudioDeviceName[] getAudioInputDeviceNames() {
if (DEBUG) logd("getAudioInputDeviceNames");
if (!mIsInitialized)
return null;
+ if (!mHasModifyAudioSettingsPermission || !mHasRecordAudioPermission) {
+ Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO");
+ Log.w(TAG, "No audio device will be available for recording");
+ return null;
+ }
+
boolean devices[] = null;
synchronized (mLock) {
devices = mAudioDevices.clone();
@@ -501,7 +546,7 @@ class AudioManagerAndroid {
*/
private void checkIfCalledOnValidThread() {
if (DEBUG && !mNonThreadSafe.calledOnValidThread()) {
- Log.wtf(TAG, "Method is not called on valid thread!");
+ Log.wtf(TAG, "Method is not called on valid thread");
}
}
@@ -511,7 +556,8 @@ class AudioManagerAndroid {
*/
private void registerBluetoothIntentsIfNeeded() {
// Check if this process has the BLUETOOTH permission or not.
- mHasBluetoothPermission = hasBluetoothPermission();
+ mHasBluetoothPermission = hasPermission(
+ android.Manifest.permission.BLUETOOTH);
// Add a Bluetooth headset to the list of available devices if a BT
// headset is detected and if we have the BLUETOOTH permission.
@@ -520,6 +566,7 @@ class AudioManagerAndroid {
// is not sticky and will only be received if a BT headset is connected
// after this method has been called.
if (!mHasBluetoothPermission) {
+ Log.w(TAG, "Requires BLUETOOTH permission");
return;
}
mAudioDevices[DEVICE_BLUETOOTH_HEADSET] = hasBluetoothHeadset();
@@ -580,16 +627,12 @@ class AudioManagerAndroid {
return mAudioManager.isWiredHeadsetOn();
}
- /** Checks if the process has BLUETOOTH permission or not. */
- private boolean hasBluetoothPermission() {
- boolean hasBluetooth = mContext.checkPermission(
- android.Manifest.permission.BLUETOOTH,
- Process.myPid(),
- Process.myUid()) == PackageManager.PERMISSION_GRANTED;
- if (DEBUG && !hasBluetooth) {
- logd("BLUETOOTH permission is missing!");
- }
- return hasBluetooth;
+ /** Checks if the process has as specified permission or not. */
+ private boolean hasPermission(String permission) {
+ return mContext.checkPermission(
+ permission,
+ Process.myPid(),
+ Process.myUid()) == PackageManager.PERMISSION_GRANTED;
}
/**
@@ -599,7 +642,7 @@ class AudioManagerAndroid {
*/
private boolean hasBluetoothHeadset() {
if (!mHasBluetoothPermission) {
- Log.wtf(TAG, "hasBluetoothHeadset() requires BLUETOOTH permission!");
+ Log.w(TAG, "hasBluetoothHeadset() requires BLUETOOTH permission");
return false;
}
@@ -695,7 +738,7 @@ class AudioManagerAndroid {
}
break;
default:
- loge("Invalid state!");
+ loge("Invalid state");
break;
}
@@ -770,7 +813,7 @@ class AudioManagerAndroid {
// Bluetooth service is switching from on to off.
break;
default:
- loge("Invalid state!");
+ loge("Invalid state");
break;
}
@@ -824,7 +867,7 @@ class AudioManagerAndroid {
// do nothing
break;
default:
- loge("Invalid state!");
+ loge("Invalid state");
}
if (DEBUG) {
reportUpdate();
@@ -875,7 +918,7 @@ class AudioManagerAndroid {
}
if (!mAudioManager.isBluetoothScoOn()) {
// TODO(henrika): can we do anything else than logging here?
- loge("Unable to stop BT SCO since it is already disabled!");
+ loge("Unable to stop BT SCO since it is already disabled");
return;
}
@@ -913,7 +956,7 @@ class AudioManagerAndroid {
setSpeakerphoneOn(false);
break;
default:
- loge("Invalid audio device selection!");
+ loge("Invalid audio device selection");
break;
}
reportUpdate();
@@ -955,7 +998,7 @@ class AudioManagerAndroid {
devices = mAudioDevices.clone();
}
if (requested == DEVICE_INVALID) {
- loge("Unable to activate device since no device is selected!");
+ loge("Unable to activate device since no device is selected");
return;
}
@@ -1045,7 +1088,7 @@ class AudioManagerAndroid {
// Ensure that the observer is activated during communication mode.
if (mAudioManager.getMode() != AudioManager.MODE_IN_COMMUNICATION) {
- Log.wtf(TAG, "Only enable SettingsObserver in COMM mode!");
+ Log.wtf(TAG, "Only enable SettingsObserver in COMM mode");
return;
}