| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.media; | 5 package org.chromium.media; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 8 import android.bluetooth.BluetoothAdapter; | 8 import android.bluetooth.BluetoothAdapter; |
| 9 import android.bluetooth.BluetoothManager; | 9 import android.bluetooth.BluetoothManager; |
| 10 import android.content.BroadcastReceiver; | 10 import android.content.BroadcastReceiver; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 import android.media.AudioManager; | 22 import android.media.AudioManager; |
| 23 import android.media.AudioRecord; | 23 import android.media.AudioRecord; |
| 24 import android.media.AudioTrack; | 24 import android.media.AudioTrack; |
| 25 import android.media.audiofx.AcousticEchoCanceler; | 25 import android.media.audiofx.AcousticEchoCanceler; |
| 26 import android.os.Build; | 26 import android.os.Build; |
| 27 import android.os.Handler; | 27 import android.os.Handler; |
| 28 import android.os.HandlerThread; | 28 import android.os.HandlerThread; |
| 29 import android.os.Process; | 29 import android.os.Process; |
| 30 import android.provider.Settings; | 30 import android.provider.Settings; |
| 31 | 31 |
| 32 import org.chromium.base.ContextUtils; |
| 32 import org.chromium.base.Log; | 33 import org.chromium.base.Log; |
| 33 import org.chromium.base.annotations.CalledByNative; | 34 import org.chromium.base.annotations.CalledByNative; |
| 34 import org.chromium.base.annotations.JNINamespace; | 35 import org.chromium.base.annotations.JNINamespace; |
| 35 import org.chromium.base.annotations.SuppressFBWarnings; | 36 import org.chromium.base.annotations.SuppressFBWarnings; |
| 36 | 37 |
| 37 import java.util.ArrayList; | 38 import java.util.ArrayList; |
| 38 import java.util.Arrays; | 39 import java.util.Arrays; |
| 39 import java.util.List; | 40 import java.util.List; |
| 40 import java.util.Map; | 41 import java.util.Map; |
| 41 | 42 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 private static final int STATE_BLUETOOTH_SCO_TURNING_OFF = 3; | 153 private static final int STATE_BLUETOOTH_SCO_TURNING_OFF = 3; |
| 153 | 154 |
| 154 // Use 44.1kHz as the default sampling rate. | 155 // Use 44.1kHz as the default sampling rate. |
| 155 private static final int DEFAULT_SAMPLING_RATE = 44100; | 156 private static final int DEFAULT_SAMPLING_RATE = 44100; |
| 156 // Randomly picked up frame size which is close to return value on N4. | 157 // Randomly picked up frame size which is close to return value on N4. |
| 157 // Return this value when getProperty(PROPERTY_OUTPUT_FRAMES_PER_BUFFER) | 158 // Return this value when getProperty(PROPERTY_OUTPUT_FRAMES_PER_BUFFER) |
| 158 // fails. | 159 // fails. |
| 159 private static final int DEFAULT_FRAME_PER_BUFFER = 256; | 160 private static final int DEFAULT_FRAME_PER_BUFFER = 256; |
| 160 | 161 |
| 161 private final AudioManager mAudioManager; | 162 private final AudioManager mAudioManager; |
| 162 private final Context mContext; | |
| 163 private final long mNativeAudioManagerAndroid; | 163 private final long mNativeAudioManagerAndroid; |
| 164 | 164 |
| 165 // Enabled during initialization if MODIFY_AUDIO_SETTINGS permission is | 165 // Enabled during initialization if MODIFY_AUDIO_SETTINGS permission is |
| 166 // granted. Required to shift system-wide audio settings. | 166 // granted. Required to shift system-wide audio settings. |
| 167 private boolean mHasModifyAudioSettingsPermission; | 167 private boolean mHasModifyAudioSettingsPermission; |
| 168 | 168 |
| 169 // Enabled during initialization if BLUETOOTH permission is granted. | 169 // Enabled during initialization if BLUETOOTH permission is granted. |
| 170 private boolean mHasBluetoothPermission; | 170 private boolean mHasBluetoothPermission; |
| 171 | 171 |
| 172 // Stores the audio states related to Bluetooth SCO audio, where some | 172 // Stores the audio states related to Bluetooth SCO audio, where some |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 | 212 |
| 213 // The UsbManager of this system. | 213 // The UsbManager of this system. |
| 214 private final UsbManager mUsbManager; | 214 private final UsbManager mUsbManager; |
| 215 // Broadcast receiver for USB audio devices intent broadcasts. | 215 // Broadcast receiver for USB audio devices intent broadcasts. |
| 216 // Utilized to detect if a USB device is attached or detached. | 216 // Utilized to detect if a USB device is attached or detached. |
| 217 private BroadcastReceiver mUsbAudioReceiver; | 217 private BroadcastReceiver mUsbAudioReceiver; |
| 218 | 218 |
| 219 /** Construction */ | 219 /** Construction */ |
| 220 @CalledByNative | 220 @CalledByNative |
| 221 private static AudioManagerAndroid createAudioManagerAndroid( | 221 private static AudioManagerAndroid createAudioManagerAndroid( |
| 222 Context context, | |
| 223 long nativeAudioManagerAndroid) { | 222 long nativeAudioManagerAndroid) { |
| 224 return new AudioManagerAndroid(context, nativeAudioManagerAndroid); | 223 return new AudioManagerAndroid(nativeAudioManagerAndroid); |
| 225 } | 224 } |
| 226 | 225 |
| 227 private AudioManagerAndroid(Context context, long nativeAudioManagerAndroid)
{ | 226 private AudioManagerAndroid(long nativeAudioManagerAndroid) { |
| 228 mContext = context; | |
| 229 mNativeAudioManagerAndroid = nativeAudioManagerAndroid; | 227 mNativeAudioManagerAndroid = nativeAudioManagerAndroid; |
| 230 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_S
ERVICE); | 228 mAudioManager = (AudioManager) ContextUtils.getApplicationContext().getS
ystemService( |
| 231 mContentResolver = mContext.getContentResolver(); | 229 Context.AUDIO_SERVICE); |
| 232 mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE
); | 230 mContentResolver = ContextUtils.getApplicationContext().getContentResolv
er(); |
| 231 mUsbManager = (UsbManager) ContextUtils.getApplicationContext().getSyste
mService( |
| 232 Context.USB_SERVICE); |
| 233 } | 233 } |
| 234 | 234 |
| 235 /** | 235 /** |
| 236 * Saves the initial speakerphone and microphone state. | 236 * Saves the initial speakerphone and microphone state. |
| 237 * Populates the list of available audio devices and registers receivers for
broadcasting | 237 * Populates the list of available audio devices and registers receivers for
broadcasting |
| 238 * intents related to wired headset and Bluetooth devices and USB audio devi
ces. | 238 * intents related to wired headset and Bluetooth devices and USB audio devi
ces. |
| 239 */ | 239 */ |
| 240 @CalledByNative | 240 @CalledByNative |
| 241 private void init() { | 241 private void init() { |
| 242 checkIfCalledOnValidThread(); | 242 checkIfCalledOnValidThread(); |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 channelConfig = AudioFormat.CHANNEL_OUT_STEREO; | 500 channelConfig = AudioFormat.CHANNEL_OUT_STEREO; |
| 501 } else { | 501 } else { |
| 502 return -1; | 502 return -1; |
| 503 } | 503 } |
| 504 return AudioTrack.getMinBufferSize( | 504 return AudioTrack.getMinBufferSize( |
| 505 sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT) / 2 /
channels; | 505 sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT) / 2 /
channels; |
| 506 } | 506 } |
| 507 | 507 |
| 508 @CalledByNative | 508 @CalledByNative |
| 509 private boolean isAudioLowLatencySupported() { | 509 private boolean isAudioLowLatencySupported() { |
| 510 return mContext.getPackageManager().hasSystemFeature( | 510 return ContextUtils.getApplicationContext().getPackageManager().hasSyste
mFeature( |
| 511 PackageManager.FEATURE_AUDIO_LOW_LATENCY); | 511 PackageManager.FEATURE_AUDIO_LOW_LATENCY); |
| 512 } | 512 } |
| 513 | 513 |
| 514 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) | 514 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) |
| 515 @CalledByNative | 515 @CalledByNative |
| 516 private int getAudioLowLatencyOutputFrameSize() { | 516 private int getAudioLowLatencyOutputFrameSize() { |
| 517 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { | 517 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { |
| 518 return DEFAULT_FRAME_PER_BUFFER; | 518 return DEFAULT_FRAME_PER_BUFFER; |
| 519 } | 519 } |
| 520 String framesPerBuffer = | 520 String framesPerBuffer = |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 mAudioManager.setMicrophoneMute(on); | 603 mAudioManager.setMicrophoneMute(on); |
| 604 } | 604 } |
| 605 | 605 |
| 606 /** Gets the current microphone mute state. */ | 606 /** Gets the current microphone mute state. */ |
| 607 private boolean isMicrophoneMute() { | 607 private boolean isMicrophoneMute() { |
| 608 return mAudioManager.isMicrophoneMute(); | 608 return mAudioManager.isMicrophoneMute(); |
| 609 } | 609 } |
| 610 | 610 |
| 611 /** Gets the current earpiece state. */ | 611 /** Gets the current earpiece state. */ |
| 612 private boolean hasEarpiece() { | 612 private boolean hasEarpiece() { |
| 613 return mContext.getPackageManager().hasSystemFeature( | 613 return ContextUtils.getApplicationContext().getPackageManager().hasSyste
mFeature( |
| 614 PackageManager.FEATURE_TELEPHONY); | 614 PackageManager.FEATURE_TELEPHONY); |
| 615 } | 615 } |
| 616 | 616 |
| 617 /** | 617 /** |
| 618 * Checks whether a wired headset is connected or not. | 618 * Checks whether a wired headset is connected or not. |
| 619 * This is not a valid indication that audio playback is actually over | 619 * This is not a valid indication that audio playback is actually over |
| 620 * the wired headset as audio routing depends on other conditions. We | 620 * the wired headset as audio routing depends on other conditions. We |
| 621 * only use it as an early indicator (during initialization) of an attached | 621 * only use it as an early indicator (during initialization) of an attached |
| 622 * wired headset. | 622 * wired headset. |
| 623 */ | 623 */ |
| 624 @Deprecated | 624 @Deprecated |
| 625 private boolean hasWiredHeadset() { | 625 private boolean hasWiredHeadset() { |
| 626 return mAudioManager.isWiredHeadsetOn(); | 626 return mAudioManager.isWiredHeadsetOn(); |
| 627 } | 627 } |
| 628 | 628 |
| 629 /** Checks if the process has as specified permission or not. */ | 629 /** Checks if the process has as specified permission or not. */ |
| 630 private boolean hasPermission(String permission) { | 630 private boolean hasPermission(String permission) { |
| 631 return mContext.checkPermission( | 631 return ContextUtils.getApplicationContext().checkPermission( |
| 632 permission, | 632 permission, Process.myPid(), Process.myUid()) |
| 633 Process.myPid(), | 633 == PackageManager.PERMISSION_GRANTED; |
| 634 Process.myUid()) == PackageManager.PERMISSION_GRANTED; | |
| 635 } | 634 } |
| 636 | 635 |
| 637 /** | 636 /** |
| 638 * Gets the current Bluetooth headset state. | 637 * Gets the current Bluetooth headset state. |
| 639 * android.bluetooth.BluetoothAdapter.getProfileConnectionState() requires | 638 * android.bluetooth.BluetoothAdapter.getProfileConnectionState() requires |
| 640 * the BLUETOOTH permission. | 639 * the BLUETOOTH permission. |
| 641 */ | 640 */ |
| 642 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) | 641 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) |
| 643 private boolean hasBluetoothHeadset() { | 642 private boolean hasBluetoothHeadset() { |
| 644 if (!mHasBluetoothPermission) { | 643 if (!mHasBluetoothPermission) { |
| 645 Log.w(TAG, "hasBluetoothHeadset() requires BLUETOOTH permission"); | 644 Log.w(TAG, "hasBluetoothHeadset() requires BLUETOOTH permission"); |
| 646 return false; | 645 return false; |
| 647 } | 646 } |
| 648 | 647 |
| 649 // To get a BluetoothAdapter representing the local Bluetooth adapter, | 648 // To get a BluetoothAdapter representing the local Bluetooth adapter, |
| 650 // when running on JELLY_BEAN_MR1 (4.2) and below, call the static | 649 // when running on JELLY_BEAN_MR1 (4.2) and below, call the static |
| 651 // getDefaultAdapter() method; when running on JELLY_BEAN_MR2 (4.3) and | 650 // getDefaultAdapter() method; when running on JELLY_BEAN_MR2 (4.3) and |
| 652 // higher, retrieve it through getSystemService(String) with | 651 // higher, retrieve it through getSystemService(String) with |
| 653 // BLUETOOTH_SERVICE. | 652 // BLUETOOTH_SERVICE. |
| 654 BluetoothAdapter btAdapter = null; | 653 BluetoothAdapter btAdapter = null; |
| 655 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { | 654 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { |
| 656 // Use BluetoothManager to get the BluetoothAdapter for | 655 // Use BluetoothManager to get the BluetoothAdapter for |
| 657 // Android 4.3 and above. | 656 // Android 4.3 and above. |
| 658 BluetoothManager btManager = | 657 BluetoothManager btManager = |
| 659 (BluetoothManager) mContext.getSystemService( | 658 (BluetoothManager) ContextUtils.getApplicationContext().getS
ystemService( |
| 660 Context.BLUETOOTH_SERVICE); | 659 Context.BLUETOOTH_SERVICE); |
| 661 btAdapter = btManager.getAdapter(); | 660 btAdapter = btManager.getAdapter(); |
| 662 } else { | 661 } else { |
| 663 // Use static method for Android 4.2 and below to get the | 662 // Use static method for Android 4.2 and below to get the |
| 664 // BluetoothAdapter. | 663 // BluetoothAdapter. |
| 665 btAdapter = BluetoothAdapter.getDefaultAdapter(); | 664 btAdapter = BluetoothAdapter.getDefaultAdapter(); |
| 666 } | 665 } |
| 667 | 666 |
| 668 if (btAdapter == null) { | 667 if (btAdapter == null) { |
| 669 // Bluetooth not supported on this platform. | 668 // Bluetooth not supported on this platform. |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 updateDeviceActivation(); | 776 updateDeviceActivation(); |
| 778 } else if (DEBUG) { | 777 } else if (DEBUG) { |
| 779 reportUpdate(); | 778 reportUpdate(); |
| 780 } | 779 } |
| 781 } | 780 } |
| 782 }; | 781 }; |
| 783 | 782 |
| 784 // Note: the intent we register for here is sticky, so it'll tell us | 783 // Note: the intent we register for here is sticky, so it'll tell us |
| 785 // immediately what the last action was (plugged or unplugged). | 784 // immediately what the last action was (plugged or unplugged). |
| 786 // It will enable us to set the speakerphone correctly. | 785 // It will enable us to set the speakerphone correctly. |
| 787 mContext.registerReceiver(mWiredHeadsetReceiver, filter); | 786 ContextUtils.getApplicationContext().registerReceiver(mWiredHeadsetRecei
ver, filter); |
| 788 } | 787 } |
| 789 | 788 |
| 790 /** Unregister receiver for broadcasted ACTION_HEADSET_PLUG intent. */ | 789 /** Unregister receiver for broadcasted ACTION_HEADSET_PLUG intent. */ |
| 791 private void unregisterForWiredHeadsetIntentBroadcast() { | 790 private void unregisterForWiredHeadsetIntentBroadcast() { |
| 792 mContext.unregisterReceiver(mWiredHeadsetReceiver); | 791 ContextUtils.getApplicationContext().unregisterReceiver(mWiredHeadsetRec
eiver); |
| 793 mWiredHeadsetReceiver = null; | 792 mWiredHeadsetReceiver = null; |
| 794 } | 793 } |
| 795 | 794 |
| 796 /** | 795 /** |
| 797 * Registers receiver for the broadcasted intent related to BT headset | 796 * Registers receiver for the broadcasted intent related to BT headset |
| 798 * availability or a change in connection state of the local Bluetooth | 797 * availability or a change in connection state of the local Bluetooth |
| 799 * adapter. Example: triggers when the BT device is turned on or off. | 798 * adapter. Example: triggers when the BT device is turned on or off. |
| 800 * BLUETOOTH permission is required to receive this one. | 799 * BLUETOOTH permission is required to receive this one. |
| 801 */ | 800 */ |
| 802 private void registerForBluetoothHeadsetIntentBroadcast() { | 801 private void registerForBluetoothHeadsetIntentBroadcast() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 loge("Invalid state"); | 844 loge("Invalid state"); |
| 846 break; | 845 break; |
| 847 } | 846 } |
| 848 | 847 |
| 849 if (DEBUG) { | 848 if (DEBUG) { |
| 850 reportUpdate(); | 849 reportUpdate(); |
| 851 } | 850 } |
| 852 } | 851 } |
| 853 }; | 852 }; |
| 854 | 853 |
| 855 mContext.registerReceiver(mBluetoothHeadsetReceiver, filter); | 854 ContextUtils.getApplicationContext().registerReceiver(mBluetoothHeadsetR
eceiver, filter); |
| 856 } | 855 } |
| 857 | 856 |
| 858 private void unregisterForBluetoothHeadsetIntentBroadcast() { | 857 private void unregisterForBluetoothHeadsetIntentBroadcast() { |
| 859 mContext.unregisterReceiver(mBluetoothHeadsetReceiver); | 858 ContextUtils.getApplicationContext().unregisterReceiver(mBluetoothHeadse
tReceiver); |
| 860 mBluetoothHeadsetReceiver = null; | 859 mBluetoothHeadsetReceiver = null; |
| 861 } | 860 } |
| 862 | 861 |
| 863 /** | 862 /** |
| 864 * Registers receiver for the broadcasted intent related the existence | 863 * Registers receiver for the broadcasted intent related the existence |
| 865 * of a BT SCO channel. Indicates if BT SCO streaming is on or off. | 864 * of a BT SCO channel. Indicates if BT SCO streaming is on or off. |
| 866 */ | 865 */ |
| 867 private void registerForBluetoothScoIntentBroadcast() { | 866 private void registerForBluetoothScoIntentBroadcast() { |
| 868 IntentFilter filter = new IntentFilter( | 867 IntentFilter filter = new IntentFilter( |
| 869 AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); | 868 AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 break; | 900 break; |
| 902 default: | 901 default: |
| 903 loge("Invalid state"); | 902 loge("Invalid state"); |
| 904 } | 903 } |
| 905 if (DEBUG) { | 904 if (DEBUG) { |
| 906 reportUpdate(); | 905 reportUpdate(); |
| 907 } | 906 } |
| 908 } | 907 } |
| 909 }; | 908 }; |
| 910 | 909 |
| 911 mContext.registerReceiver(mBluetoothScoReceiver, filter); | 910 ContextUtils.getApplicationContext().registerReceiver(mBluetoothScoRecei
ver, filter); |
| 912 } | 911 } |
| 913 | 912 |
| 914 private void unregisterForBluetoothScoIntentBroadcast() { | 913 private void unregisterForBluetoothScoIntentBroadcast() { |
| 915 mContext.unregisterReceiver(mBluetoothScoReceiver); | 914 ContextUtils.getApplicationContext().unregisterReceiver(mBluetoothScoRec
eiver); |
| 916 mBluetoothScoReceiver = null; | 915 mBluetoothScoReceiver = null; |
| 917 } | 916 } |
| 918 | 917 |
| 919 /** Enables BT audio using the SCO audio channel. */ | 918 /** Enables BT audio using the SCO audio channel. */ |
| 920 private void startBluetoothSco() { | 919 private void startBluetoothSco() { |
| 921 if (!mHasBluetoothPermission) { | 920 if (!mHasBluetoothPermission) { |
| 922 return; | 921 return; |
| 923 } | 922 } |
| 924 if (mBluetoothScoState == STATE_BLUETOOTH_SCO_ON | 923 if (mBluetoothScoState == STATE_BLUETOOTH_SCO_ON |
| 925 || mBluetoothScoState == STATE_BLUETOOTH_SCO_TURNING_ON) { | 924 || mBluetoothScoState == STATE_BLUETOOTH_SCO_TURNING_ON) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1236 } else if (DEBUG) { | 1235 } else if (DEBUG) { |
| 1237 reportUpdate(); | 1236 reportUpdate(); |
| 1238 } | 1237 } |
| 1239 } | 1238 } |
| 1240 }; | 1239 }; |
| 1241 | 1240 |
| 1242 IntentFilter filter = new IntentFilter(); | 1241 IntentFilter filter = new IntentFilter(); |
| 1243 filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); | 1242 filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); |
| 1244 filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); | 1243 filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); |
| 1245 | 1244 |
| 1246 mContext.registerReceiver(mUsbAudioReceiver, filter); | 1245 ContextUtils.getApplicationContext().registerReceiver(mUsbAudioReceiver,
filter); |
| 1247 } | 1246 } |
| 1248 | 1247 |
| 1249 /** Unregister receiver for broadcasted ACTION_USB_DEVICE_ATTACHED/DETACHED
intent. */ | 1248 /** Unregister receiver for broadcasted ACTION_USB_DEVICE_ATTACHED/DETACHED
intent. */ |
| 1250 private void unregisterForUsbAudioIntentBroadcast() { | 1249 private void unregisterForUsbAudioIntentBroadcast() { |
| 1251 mContext.unregisterReceiver(mUsbAudioReceiver); | 1250 ContextUtils.getApplicationContext().unregisterReceiver(mUsbAudioReceive
r); |
| 1252 mUsbAudioReceiver = null; | 1251 mUsbAudioReceiver = null; |
| 1253 } | 1252 } |
| 1254 | 1253 |
| 1255 private native void nativeSetMute(long nativeAudioManagerAndroid, boolean mu
ted); | 1254 private native void nativeSetMute(long nativeAudioManagerAndroid, boolean mu
ted); |
| 1256 } | 1255 } |
| OLD | NEW |