diff --git a/talk/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java b/talk/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java new file mode 100644 index 000000000..b2a1a44e5 --- /dev/null +++ b/talk/examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java @@ -0,0 +1,108 @@ +/* + * libjingle + * Copyright 2013, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.appspot.apprtc; + +import android.content.Context; +import android.media.AudioManager; +import android.util.Log; + +/** + * AppRTCAudioManager manages all audio related parts of the AppRTC demo. + * TODO(henrika): add support for device enumeration, device selection etc. + */ +public class AppRTCAudioManager { + private static final String TAG = "AppRTCAudioManager"; + + private boolean initialized = false; + private AudioManager audioManager; + private int savedAudioMode = AudioManager.MODE_INVALID; + private boolean savedIsSpeakerPhoneOn = false; + private boolean savedIsMicrophoneMute = false; + + /** Construction */ + static AppRTCAudioManager create(Context context) { + return new AppRTCAudioManager(context); + } + + private AppRTCAudioManager(Context context) { + Log.d(TAG, "AppRTCAudioManager"); + audioManager = ((AudioManager) context.getSystemService( + Context.AUDIO_SERVICE)); + } + + public void init() { + Log.d(TAG, "init"); + if (initialized) { + return; + } + + // Store current audio state so we can restore it when close() is called. + savedAudioMode = audioManager.getMode(); + savedIsSpeakerPhoneOn = audioManager.isSpeakerphoneOn(); + savedIsMicrophoneMute = audioManager.isMicrophoneMute(); + + // The AppRTC demo shall always run in COMMUNICATION mode since it will + // result in best possible "VoIP settings", like audio routing, volume + // control etc. + audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); + + initialized = true; + } + + public void close() { + Log.d(TAG, "close"); + if (!initialized) { + return; + } + + // Restore previously stored audio states. + setSpeakerphoneOn(savedIsSpeakerPhoneOn); + setMicrophoneMute(savedIsMicrophoneMute); + audioManager.setMode(savedAudioMode); + + initialized = false; + } + + /** Sets the speaker phone mode. */ + private void setSpeakerphoneOn(boolean on) { + boolean wasOn = audioManager.isSpeakerphoneOn(); + if (wasOn == on) { + return; + } + audioManager.setSpeakerphoneOn(on); + } + + /** Sets the microphone mute state. */ + private void setMicrophoneMute(boolean on) { + boolean wasMuted = audioManager.isMicrophoneMute(); + if (wasMuted == on) { + return; + } + audioManager.setMicrophoneMute(on); + } +} diff --git a/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java b/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java index ad0e2d550..3ad26afca 100644 --- a/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java +++ b/talk/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java @@ -34,7 +34,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Color; -import android.media.AudioManager; import android.net.Uri; import android.opengl.GLSurfaceView; import android.os.Bundle; @@ -72,6 +71,7 @@ public class AppRTCDemoActivity extends Activity private PeerConnectionClient pc; private AppRTCClient appRtcClient = new GAERTCClient(this, this); private AppRTCSignalingParameters appRtcParameters; + private AppRTCAudioManager audioManager = null; private View rootView; private View menuBar; private GLSurfaceView videoView; @@ -187,15 +187,9 @@ public class AppRTCDemoActivity extends Activity hudView.setVisibility(View.INVISIBLE); addContentView(hudView, hudLayout); - AudioManager audioManager = - ((AudioManager) getSystemService(AUDIO_SERVICE)); - // TODO(fischman): figure out how to do this Right(tm) and remove the - // suppression. - @SuppressWarnings("deprecation") - boolean isWiredHeadsetOn = audioManager.isWiredHeadsetOn(); - audioManager.setMode(isWiredHeadsetOn ? - AudioManager.MODE_IN_CALL : AudioManager.MODE_IN_COMMUNICATION); - audioManager.setSpeakerphoneOn(!isWiredHeadsetOn); + // Create and audio manager that will take care of audio routing, + // audio modes, audio device enumeration etc. + audioManager = AppRTCAudioManager.create(this); final Intent intent = getIntent(); Uri url = intent.getData(); @@ -253,6 +247,10 @@ public class AppRTCDemoActivity extends Activity @Override protected void onDestroy() { disconnect(); + if (audioManager != null) { + audioManager.close(); + audioManager = null; + } super.onDestroy(); } @@ -360,6 +358,12 @@ public class AppRTCDemoActivity extends Activity // All events are called from UI thread. @Override public void onConnectedToRoom(final AppRTCSignalingParameters params) { + if (audioManager != null) { + // Store existing audio settings and change audio mode to + // MODE_IN_COMMUNICATION for best possible VoIP performance. + logAndToast("Initializing the audio manager..."); + audioManager.init(); + } appRtcParameters = params; abortUnless(PeerConnectionFactory.initializeAndroidGlobals( this, true, true, VideoRendererGui.getEGLContext()), diff --git a/talk/libjingle_examples.gyp b/talk/libjingle_examples.gyp index d0f174762..f7ce53bdd 100755 --- a/talk/libjingle_examples.gyp +++ b/talk/libjingle_examples.gyp @@ -344,6 +344,7 @@ 'examples/android/res/values/arrays.xml', 'examples/android/res/values/strings.xml', 'examples/android/res/xml/preferences.xml', + 'examples/android/src/org/appspot/apprtc/AppRTCAudioManager.java', 'examples/android/src/org/appspot/apprtc/AppRTCClient.java', 'examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java', 'examples/android/src/org/appspot/apprtc/ConnectActivity.java',