OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 | 77 |
78 // This method is called when the proximity sensor reports a state change, | 78 // This method is called when the proximity sensor reports a state change, |
79 // e.g. from "NEAR to FAR" or from "FAR to NEAR". | 79 // e.g. from "NEAR to FAR" or from "FAR to NEAR". |
80 private void onProximitySensorChangedState() { | 80 private void onProximitySensorChangedState() { |
81 if (!useSpeakerphone.equals(SPEAKERPHONE_AUTO)) { | 81 if (!useSpeakerphone.equals(SPEAKERPHONE_AUTO)) { |
82 return; | 82 return; |
83 } | 83 } |
84 | 84 |
85 // The proximity sensor should only be activated when there are exactly two | 85 // The proximity sensor should only be activated when there are exactly two |
86 // available audio devices. | 86 // available audio devices. |
87 if (audioDevices.size() == 2 | 87 if (audioDevices.size() == 2 && audioDevices.contains(AppRTCAudioManager.Aud
ioDevice.EARPIECE) |
88 && audioDevices.contains(AppRTCAudioManager.AudioDevice.EARPIECE) | 88 && audioDevices.contains(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE))
{ |
89 && audioDevices.contains( | |
90 AppRTCAudioManager.AudioDevice.SPEAKER_PHONE)) { | |
91 if (proximitySensor.sensorReportsNearState()) { | 89 if (proximitySensor.sensorReportsNearState()) { |
92 // Sensor reports that a "handset is being held up to a person's ear", | 90 // Sensor reports that a "handset is being held up to a person's ear", |
93 // or "something is covering the light sensor". | 91 // or "something is covering the light sensor". |
94 setAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE); | 92 setAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE); |
95 } else { | 93 } else { |
96 // Sensor reports that a "handset is removed from a person's ear", or | 94 // Sensor reports that a "handset is removed from a person's ear", or |
97 // "the light sensor is no longer covered". | 95 // "the light sensor is no longer covered". |
98 setAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE); | 96 setAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE); |
99 } | 97 } |
100 } | 98 } |
101 } | 99 } |
102 | 100 |
103 /** Construction */ | 101 /** Construction */ |
104 static AppRTCAudioManager create(Context context, | 102 static AppRTCAudioManager create(Context context, Runnable deviceStateChangeLi
stener) { |
105 Runnable deviceStateChangeListener) { | |
106 return new AppRTCAudioManager(context, deviceStateChangeListener); | 103 return new AppRTCAudioManager(context, deviceStateChangeListener); |
107 } | 104 } |
108 | 105 |
109 private AppRTCAudioManager(Context context, | 106 private AppRTCAudioManager(Context context, Runnable deviceStateChangeListener
) { |
110 Runnable deviceStateChangeListener) { | |
111 apprtcContext = context; | 107 apprtcContext = context; |
112 onStateChangeListener = deviceStateChangeListener; | 108 onStateChangeListener = deviceStateChangeListener; |
113 audioManager = ((AudioManager) context.getSystemService( | 109 audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVIC
E)); |
114 Context.AUDIO_SERVICE)); | |
115 | 110 |
116 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPref
erences(context); | 111 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPref
erences(context); |
117 useSpeakerphone = sharedPreferences.getString(context.getString(R.string.pre
f_speakerphone_key), | 112 useSpeakerphone = sharedPreferences.getString(context.getString(R.string.pre
f_speakerphone_key), |
118 context.getString(R.string.pref_speakerphone_default)); | 113 context.getString(R.string.pref_speakerphone_default)); |
119 | 114 |
120 if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) { | 115 if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) { |
121 defaultAudioDevice = AudioDevice.EARPIECE; | 116 defaultAudioDevice = AudioDevice.EARPIECE; |
122 } else { | 117 } else { |
123 defaultAudioDevice = AudioDevice.SPEAKER_PHONE; | 118 defaultAudioDevice = AudioDevice.SPEAKER_PHONE; |
124 } | 119 } |
(...skipping 17 matching lines...) Expand all Loading... |
142 if (initialized) { | 137 if (initialized) { |
143 return; | 138 return; |
144 } | 139 } |
145 | 140 |
146 // Store current audio state so we can restore it when close() is called. | 141 // Store current audio state so we can restore it when close() is called. |
147 savedAudioMode = audioManager.getMode(); | 142 savedAudioMode = audioManager.getMode(); |
148 savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn(); | 143 savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn(); |
149 savedIsMicrophoneMute = audioManager.isMicrophoneMute(); | 144 savedIsMicrophoneMute = audioManager.isMicrophoneMute(); |
150 | 145 |
151 // Request audio focus before making any device switch. | 146 // Request audio focus before making any device switch. |
152 audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, | 147 audioManager.requestAudioFocus( |
153 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); | 148 null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANS
IENT); |
154 | 149 |
155 // Start by setting MODE_IN_COMMUNICATION as default audio mode. It is | 150 // Start by setting MODE_IN_COMMUNICATION as default audio mode. It is |
156 // required to be in this mode when playout and/or recording starts for | 151 // required to be in this mode when playout and/or recording starts for |
157 // best possible VoIP performance. | 152 // best possible VoIP performance. |
158 // TODO(henrika): we migh want to start with RINGTONE mode here instead. | 153 // TODO(henrika): we migh want to start with RINGTONE mode here instead. |
159 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); | 154 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); |
160 | 155 |
161 // Always disable microphone mute during a WebRTC call. | 156 // Always disable microphone mute during a WebRTC call. |
162 setMicrophoneMute(false); | 157 setMicrophoneMute(false); |
163 | 158 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 private static final int STATE_UNPLUGGED = 0; | 238 private static final int STATE_UNPLUGGED = 0; |
244 private static final int STATE_PLUGGED = 1; | 239 private static final int STATE_PLUGGED = 1; |
245 private static final int HAS_NO_MIC = 0; | 240 private static final int HAS_NO_MIC = 0; |
246 private static final int HAS_MIC = 1; | 241 private static final int HAS_MIC = 1; |
247 | 242 |
248 @Override | 243 @Override |
249 public void onReceive(Context context, Intent intent) { | 244 public void onReceive(Context context, Intent intent) { |
250 int state = intent.getIntExtra("state", STATE_UNPLUGGED); | 245 int state = intent.getIntExtra("state", STATE_UNPLUGGED); |
251 int microphone = intent.getIntExtra("microphone", HAS_NO_MIC); | 246 int microphone = intent.getIntExtra("microphone", HAS_NO_MIC); |
252 String name = intent.getStringExtra("name"); | 247 String name = intent.getStringExtra("name"); |
253 Log.d(TAG, "BroadcastReceiver.onReceive" + AppRTCUtils.getThreadInfo() | 248 Log.d(TAG, "BroadcastReceiver.onReceive" + AppRTCUtils.getThreadInfo() +
": " |
254 + ": " | 249 + "a=" + intent.getAction() + ", s=" |
255 + "a=" + intent.getAction() | 250 + (state == STATE_UNPLUGGED ? "unplugged" : "plugged") + ", m=" |
256 + ", s=" + (state == STATE_UNPLUGGED ? "unplugged" : "plugged") | 251 + (microphone == HAS_MIC ? "mic" : "no mic") + ", n=" + name + "
, sb=" |
257 + ", m=" + (microphone == HAS_MIC ? "mic" : "no mic") | 252 + isInitialStickyBroadcast()); |
258 + ", n=" + name | |
259 + ", sb=" + isInitialStickyBroadcast()); | |
260 | 253 |
261 boolean hasWiredHeadset = (state == STATE_PLUGGED); | 254 boolean hasWiredHeadset = (state == STATE_PLUGGED); |
262 switch (state) { | 255 switch (state) { |
263 case STATE_UNPLUGGED: | 256 case STATE_UNPLUGGED: |
264 updateAudioDeviceState(hasWiredHeadset); | 257 updateAudioDeviceState(hasWiredHeadset); |
265 break; | 258 break; |
266 case STATE_PLUGGED: | 259 case STATE_PLUGGED: |
267 if (selectedAudioDevice != AudioDevice.WIRED_HEADSET) { | 260 if (selectedAudioDevice != AudioDevice.WIRED_HEADSET) { |
268 updateAudioDeviceState(hasWiredHeadset); | 261 updateAudioDeviceState(hasWiredHeadset); |
269 } | 262 } |
(...skipping 27 matching lines...) Expand all Loading... |
297 private void setMicrophoneMute(boolean on) { | 290 private void setMicrophoneMute(boolean on) { |
298 boolean wasMuted = audioManager.isMicrophoneMute(); | 291 boolean wasMuted = audioManager.isMicrophoneMute(); |
299 if (wasMuted == on) { | 292 if (wasMuted == on) { |
300 return; | 293 return; |
301 } | 294 } |
302 audioManager.setMicrophoneMute(on); | 295 audioManager.setMicrophoneMute(on); |
303 } | 296 } |
304 | 297 |
305 /** Gets the current earpiece state. */ | 298 /** Gets the current earpiece state. */ |
306 private boolean hasEarpiece() { | 299 private boolean hasEarpiece() { |
307 return apprtcContext.getPackageManager().hasSystemFeature( | 300 return apprtcContext.getPackageManager().hasSystemFeature(PackageManager.FEA
TURE_TELEPHONY); |
308 PackageManager.FEATURE_TELEPHONY); | |
309 } | 301 } |
310 | 302 |
311 /** | 303 /** |
312 * Checks whether a wired headset is connected or not. | 304 * Checks whether a wired headset is connected or not. |
313 * This is not a valid indication that audio playback is actually over | 305 * This is not a valid indication that audio playback is actually over |
314 * the wired headset as audio routing depends on other conditions. We | 306 * the wired headset as audio routing depends on other conditions. We |
315 * only use it as an early indicator (during initialization) of an attached | 307 * only use it as an early indicator (during initialization) of an attached |
316 * wired headset. | 308 * wired headset. |
317 */ | 309 */ |
318 @Deprecated | 310 @Deprecated |
319 private boolean hasWiredHeadset() { | 311 private boolean hasWiredHeadset() { |
320 return audioManager.isWiredHeadsetOn(); | 312 return audioManager.isWiredHeadsetOn(); |
321 } | 313 } |
322 | 314 |
323 /** Update list of possible audio devices and make new device selection. */ | 315 /** Update list of possible audio devices and make new device selection. */ |
324 private void updateAudioDeviceState(boolean hasWiredHeadset) { | 316 private void updateAudioDeviceState(boolean hasWiredHeadset) { |
325 // Update the list of available audio devices. | 317 // Update the list of available audio devices. |
326 audioDevices.clear(); | 318 audioDevices.clear(); |
327 if (hasWiredHeadset) { | 319 if (hasWiredHeadset) { |
328 // If a wired headset is connected, then it is the only possible option. | 320 // If a wired headset is connected, then it is the only possible option. |
329 audioDevices.add(AudioDevice.WIRED_HEADSET); | 321 audioDevices.add(AudioDevice.WIRED_HEADSET); |
330 } else { | 322 } else { |
331 // No wired headset, hence the audio-device list can contain speaker | 323 // No wired headset, hence the audio-device list can contain speaker |
332 // phone (on a tablet), or speaker phone and earpiece (on mobile phone). | 324 // phone (on a tablet), or speaker phone and earpiece (on mobile phone). |
333 audioDevices.add(AudioDevice.SPEAKER_PHONE); | 325 audioDevices.add(AudioDevice.SPEAKER_PHONE); |
334 if (hasEarpiece()) { | 326 if (hasEarpiece()) { |
335 audioDevices.add(AudioDevice.EARPIECE); | 327 audioDevices.add(AudioDevice.EARPIECE); |
336 } | 328 } |
337 } | 329 } |
338 Log.d(TAG, "audioDevices: " + audioDevices); | 330 Log.d(TAG, "audioDevices: " + audioDevices); |
339 | 331 |
340 // Switch to correct audio device given the list of available audio devices. | 332 // Switch to correct audio device given the list of available audio devices. |
341 if (hasWiredHeadset) { | 333 if (hasWiredHeadset) { |
342 setAudioDevice(AudioDevice.WIRED_HEADSET); | 334 setAudioDevice(AudioDevice.WIRED_HEADSET); |
343 } else { | 335 } else { |
344 setAudioDevice(defaultAudioDevice); | 336 setAudioDevice(defaultAudioDevice); |
345 } | 337 } |
346 } | 338 } |
347 | 339 |
348 /** Called each time a new audio device has been added or removed. */ | 340 /** Called each time a new audio device has been added or removed. */ |
349 private void onAudioManagerChangedState() { | 341 private void onAudioManagerChangedState() { |
350 Log.d(TAG, "onAudioManagerChangedState: devices=" + audioDevices | 342 Log.d(TAG, "onAudioManagerChangedState: devices=" + audioDevices + ", select
ed=" |
351 + ", selected=" + selectedAudioDevice); | 343 + selectedAudioDevice); |
352 | 344 |
353 // Enable the proximity sensor if there are two available audio devices | 345 // Enable the proximity sensor if there are two available audio devices |
354 // in the list. Given the current implementation, we know that the choice | 346 // in the list. Given the current implementation, we know that the choice |
355 // will then be between EARPIECE and SPEAKER_PHONE. | 347 // will then be between EARPIECE and SPEAKER_PHONE. |
356 if (audioDevices.size() == 2) { | 348 if (audioDevices.size() == 2) { |
357 AppRTCUtils.assertIsTrue(audioDevices.contains(AudioDevice.EARPIECE) | 349 AppRTCUtils.assertIsTrue(audioDevices.contains(AudioDevice.EARPIECE) |
358 && audioDevices.contains(AudioDevice.SPEAKER_PHONE)); | 350 && audioDevices.contains(AudioDevice.SPEAKER_PHONE)); |
359 // Start the proximity sensor. | 351 // Start the proximity sensor. |
360 proximitySensor.start(); | 352 proximitySensor.start(); |
361 } else if (audioDevices.size() == 1) { | 353 } else if (audioDevices.size() == 1) { |
362 // Stop the proximity sensor since it is no longer needed. | 354 // Stop the proximity sensor since it is no longer needed. |
363 proximitySensor.stop(); | 355 proximitySensor.stop(); |
364 } else { | 356 } else { |
365 Log.e(TAG, "Invalid device list"); | 357 Log.e(TAG, "Invalid device list"); |
366 } | 358 } |
367 | 359 |
368 if (onStateChangeListener != null) { | 360 if (onStateChangeListener != null) { |
369 // Run callback to notify a listening client. The client can then | 361 // Run callback to notify a listening client. The client can then |
370 // use public getters to query the new state. | 362 // use public getters to query the new state. |
371 onStateChangeListener.run(); | 363 onStateChangeListener.run(); |
372 } | 364 } |
373 } | 365 } |
374 } | 366 } |
OLD | NEW |