| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 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 | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 package org.webrtc.webrtcdemo; | |
| 12 | |
| 13 import android.app.AlertDialog; | |
| 14 import android.content.BroadcastReceiver; | |
| 15 import android.content.Context; | |
| 16 import android.content.DialogInterface; | |
| 17 import android.content.Intent; | |
| 18 import android.content.IntentFilter; | |
| 19 import android.media.AudioManager; | |
| 20 import android.os.Environment; | |
| 21 import android.util.Log; | |
| 22 import android.view.OrientationEventListener; | |
| 23 import java.io.File; | |
| 24 | |
| 25 public class MediaEngine { | |
| 26 private static final String LOG_DIR = "webrtc"; | |
| 27 | |
| 28 // Checks for and communicate failures to user (logcat and popup). | |
| 29 private void check(boolean value, String message) { | |
| 30 if (value) { | |
| 31 return; | |
| 32 } | |
| 33 Log.e("WEBRTC-CHECK", message); | |
| 34 AlertDialog alertDialog = new AlertDialog.Builder(context).create(); | |
| 35 alertDialog.setTitle("WebRTC Error"); | |
| 36 alertDialog.setMessage(message); | |
| 37 alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, | |
| 38 "OK", | |
| 39 new DialogInterface.OnClickListener() { | |
| 40 public void onClick(DialogInterface dialog, int which) { | |
| 41 dialog.dismiss(); | |
| 42 return; | |
| 43 } | |
| 44 } | |
| 45 ); | |
| 46 alertDialog.show(); | |
| 47 } | |
| 48 | |
| 49 | |
| 50 // Shared Audio/Video members. | |
| 51 private final Context context; | |
| 52 private String remoteIp; | |
| 53 private boolean enableTrace; | |
| 54 | |
| 55 // Audio | |
| 56 private VoiceEngine voe; | |
| 57 private int audioChannel; | |
| 58 private boolean audioEnabled; | |
| 59 private boolean voeRunning; | |
| 60 private int audioCodecIndex; | |
| 61 private int audioTxPort; | |
| 62 private int audioRxPort; | |
| 63 | |
| 64 private boolean speakerEnabled; | |
| 65 private boolean headsetPluggedIn; | |
| 66 private boolean enableAgc; | |
| 67 private boolean enableNs; | |
| 68 private boolean enableAecm; | |
| 69 | |
| 70 private BroadcastReceiver headsetListener; | |
| 71 | |
| 72 private boolean audioRtpDump; | |
| 73 private boolean apmRecord; | |
| 74 | |
| 75 private int inFps; | |
| 76 private int inKbps; | |
| 77 private int outFps; | |
| 78 private int outKbps; | |
| 79 private int inWidth; | |
| 80 private int inHeight; | |
| 81 | |
| 82 public MediaEngine(Context context) { | |
| 83 this.context = context; | |
| 84 voe = new VoiceEngine(); | |
| 85 check(voe.init() == 0, "Failed voe Init"); | |
| 86 audioChannel = voe.createChannel(); | |
| 87 check(audioChannel >= 0, "Failed voe CreateChannel"); | |
| 88 check(audioChannel >= 0, "Failed voe CreateChannel"); | |
| 89 | |
| 90 check(voe.setAecmMode(VoiceEngine.AecmModes.SPEAKERPHONE, false) == 0, | |
| 91 "VoE set Aecm speakerphone mode failed"); | |
| 92 | |
| 93 // Set audio mode to communication | |
| 94 AudioManager audioManager = | |
| 95 ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); | |
| 96 audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); | |
| 97 // Listen to headset being plugged in/out. | |
| 98 IntentFilter receiverFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); | |
| 99 headsetListener = new BroadcastReceiver() { | |
| 100 @Override | |
| 101 public void onReceive(Context context, Intent intent) { | |
| 102 if (intent.getAction().compareTo(Intent.ACTION_HEADSET_PLUG) == 0) { | |
| 103 headsetPluggedIn = intent.getIntExtra("state", 0) == 1; | |
| 104 updateAudioOutput(); | |
| 105 } | |
| 106 } | |
| 107 }; | |
| 108 context.registerReceiver(headsetListener, receiverFilter); | |
| 109 } | |
| 110 | |
| 111 public void dispose() { | |
| 112 check(!voeRunning && !voeRunning, "Engines must be stopped before dispose"); | |
| 113 context.unregisterReceiver(headsetListener); | |
| 114 check(voe.deleteChannel(audioChannel) == 0, "VoE delete channel failed"); | |
| 115 voe.dispose(); | |
| 116 } | |
| 117 | |
| 118 public void start() { | |
| 119 if (audioEnabled) { | |
| 120 startVoE(); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 public void stop() { | |
| 125 stopVoe(); | |
| 126 } | |
| 127 | |
| 128 public boolean isRunning() { | |
| 129 return voeRunning; | |
| 130 } | |
| 131 | |
| 132 public void setRemoteIp(String remoteIp) { | |
| 133 this.remoteIp = remoteIp; | |
| 134 UpdateSendDestination(); | |
| 135 } | |
| 136 | |
| 137 public String remoteIp() { return remoteIp; } | |
| 138 | |
| 139 private String getDebugDirectory() { | |
| 140 // Should create a folder in /scard/|LOG_DIR| | |
| 141 return Environment.getExternalStorageDirectory().toString() + "/" + | |
| 142 LOG_DIR; | |
| 143 } | |
| 144 | |
| 145 private boolean createDebugDirectory() { | |
| 146 File webrtc_dir = new File(getDebugDirectory()); | |
| 147 if (!webrtc_dir.exists()) { | |
| 148 return webrtc_dir.mkdir(); | |
| 149 } | |
| 150 return webrtc_dir.isDirectory(); | |
| 151 } | |
| 152 | |
| 153 public void startVoE() { | |
| 154 check(!voeRunning, "VoE already started"); | |
| 155 check(voe.startListen(audioChannel) == 0, "Failed StartListen"); | |
| 156 check(voe.startPlayout(audioChannel) == 0, "VoE start playout failed"); | |
| 157 check(voe.startSend(audioChannel) == 0, "VoE start send failed"); | |
| 158 voeRunning = true; | |
| 159 } | |
| 160 | |
| 161 private void stopVoe() { | |
| 162 check(voeRunning, "VoE not started"); | |
| 163 check(voe.stopSend(audioChannel) == 0, "VoE stop send failed"); | |
| 164 check(voe.stopPlayout(audioChannel) == 0, "VoE stop playout failed"); | |
| 165 check(voe.stopListen(audioChannel) == 0, "VoE stop listen failed"); | |
| 166 voeRunning = false; | |
| 167 } | |
| 168 | |
| 169 public void setAudio(boolean audioEnabled) { | |
| 170 this.audioEnabled = audioEnabled; | |
| 171 } | |
| 172 | |
| 173 public boolean audioEnabled() { return audioEnabled; } | |
| 174 | |
| 175 public int audioCodecIndex() { return audioCodecIndex; } | |
| 176 | |
| 177 public void setAudioCodec(int codecNumber) { | |
| 178 audioCodecIndex = codecNumber; | |
| 179 CodecInst codec = voe.getCodec(codecNumber); | |
| 180 check(voe.setSendCodec(audioChannel, codec) == 0, "Failed setSendCodec"); | |
| 181 codec.dispose(); | |
| 182 } | |
| 183 | |
| 184 public String[] audioCodecsAsString() { | |
| 185 String[] retVal = new String[voe.numOfCodecs()]; | |
| 186 for (int i = 0; i < voe.numOfCodecs(); ++i) { | |
| 187 CodecInst codec = voe.getCodec(i); | |
| 188 retVal[i] = codec.toString(); | |
| 189 codec.dispose(); | |
| 190 } | |
| 191 return retVal; | |
| 192 } | |
| 193 | |
| 194 private CodecInst[] defaultAudioCodecs() { | |
| 195 CodecInst[] retVal = new CodecInst[voe.numOfCodecs()]; | |
| 196 for (int i = 0; i < voe.numOfCodecs(); ++i) { | |
| 197 retVal[i] = voe.getCodec(i); | |
| 198 } | |
| 199 return retVal; | |
| 200 } | |
| 201 | |
| 202 public int getIsacIndex() { | |
| 203 CodecInst[] codecs = defaultAudioCodecs(); | |
| 204 for (int i = 0; i < codecs.length; ++i) { | |
| 205 if (codecs[i].name().contains("ISAC")) { | |
| 206 return i; | |
| 207 } | |
| 208 } | |
| 209 return 0; | |
| 210 } | |
| 211 | |
| 212 public void setAudioTxPort(int audioTxPort) { | |
| 213 this.audioTxPort = audioTxPort; | |
| 214 UpdateSendDestination(); | |
| 215 } | |
| 216 | |
| 217 public int audioTxPort() { return audioTxPort; } | |
| 218 | |
| 219 public void setAudioRxPort(int audioRxPort) { | |
| 220 check(voe.setLocalReceiver(audioChannel, audioRxPort) == 0, | |
| 221 "Failed setLocalReceiver"); | |
| 222 this.audioRxPort = audioRxPort; | |
| 223 } | |
| 224 | |
| 225 public int audioRxPort() { return audioRxPort; } | |
| 226 | |
| 227 public boolean agcEnabled() { return enableAgc; } | |
| 228 | |
| 229 public void setAgc(boolean enable) { | |
| 230 enableAgc = enable; | |
| 231 VoiceEngine.AgcConfig agc_config = | |
| 232 new VoiceEngine.AgcConfig(3, 9, true); | |
| 233 check(voe.setAgcConfig(agc_config) == 0, "VoE set AGC Config failed"); | |
| 234 check(voe.setAgcStatus(enableAgc, VoiceEngine.AgcModes.FIXED_DIGITAL) == 0, | |
| 235 "VoE set AGC Status failed"); | |
| 236 } | |
| 237 | |
| 238 public boolean nsEnabled() { return enableNs; } | |
| 239 | |
| 240 public void setNs(boolean enable) { | |
| 241 enableNs = enable; | |
| 242 check(voe.setNsStatus(enableNs, | |
| 243 VoiceEngine.NsModes.MODERATE_SUPPRESSION) == 0, | |
| 244 "VoE set NS Status failed"); | |
| 245 } | |
| 246 | |
| 247 public boolean aecmEnabled() { return enableAecm; } | |
| 248 | |
| 249 public void setEc(boolean enable) { | |
| 250 enableAecm = enable; | |
| 251 check(voe.setEcStatus(enable, VoiceEngine.EcModes.AECM) == 0, | |
| 252 "voe setEcStatus"); | |
| 253 } | |
| 254 | |
| 255 public boolean speakerEnabled() { | |
| 256 return speakerEnabled; | |
| 257 } | |
| 258 | |
| 259 public void setSpeaker(boolean enable) { | |
| 260 speakerEnabled = enable; | |
| 261 updateAudioOutput(); | |
| 262 } | |
| 263 | |
| 264 // Debug helpers. | |
| 265 public boolean apmRecord() { return apmRecord; } | |
| 266 | |
| 267 public boolean audioRtpDump() { return audioRtpDump; } | |
| 268 | |
| 269 public void setDebuging(boolean enable) { | |
| 270 apmRecord = enable; | |
| 271 if (!enable) { | |
| 272 check(voe.stopDebugRecording() == 0, "Failed stopping debug"); | |
| 273 return; | |
| 274 } | |
| 275 if (!createDebugDirectory()) { | |
| 276 check(false, "Unable to create debug directory."); | |
| 277 return; | |
| 278 } | |
| 279 String debugDirectory = getDebugDirectory(); | |
| 280 check(voe.startDebugRecording(debugDirectory + String.format("/apm_%d.dat", | |
| 281 System.currentTimeMillis())) == 0, | |
| 282 "Failed starting debug"); | |
| 283 } | |
| 284 | |
| 285 public void setIncomingVoeRtpDump(boolean enable) { | |
| 286 audioRtpDump = enable; | |
| 287 if (!enable) { | |
| 288 check(voe.stopRtpDump(audioChannel, | |
| 289 VoiceEngine.RtpDirections.INCOMING) == 0, | |
| 290 "voe stopping rtp dump"); | |
| 291 return; | |
| 292 } | |
| 293 String debugDirectory = getDebugDirectory(); | |
| 294 check(voe.startRtpDump(audioChannel, debugDirectory + | |
| 295 String.format("/voe_%d.rtp", System.currentTimeMillis()), | |
| 296 VoiceEngine.RtpDirections.INCOMING) == 0, | |
| 297 "voe starting rtp dump"); | |
| 298 } | |
| 299 | |
| 300 private void updateAudioOutput() { | |
| 301 boolean useSpeaker = !headsetPluggedIn && speakerEnabled; | |
| 302 AudioManager audioManager = | |
| 303 ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); | |
| 304 audioManager.setSpeakerphoneOn(useSpeaker); | |
| 305 } | |
| 306 | |
| 307 private void UpdateSendDestination() { | |
| 308 if (remoteIp == null) { | |
| 309 return; | |
| 310 } | |
| 311 if (audioTxPort != 0) { | |
| 312 check(voe.setSendDestination(audioChannel, audioTxPort, | |
| 313 remoteIp) == 0, "VoE set send destination failed"); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 MediaEngineObserver observer; | |
| 318 public void setObserver(MediaEngineObserver observer) { | |
| 319 this.observer = observer; | |
| 320 } | |
| 321 } | |
| OLD | NEW |