Add RtcEventLog to AppRTCMobile with preference setting.

Enable diagnostic packet and event recording as in the "webrtc-internal"
setting in Chromium.

Bug: webrtc:8859
Change-Id: I1d4a19e0dd60133cdd0d4e18a55780623b65653c
Reviewed-on: https://webrtc-review.googlesource.com/49541
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21987}
This commit is contained in:
Qingsi Wang
2018-02-12 10:34:18 -08:00
committed by Commit Bot
parent f7f8cb979b
commit a4e72b7914
9 changed files with 158 additions and 20 deletions

View File

@ -83,6 +83,7 @@ if (is_android) {
"androidapp/src/org/appspot/apprtc/HudFragment.java",
"androidapp/src/org/appspot/apprtc/PeerConnectionClient.java",
"androidapp/src/org/appspot/apprtc/RoomParametersFetcher.java",
"androidapp/src/org/appspot/apprtc/RtcEventLog.java",
"androidapp/src/org/appspot/apprtc/SettingsActivity.java",
"androidapp/src/org/appspot/apprtc/SettingsFragment.java",
"androidapp/src/org/appspot/apprtc/TCPChannelClient.java",

View File

@ -213,4 +213,8 @@
<string name="pref_tracing_title">Debug performance tracing.</string>
<string name="pref_tracing_dlg">Debug performance tracing.</string>
<string name="pref_tracing_default" translatable="false">false</string>
<string name="pref_enable_rtceventlog_key">enable_rtceventlog_key</string>
<string name="pref_enable_rtceventlog_title">Enable RtcEventLog.</string>
<string name="pref_enable_rtceventlog_default">false</string>
</resources>

View File

@ -236,6 +236,11 @@
android:title="@string/pref_tracing_title"
android:dialogTitle="@string/pref_tracing_dlg"
android:defaultValue="@string/pref_tracing_default" />
<CheckBoxPreference
android:key="@string/pref_enable_rtceventlog_key"
android:title="@string/pref_enable_rtceventlog_title"
android:defaultValue="@string/pref_enable_rtceventlog_default"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -117,6 +117,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
public static final String EXTRA_PROTOCOL = "org.appspot.apprtc.PROTOCOL";
public static final String EXTRA_NEGOTIATED = "org.appspot.apprtc.NEGOTIATED";
public static final String EXTRA_ID = "org.appspot.apprtc.ID";
public static final String EXTRA_ENABLE_RTCEVENTLOG = "org.appspot.apprtc.ENABLE_RTCEVENTLOG";
private static final int CAPTURE_PERMISSION_REQUEST_CODE = 1;
@ -242,7 +243,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
final Intent intent = getIntent();
// Create peer connection client.
peerConnectionClient = new PeerConnectionClient();
peerConnectionClient = new PeerConnectionClient(getApplicationContext());
// Create video renderers.
pipRenderer.init(peerConnectionClient.getRenderContext(), null);
@ -335,7 +336,8 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
intent.getBooleanExtra(EXTRA_DISABLE_BUILT_IN_AGC, false),
intent.getBooleanExtra(EXTRA_DISABLE_BUILT_IN_NS, false),
intent.getBooleanExtra(EXTRA_ENABLE_LEVEL_CONTROL, false),
intent.getBooleanExtra(EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, false), dataChannelParameters);
intent.getBooleanExtra(EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, false),
intent.getBooleanExtra(EXTRA_ENABLE_RTCEVENTLOG, false), dataChannelParameters);
commandLineRun = intent.getBooleanExtra(EXTRA_CMDLINE, false);
int runTimeMs = intent.getIntExtra(EXTRA_RUNTIME, 0);
@ -384,8 +386,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
options.networkIgnoreMask = 0;
peerConnectionClient.setPeerConnectionFactoryOptions(options);
}
peerConnectionClient.createPeerConnectionFactory(
getApplicationContext(), peerConnectionParameters, CallActivity.this);
peerConnectionClient.createPeerConnectionFactory(peerConnectionParameters, CallActivity.this);
if (screencaptureEnabled) {
startScreenCapture();

View File

@ -430,6 +430,11 @@ public class ConnectActivity extends Activity {
boolean tracing = sharedPrefGetBoolean(R.string.pref_tracing_key, CallActivity.EXTRA_TRACING,
R.string.pref_tracing_default, useValuesFromIntent);
// Check Enable RtcEventLog.
boolean rtcEventLogEnabled = sharedPrefGetBoolean(R.string.pref_enable_rtceventlog_key,
CallActivity.EXTRA_ENABLE_RTCEVENTLOG, R.string.pref_enable_rtceventlog_default,
useValuesFromIntent);
// Get datachannel options
boolean dataChannelEnabled = sharedPrefGetBoolean(R.string.pref_enable_datachannel_key,
CallActivity.EXTRA_DATA_CHANNEL_ENABLED, R.string.pref_enable_datachannel_default,
@ -481,6 +486,7 @@ public class ConnectActivity extends Activity {
intent.putExtra(CallActivity.EXTRA_AUDIOCODEC, audioCodec);
intent.putExtra(CallActivity.EXTRA_DISPLAY_HUD, displayHud);
intent.putExtra(CallActivity.EXTRA_TRACING, tracing);
intent.putExtra(CallActivity.EXTRA_ENABLE_RTCEVENTLOG, rtcEventLogEnabled);
intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun);
intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs);

View File

@ -13,16 +13,21 @@ package org.appspot.apprtc;
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
@ -105,6 +110,7 @@ public class PeerConnectionClient {
private static final int HD_VIDEO_WIDTH = 1280;
private static final int HD_VIDEO_HEIGHT = 720;
private static final int BPS_IN_KBPS = 1000;
private static final String RTCEVENTLOG_OUTPUT_DIR_NAME = "rtc_event_log";
// Executor thread is started once in private ctor and is used for all
// peer connection API calls to ensure new peer connection factory is
@ -115,6 +121,7 @@ public class PeerConnectionClient {
private final SDPObserver sdpObserver = new SDPObserver();
private final EglBase rootEglBase;
private final Context appContext;
private PeerConnectionFactory factory;
private PeerConnection peerConnection;
PeerConnectionFactory.Options options = null;
@ -154,6 +161,8 @@ public class PeerConnectionClient {
private AudioTrack localAudioTrack;
private DataChannel dataChannel;
private boolean dataChannelEnabled;
// Enable RtcEventLog.
private RtcEventLog rtcEventLog;
/**
* Peer connection parameters.
@ -201,6 +210,7 @@ public class PeerConnectionClient {
public final boolean disableBuiltInNS;
public final boolean enableLevelControl;
public final boolean disableWebRtcAGCAndHPF;
public final boolean enableRtcEventLog;
private final DataChannelParameters dataChannelParameters;
public PeerConnectionParameters(boolean videoCallEnabled, boolean loopback, boolean tracing,
@ -208,11 +218,11 @@ public class PeerConnectionClient {
boolean videoCodecHwAcceleration, boolean videoFlexfecEnabled, int audioStartBitrate,
String audioCodec, boolean noAudioProcessing, boolean aecDump, boolean useOpenSLES,
boolean disableBuiltInAEC, boolean disableBuiltInAGC, boolean disableBuiltInNS,
boolean enableLevelControl, boolean disableWebRtcAGCAndHPF) {
boolean enableLevelControl, boolean disableWebRtcAGCAndHPF, boolean enableRtcEventLog) {
this(videoCallEnabled, loopback, tracing, videoWidth, videoHeight, videoFps, videoMaxBitrate,
videoCodec, videoCodecHwAcceleration, videoFlexfecEnabled, audioStartBitrate, audioCodec,
noAudioProcessing, aecDump, useOpenSLES, disableBuiltInAEC, disableBuiltInAGC,
disableBuiltInNS, enableLevelControl, disableWebRtcAGCAndHPF, null);
disableBuiltInNS, enableLevelControl, disableWebRtcAGCAndHPF, enableRtcEventLog, null);
}
public PeerConnectionParameters(boolean videoCallEnabled, boolean loopback, boolean tracing,
@ -220,7 +230,7 @@ public class PeerConnectionClient {
boolean videoCodecHwAcceleration, boolean videoFlexfecEnabled, int audioStartBitrate,
String audioCodec, boolean noAudioProcessing, boolean aecDump, boolean useOpenSLES,
boolean disableBuiltInAEC, boolean disableBuiltInAGC, boolean disableBuiltInNS,
boolean enableLevelControl, boolean disableWebRtcAGCAndHPF,
boolean enableLevelControl, boolean disableWebRtcAGCAndHPF, boolean enableRtcEventLog,
DataChannelParameters dataChannelParameters) {
this.videoCallEnabled = videoCallEnabled;
this.loopback = loopback;
@ -242,6 +252,7 @@ public class PeerConnectionClient {
this.disableBuiltInNS = disableBuiltInNS;
this.enableLevelControl = enableLevelControl;
this.disableWebRtcAGCAndHPF = disableWebRtcAGCAndHPF;
this.enableRtcEventLog = enableRtcEventLog;
this.dataChannelParameters = dataChannelParameters;
}
}
@ -293,15 +304,19 @@ public class PeerConnectionClient {
void onPeerConnectionError(final String description);
}
public PeerConnectionClient() {
public PeerConnectionClient(Context appContext) {
if (appContext == null) {
throw new NullPointerException("The application context is null");
}
rootEglBase = EglBase.create();
this.appContext = appContext;
}
public void setPeerConnectionFactoryOptions(PeerConnectionFactory.Options options) {
this.options = options;
}
public void createPeerConnectionFactory(final Context context,
public void createPeerConnectionFactory(
final PeerConnectionParameters peerConnectionParameters, final PeerConnectionEvents events) {
this.peerConnectionParameters = peerConnectionParameters;
this.events = events;
@ -328,7 +343,7 @@ public class PeerConnectionClient {
executor.execute(new Runnable() {
@Override
public void run() {
createPeerConnectionFactoryInternal(context);
createPeerConnectionFactoryInternal();
}
});
}
@ -357,6 +372,7 @@ public class PeerConnectionClient {
try {
createMediaConstraintsInternal();
createPeerConnectionInternal();
maybeCreateAndStartRtcEventLog();
} catch (Exception e) {
reportError("Failed to create peer connection: " + e.getMessage());
throw e;
@ -378,7 +394,7 @@ public class PeerConnectionClient {
return videoCallEnabled;
}
private void createPeerConnectionFactoryInternal(Context context) {
private void createPeerConnectionFactoryInternal() {
isError = false;
// Initialize field trials.
@ -422,7 +438,7 @@ public class PeerConnectionClient {
"Initialize WebRTC. Field trials: " + fieldTrials + " Enable video HW acceleration: "
+ peerConnectionParameters.videoCodecHwAcceleration);
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions.builder(context)
PeerConnectionFactory.InitializationOptions.builder(appContext)
.setFieldTrials(fieldTrials)
.setEnableVideoHwAcceleration(peerConnectionParameters.videoCodecHwAcceleration)
.setEnableInternalTracer(true)
@ -664,6 +680,26 @@ public class PeerConnectionClient {
Log.d(TAG, "Peer connection created.");
}
private File createRtcEventLogOutputFile() {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hhmm_ss", Locale.getDefault());
Date date = new Date();
final String outputFileName = "event_log_" + dateFormat.format(date) + ".log";
return new File(
appContext.getDir(RTCEVENTLOG_OUTPUT_DIR_NAME, Context.MODE_PRIVATE), outputFileName);
}
private void maybeCreateAndStartRtcEventLog() {
if (appContext == null || peerConnection == null) {
return;
}
if (!peerConnectionParameters.enableRtcEventLog) {
Log.d(TAG, "RtcEventLog is disabled.");
return;
}
rtcEventLog = new RtcEventLog(peerConnection);
rtcEventLog.start(createRtcEventLogOutputFile());
}
private void closeInternal() {
if (factory != null && peerConnectionParameters.aecDump) {
factory.stopAecDump();
@ -674,6 +710,11 @@ public class PeerConnectionClient {
dataChannel.dispose();
dataChannel = null;
}
if (rtcEventLog != null) {
// RtcEventLog should stop before the peer connection is disposed.
rtcEventLog.stop();
rtcEventLog = null;
}
if (peerConnection != null) {
peerConnection.dispose();
peerConnection = null;

View File

@ -0,0 +1,74 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.appspot.apprtc;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import org.webrtc.PeerConnection;
public class RtcEventLog {
private static final String TAG = "RtcEventLog";
private static final int OUTPUT_FILE_MAX_BYTES = 10_000_000;
private final PeerConnection peerConnection;
private RtcEventLogState state = RtcEventLogState.INACTIVE;
enum RtcEventLogState {
INACTIVE,
STARTED,
STOPPED,
}
public RtcEventLog(PeerConnection peerConnection) {
if (peerConnection == null) {
throw new NullPointerException("The peer connection is null.");
}
this.peerConnection = peerConnection;
}
public void start(final File outputFile) {
if (state == RtcEventLogState.STARTED) {
Log.e(TAG, "RtcEventLog has already started.");
return;
}
final ParcelFileDescriptor fileDescriptor;
try {
fileDescriptor = ParcelFileDescriptor.open(outputFile,
ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE
| ParcelFileDescriptor.MODE_TRUNCATE);
} catch (IOException e) {
Log.e(TAG, "Failed to create a new file", e);
return;
}
// Passes ownership of the file to WebRTC.
boolean success =
peerConnection.startRtcEventLog(fileDescriptor.detachFd(), OUTPUT_FILE_MAX_BYTES);
if (!success) {
Log.e(TAG, "Failed to start RTC event log.");
return;
}
state = RtcEventLogState.STARTED;
Log.d(TAG, "RtcEventLog started.");
}
public void stop() {
if (state != RtcEventLogState.STARTED) {
Log.e(TAG, "RtcEventLog was not started.");
return;
}
peerConnection.stopRtcEventLog();
state = RtcEventLogState.STOPPED;
Log.d(TAG, "RtcEventLog stopped.");
}
}

View File

@ -53,6 +53,7 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan
private String keyPrefRoomServerUrl;
private String keyPrefDisplayHud;
private String keyPrefTracing;
private String keyprefEnabledRtcEventLog;
private String keyprefEnableDataChannel;
private String keyprefOrdered;
@ -102,6 +103,7 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan
keyPrefRoomServerUrl = getString(R.string.pref_room_server_url_key);
keyPrefDisplayHud = getString(R.string.pref_displayhud_key);
keyPrefTracing = getString(R.string.pref_tracing_key);
keyprefEnabledRtcEventLog = getString(R.string.pref_enable_rtceventlog_key);
// Display the fragment as the main content.
settingsFragment = new SettingsFragment();
@ -158,6 +160,7 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan
updateSummary(sharedPreferences, keyPrefRoomServerUrl);
updateSummaryB(sharedPreferences, keyPrefDisplayHud);
updateSummaryB(sharedPreferences, keyPrefTracing);
updateSummaryB(sharedPreferences, keyprefEnabledRtcEventLog);
if (!Camera2Enumerator.isSupported(this)) {
Preference camera2Preference = settingsFragment.findPreference(keyprefCamera2);
@ -241,7 +244,8 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan
|| key.equals(keyPrefDisplayHud)
|| key.equals(keyprefEnableDataChannel)
|| key.equals(keyprefOrdered)
|| key.equals(keyprefNegotiated)) {
|| key.equals(keyprefNegotiated)
|| key.equals(keyprefEnabledRtcEventLog)) {
updateSummaryB(sharedPreferences, key);
} else if (key.equals(keyprefSpeakerphone)) {
updateSummaryList(sharedPreferences, key);

View File

@ -315,13 +315,13 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
null, null, null, // clientId, wssUrl, wssPostUrl.
null, null); // offerSdp, iceCandidates.
PeerConnectionClient client = new PeerConnectionClient();
PeerConnectionClient client =
new PeerConnectionClient(InstrumentationRegistry.getTargetContext());
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
options.networkIgnoreMask = 0;
options.disableNetworkMonitor = true;
client.setPeerConnectionFactoryOptions(options);
client.createPeerConnectionFactory(
InstrumentationRegistry.getTargetContext(), peerConnectionParameters, this);
client.createPeerConnectionFactory(peerConnectionParameters, this);
client.createPeerConnection(localRenderer, remoteRenderer, videoCapturer, signalingParameters);
client.createOffer();
return client;
@ -345,7 +345,8 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
false, /* noAudioProcessing */
false, /* aecDump */
false /* useOpenSLES */, false /* disableBuiltInAEC */, false /* disableBuiltInAGC */,
false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */);
false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */,
false /* enableRtcEventLog */);
}
private VideoCapturer createCameraCapturer(boolean captureToTexture) {
@ -380,7 +381,8 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
false, /* noAudioProcessing */
false, /* aecDump */
false /* useOpenSLES */, false /* disableBuiltInAEC */, false /* disableBuiltInAGC */,
false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */);
false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */,
false /* enableRtcEventLog */);
}
@Before