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 |