Support for video file instead of camera and output video out to file
When video out to file is enabled the remote video which is recorded is not show on screen. You can use this command line for file input and output: monkeyrunner ./webrtc/examples/androidapp/start_loopback_stubbed_camera_saved_video_out.py --devname 02157df28cd47001 --videoin /storage/emulated/0/reference_video_1280x720_30fps.y4m --videoout /storage/emulated/0/output.y4m --videoout_width 1280 --videoout_height 720 --videooutsave /tmp/out.y4m BUG=webrtc:6545 Review-Url: https://codereview.webrtc.org/2273573003 Cr-Commit-Position: refs/heads/master@{#14660}
This commit is contained in:
@ -29,14 +29,26 @@ import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.RuntimeException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.webrtc.Camera1Enumerator;
|
||||
import org.webrtc.Camera2Enumerator;
|
||||
import org.webrtc.CameraEnumerator;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.FileVideoCapturer;
|
||||
import org.webrtc.VideoFileRenderer;
|
||||
import org.webrtc.IceCandidate;
|
||||
import org.webrtc.Logging;
|
||||
import org.webrtc.PeerConnectionFactory;
|
||||
import org.webrtc.RendererCommon.ScalingType;
|
||||
import org.webrtc.SessionDescription;
|
||||
import org.webrtc.StatsReport;
|
||||
import org.webrtc.SurfaceViewRenderer;
|
||||
import org.webrtc.VideoCapturer;
|
||||
import org.webrtc.VideoRenderer;
|
||||
|
||||
/**
|
||||
* Activity for peer connection call setup, call waiting
|
||||
@ -72,6 +84,15 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
public static final String EXTRA_TRACING = "org.appspot.apprtc.TRACING";
|
||||
public static final String EXTRA_CMDLINE = "org.appspot.apprtc.CMDLINE";
|
||||
public static final String EXTRA_RUNTIME = "org.appspot.apprtc.RUNTIME";
|
||||
public static final String EXTRA_VIDEO_FILE_AS_CAMERA = "org.appspot.apprtc.VIDEO_FILE_AS_CAMERA";
|
||||
public static final String EXTRA_SAVE_REMOTE_VIDEO_TO_FILE =
|
||||
"org.appspot.apprtc.SAVE_REMOTE_VIDEO_TO_FILE";
|
||||
public static final String EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH =
|
||||
"org.appspot.apprtc.SAVE_REMOTE_VIDEO_TO_FILE_WIDTH";
|
||||
public static final String EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT =
|
||||
"org.appspot.apprtc.SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT";
|
||||
public static final String EXTRA_USE_VALUES_FROM_INTENT =
|
||||
"org.appspot.apprtc.USE_VALUES_FROM_INTENT";
|
||||
private static final String TAG = "CallRTCClient";
|
||||
|
||||
// List of mandatory application permissions.
|
||||
@ -101,7 +122,10 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
private AppRTCAudioManager audioManager = null;
|
||||
private EglBase rootEglBase;
|
||||
private SurfaceViewRenderer localRender;
|
||||
private SurfaceViewRenderer remoteRender;
|
||||
private SurfaceViewRenderer remoteRenderScreen;
|
||||
private VideoFileRenderer videoFileRenderer;
|
||||
private final List<VideoRenderer.Callbacks> remoteRenderers =
|
||||
new ArrayList<VideoRenderer.Callbacks>();
|
||||
private PercentFrameLayout localRenderLayout;
|
||||
private PercentFrameLayout remoteRenderLayout;
|
||||
private ScalingType scalingType;
|
||||
@ -143,7 +167,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
|
||||
// Create UI controls.
|
||||
localRender = (SurfaceViewRenderer) findViewById(R.id.local_video_view);
|
||||
remoteRender = (SurfaceViewRenderer) findViewById(R.id.remote_video_view);
|
||||
remoteRenderScreen = (SurfaceViewRenderer) findViewById(R.id.remote_video_view);
|
||||
localRenderLayout = (PercentFrameLayout) findViewById(R.id.local_video_layout);
|
||||
remoteRenderLayout = (PercentFrameLayout) findViewById(R.id.remote_video_layout);
|
||||
callFragment = new CallFragment();
|
||||
@ -158,12 +182,31 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
};
|
||||
|
||||
localRender.setOnClickListener(listener);
|
||||
remoteRender.setOnClickListener(listener);
|
||||
remoteRenderScreen.setOnClickListener(listener);
|
||||
remoteRenderers.add(remoteRenderScreen);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
// Create video renderers.
|
||||
rootEglBase = EglBase.create();
|
||||
localRender.init(rootEglBase.getEglBaseContext(), null);
|
||||
remoteRender.init(rootEglBase.getEglBaseContext(), null);
|
||||
String saveRemoteVideoToFile = intent.getStringExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE);
|
||||
|
||||
// When saveRemoteVideoToFile is set we save the video from the remote to a file.
|
||||
if (saveRemoteVideoToFile != null) {
|
||||
int videoOutWidth = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, 0);
|
||||
int videoOutHeight = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, 0);
|
||||
try {
|
||||
videoFileRenderer = new VideoFileRenderer(
|
||||
saveRemoteVideoToFile, videoOutWidth, videoOutHeight, rootEglBase.getEglBaseContext());
|
||||
remoteRenderers.add(videoFileRenderer);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to open video file for output: " + saveRemoteVideoToFile, e);
|
||||
}
|
||||
}
|
||||
remoteRenderScreen.init(rootEglBase.getEglBaseContext(), null);
|
||||
|
||||
localRender.setZOrderMediaOverlay(true);
|
||||
updateVideoView();
|
||||
|
||||
@ -177,8 +220,6 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
}
|
||||
}
|
||||
|
||||
// Get Intent parameters.
|
||||
final Intent intent = getIntent();
|
||||
Uri roomUri = intent.getData();
|
||||
if (roomUri == null) {
|
||||
logAndToast(getString(R.string.missing_url));
|
||||
@ -187,7 +228,10 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Intent parameters.
|
||||
String roomId = intent.getStringExtra(EXTRA_ROOMID);
|
||||
Log.d(TAG, "Room ID: " + roomId);
|
||||
if (roomId == null || roomId.length() == 0) {
|
||||
logAndToast(getString(R.string.missing_url));
|
||||
Log.e(TAG, "Incorrect room ID in intent!");
|
||||
@ -199,16 +243,12 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
boolean loopback = intent.getBooleanExtra(EXTRA_LOOPBACK, false);
|
||||
boolean tracing = intent.getBooleanExtra(EXTRA_TRACING, false);
|
||||
|
||||
boolean useCamera2 =
|
||||
Camera2Enumerator.isSupported(this) && intent.getBooleanExtra(EXTRA_CAMERA2, true);
|
||||
|
||||
peerConnectionParameters =
|
||||
new PeerConnectionParameters(intent.getBooleanExtra(EXTRA_VIDEO_CALL, true), loopback,
|
||||
tracing, useCamera2, intent.getIntExtra(EXTRA_VIDEO_WIDTH, 0),
|
||||
tracing, intent.getIntExtra(EXTRA_VIDEO_WIDTH, 0),
|
||||
intent.getIntExtra(EXTRA_VIDEO_HEIGHT, 0), intent.getIntExtra(EXTRA_VIDEO_FPS, 0),
|
||||
intent.getIntExtra(EXTRA_VIDEO_BITRATE, 0), intent.getStringExtra(EXTRA_VIDEOCODEC),
|
||||
intent.getBooleanExtra(EXTRA_HWCODEC_ENABLED, true),
|
||||
intent.getBooleanExtra(EXTRA_CAPTURETOTEXTURE_ENABLED, false),
|
||||
intent.getIntExtra(EXTRA_AUDIO_BITRATE, 0), intent.getStringExtra(EXTRA_AUDIOCODEC),
|
||||
intent.getBooleanExtra(EXTRA_NOAUDIOPROCESSING_ENABLED, false),
|
||||
intent.getBooleanExtra(EXTRA_AECDUMP_ENABLED, false),
|
||||
@ -220,6 +260,8 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
commandLineRun = intent.getBooleanExtra(EXTRA_CMDLINE, false);
|
||||
runTimeMs = intent.getIntExtra(EXTRA_RUNTIME, 0);
|
||||
|
||||
Log.d(TAG, "VIDEO_FILE: '" + intent.getStringExtra(EXTRA_VIDEO_FILE_AS_CAMERA) + "'");
|
||||
|
||||
// Create connection client. Use DirectRTCClient if room name is an IP otherwise use the
|
||||
// standard WebSocketRTCClient.
|
||||
if (loopback || !DirectRTCClient.IP_PATTERN.matcher(roomId).matches()) {
|
||||
@ -265,6 +307,46 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
CallActivity.this, peerConnectionParameters, CallActivity.this);
|
||||
}
|
||||
|
||||
private boolean useCamera2() {
|
||||
return Camera2Enumerator.isSupported(this) && getIntent().getBooleanExtra(EXTRA_CAMERA2, true);
|
||||
}
|
||||
|
||||
private boolean captureToTexture() {
|
||||
return getIntent().getBooleanExtra(EXTRA_CAPTURETOTEXTURE_ENABLED, false);
|
||||
}
|
||||
|
||||
private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
|
||||
final String[] deviceNames = enumerator.getDeviceNames();
|
||||
|
||||
// First, try to find front facing camera
|
||||
Logging.d(TAG, "Looking for front facing cameras.");
|
||||
for (String deviceName : deviceNames) {
|
||||
if (enumerator.isFrontFacing(deviceName)) {
|
||||
Logging.d(TAG, "Creating front facing camera capturer.");
|
||||
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
return videoCapturer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Front facing camera not found, try something else
|
||||
Logging.d(TAG, "Looking for other cameras.");
|
||||
for (String deviceName : deviceNames) {
|
||||
if (!enumerator.isFrontFacing(deviceName)) {
|
||||
Logging.d(TAG, "Creating other camera capturer.");
|
||||
VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
return videoCapturer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Activity interfaces
|
||||
@Override
|
||||
public void onPause() {
|
||||
@ -353,8 +435,8 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
|
||||
private void updateVideoView() {
|
||||
remoteRenderLayout.setPosition(REMOTE_X, REMOTE_Y, REMOTE_WIDTH, REMOTE_HEIGHT);
|
||||
remoteRender.setScalingType(scalingType);
|
||||
remoteRender.setMirror(false);
|
||||
remoteRenderScreen.setScalingType(scalingType);
|
||||
remoteRenderScreen.setMirror(false);
|
||||
|
||||
if (iceConnected) {
|
||||
localRenderLayout.setPosition(
|
||||
@ -368,7 +450,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
localRender.setMirror(true);
|
||||
|
||||
localRender.requestLayout();
|
||||
remoteRender.requestLayout();
|
||||
remoteRenderScreen.requestLayout();
|
||||
}
|
||||
|
||||
private void startCall() {
|
||||
@ -432,9 +514,13 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
localRender.release();
|
||||
localRender = null;
|
||||
}
|
||||
if (remoteRender != null) {
|
||||
remoteRender.release();
|
||||
remoteRender = null;
|
||||
if (videoFileRenderer != null) {
|
||||
videoFileRenderer.release();
|
||||
videoFileRenderer = null;
|
||||
}
|
||||
if (remoteRenderScreen != null) {
|
||||
remoteRenderScreen.release();
|
||||
remoteRenderScreen = null;
|
||||
}
|
||||
if (audioManager != null) {
|
||||
audioManager.close();
|
||||
@ -492,6 +578,35 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
});
|
||||
}
|
||||
|
||||
private VideoCapturer createVideoCapturer() {
|
||||
VideoCapturer videoCapturer = null;
|
||||
String videoFileAsCamera = getIntent().getStringExtra(EXTRA_VIDEO_FILE_AS_CAMERA);
|
||||
if (videoFileAsCamera != null) {
|
||||
try {
|
||||
videoCapturer = new FileVideoCapturer(videoFileAsCamera);
|
||||
} catch (IOException e) {
|
||||
reportError("Failed to open video file for emulated camera");
|
||||
return null;
|
||||
}
|
||||
} else if (useCamera2()) {
|
||||
if (!captureToTexture()) {
|
||||
reportError(getString(R.string.camera2_texture_only_error));
|
||||
return null;
|
||||
}
|
||||
|
||||
Logging.d(TAG, "Creating capturer using camera2 API.");
|
||||
videoCapturer = createCameraCapturer(new Camera2Enumerator(this));
|
||||
} else {
|
||||
Logging.d(TAG, "Creating capturer using camera1 API.");
|
||||
videoCapturer = createCameraCapturer(new Camera1Enumerator(captureToTexture()));
|
||||
}
|
||||
if (videoCapturer == null) {
|
||||
reportError("Failed to open camera");
|
||||
return null;
|
||||
}
|
||||
return videoCapturer;
|
||||
}
|
||||
|
||||
// -----Implementation of AppRTCClient.AppRTCSignalingEvents ---------------
|
||||
// All callbacks are invoked from websocket signaling looper thread and
|
||||
// are routed to UI thread.
|
||||
@ -500,8 +615,12 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven
|
||||
|
||||
signalingParameters = params;
|
||||
logAndToast("Creating peer connection, delay=" + delta + "ms");
|
||||
peerConnectionClient.createPeerConnection(
|
||||
rootEglBase.getEglBaseContext(), localRender, remoteRender, signalingParameters);
|
||||
VideoCapturer videoCapturer = null;
|
||||
if (peerConnectionParameters.videoCallEnabled) {
|
||||
videoCapturer = createVideoCapturer();
|
||||
}
|
||||
peerConnectionClient.createPeerConnection(rootEglBase.getEglBaseContext(), localRender,
|
||||
remoteRenderers, videoCapturer, signalingParameters);
|
||||
|
||||
if (signalingParameters.initiator) {
|
||||
logAndToast("Creating OFFER...");
|
||||
|
||||
@ -144,8 +144,10 @@ public class ConnectActivity extends Activity {
|
||||
if ("android.intent.action.VIEW".equals(intent.getAction()) && !commandLineRun) {
|
||||
boolean loopback = intent.getBooleanExtra(CallActivity.EXTRA_LOOPBACK, false);
|
||||
int runTimeMs = intent.getIntExtra(CallActivity.EXTRA_RUNTIME, 0);
|
||||
boolean useValuesFromIntent =
|
||||
intent.getBooleanExtra(CallActivity.EXTRA_USE_VALUES_FROM_INTENT, false);
|
||||
String room = sharedPref.getString(keyprefRoom, "");
|
||||
connectToRoom(room, true, loopback, runTimeMs);
|
||||
connectToRoom(room, true, loopback, useValuesFromIntent, runTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +192,7 @@ public class ConnectActivity extends Activity {
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_loopback) {
|
||||
connectToRoom(null, false, true, 0);
|
||||
connectToRoom(null, false, true, false, 0);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
@ -243,8 +245,42 @@ public class ConnectActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void connectToRoom(
|
||||
String roomId, boolean commandLineRun, boolean loopback, int runTimeMs) {
|
||||
/**
|
||||
* Get a value from the shared preference or from the intent, if it does not
|
||||
* exist the default is used.
|
||||
*/
|
||||
private String sharedPrefGetString(
|
||||
int attributeId, String intentName, int defaultId, boolean useFromIntent) {
|
||||
String defaultValue = getString(defaultId);
|
||||
if (useFromIntent) {
|
||||
String value = getIntent().getStringExtra(intentName);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
} else {
|
||||
String attributeName = getString(attributeId);
|
||||
return sharedPref.getString(attributeName, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the shared preference or from the intent, if it does not
|
||||
* exist the default is used.
|
||||
*/
|
||||
private boolean sharedPrefGetBoolean(
|
||||
int attributeId, String intentName, int defaultId, boolean useFromIntent) {
|
||||
boolean defaultValue = Boolean.valueOf(getString(defaultId));
|
||||
if (useFromIntent) {
|
||||
return getIntent().getBooleanExtra(intentName, defaultValue);
|
||||
} else {
|
||||
String attributeName = getString(attributeId);
|
||||
return sharedPref.getBoolean(attributeName, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectToRoom(String roomId, boolean commandLineRun, boolean loopback,
|
||||
boolean useValuesFromIntent, int runTimeMs) {
|
||||
this.commandLineRun = commandLineRun;
|
||||
|
||||
// roomId is random for loopback.
|
||||
@ -256,112 +292,142 @@ public class ConnectActivity extends Activity {
|
||||
keyprefRoomServerUrl, getString(R.string.pref_room_server_url_default));
|
||||
|
||||
// Video call enabled flag.
|
||||
boolean videoCallEnabled = sharedPref.getBoolean(
|
||||
keyprefVideoCallEnabled, Boolean.valueOf(getString(R.string.pref_videocall_default)));
|
||||
boolean videoCallEnabled = sharedPrefGetBoolean(R.string.pref_videocall_key,
|
||||
CallActivity.EXTRA_VIDEO_CALL, R.string.pref_videocall_default, useValuesFromIntent);
|
||||
|
||||
// Use Camera2 option.
|
||||
boolean useCamera2 = sharedPref.getBoolean(
|
||||
keyprefCamera2, Boolean.valueOf(getString(R.string.pref_camera2_default)));
|
||||
boolean useCamera2 = sharedPrefGetBoolean(R.string.pref_camera2_key, CallActivity.EXTRA_CAMERA2,
|
||||
R.string.pref_camera2_default, useValuesFromIntent);
|
||||
|
||||
// Get default codecs.
|
||||
String videoCodec =
|
||||
sharedPref.getString(keyprefVideoCodec, getString(R.string.pref_videocodec_default));
|
||||
String audioCodec =
|
||||
sharedPref.getString(keyprefAudioCodec, getString(R.string.pref_audiocodec_default));
|
||||
String videoCodec = sharedPrefGetString(R.string.pref_videocodec_key,
|
||||
CallActivity.EXTRA_VIDEOCODEC, R.string.pref_videocodec_default, useValuesFromIntent);
|
||||
String audioCodec = sharedPrefGetString(R.string.pref_audiocodec_key,
|
||||
CallActivity.EXTRA_AUDIOCODEC, R.string.pref_audiocodec_default, useValuesFromIntent);
|
||||
|
||||
// Check HW codec flag.
|
||||
boolean hwCodec = sharedPref.getBoolean(
|
||||
keyprefHwCodecAcceleration, Boolean.valueOf(getString(R.string.pref_hwcodec_default)));
|
||||
boolean hwCodec = sharedPrefGetBoolean(R.string.pref_hwcodec_key,
|
||||
CallActivity.EXTRA_HWCODEC_ENABLED, R.string.pref_hwcodec_default, useValuesFromIntent);
|
||||
|
||||
// Check Capture to texture.
|
||||
boolean captureToTexture = sharedPref.getBoolean(keyprefCaptureToTexture,
|
||||
Boolean.valueOf(getString(R.string.pref_capturetotexture_default)));
|
||||
boolean captureToTexture = sharedPrefGetBoolean(R.string.pref_capturetotexture_key,
|
||||
CallActivity.EXTRA_CAPTURETOTEXTURE_ENABLED, R.string.pref_capturetotexture_default,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Check Disable Audio Processing flag.
|
||||
boolean noAudioProcessing = sharedPref.getBoolean(keyprefNoAudioProcessingPipeline,
|
||||
Boolean.valueOf(getString(R.string.pref_noaudioprocessing_default)));
|
||||
boolean noAudioProcessing = sharedPrefGetBoolean(R.string.pref_noaudioprocessing_key,
|
||||
CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, R.string.pref_noaudioprocessing_default,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Check Disable Audio Processing flag.
|
||||
boolean aecDump = sharedPref.getBoolean(
|
||||
keyprefAecDump, Boolean.valueOf(getString(R.string.pref_aecdump_default)));
|
||||
boolean aecDump = sharedPrefGetBoolean(R.string.pref_aecdump_key,
|
||||
CallActivity.EXTRA_AECDUMP_ENABLED, R.string.pref_aecdump_default, useValuesFromIntent);
|
||||
|
||||
// Check OpenSL ES enabled flag.
|
||||
boolean useOpenSLES = sharedPref.getBoolean(
|
||||
keyprefOpenSLES, Boolean.valueOf(getString(R.string.pref_opensles_default)));
|
||||
boolean useOpenSLES = sharedPrefGetBoolean(R.string.pref_opensles_key,
|
||||
CallActivity.EXTRA_OPENSLES_ENABLED, R.string.pref_opensles_default, useValuesFromIntent);
|
||||
|
||||
// Check Disable built-in AEC flag.
|
||||
boolean disableBuiltInAEC = sharedPref.getBoolean(keyprefDisableBuiltInAec,
|
||||
Boolean.valueOf(getString(R.string.pref_disable_built_in_aec_default)));
|
||||
boolean disableBuiltInAEC = sharedPrefGetBoolean(R.string.pref_disable_built_in_aec_key,
|
||||
CallActivity.EXTRA_DISABLE_BUILT_IN_AEC, R.string.pref_disable_built_in_aec_default,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Check Disable built-in AGC flag.
|
||||
boolean disableBuiltInAGC = sharedPref.getBoolean(keyprefDisableBuiltInAgc,
|
||||
Boolean.valueOf(getString(R.string.pref_disable_built_in_agc_default)));
|
||||
boolean disableBuiltInAGC = sharedPrefGetBoolean(R.string.pref_disable_built_in_agc_key,
|
||||
CallActivity.EXTRA_DISABLE_BUILT_IN_AGC, R.string.pref_disable_built_in_agc_default,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Check Disable built-in NS flag.
|
||||
boolean disableBuiltInNS = sharedPref.getBoolean(keyprefDisableBuiltInNs,
|
||||
Boolean.valueOf(getString(R.string.pref_disable_built_in_ns_default)));
|
||||
boolean disableBuiltInNS = sharedPrefGetBoolean(R.string.pref_disable_built_in_ns_key,
|
||||
CallActivity.EXTRA_DISABLE_BUILT_IN_NS, R.string.pref_disable_built_in_ns_default,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Check Enable level control.
|
||||
boolean enableLevelControl = sharedPref.getBoolean(keyprefEnableLevelControl,
|
||||
Boolean.valueOf(getString(R.string.pref_enable_level_control_key)));
|
||||
boolean enableLevelControl = sharedPrefGetBoolean(R.string.pref_enable_level_control_key,
|
||||
CallActivity.EXTRA_ENABLE_LEVEL_CONTROL, R.string.pref_enable_level_control_key,
|
||||
useValuesFromIntent);
|
||||
|
||||
// Get video resolution from settings.
|
||||
int videoWidth = 0;
|
||||
int videoHeight = 0;
|
||||
String resolution =
|
||||
sharedPref.getString(keyprefResolution, getString(R.string.pref_resolution_default));
|
||||
String[] dimensions = resolution.split("[ x]+");
|
||||
if (dimensions.length == 2) {
|
||||
try {
|
||||
videoWidth = Integer.parseInt(dimensions[0]);
|
||||
videoHeight = Integer.parseInt(dimensions[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
videoWidth = 0;
|
||||
videoHeight = 0;
|
||||
Log.e(TAG, "Wrong video resolution setting: " + resolution);
|
||||
if (useValuesFromIntent) {
|
||||
videoWidth = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_WIDTH, 0);
|
||||
videoHeight = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_HEIGHT, 0);
|
||||
}
|
||||
if (videoWidth == 0 && videoHeight == 0) {
|
||||
String resolution =
|
||||
sharedPref.getString(keyprefResolution, getString(R.string.pref_resolution_default));
|
||||
String[] dimensions = resolution.split("[ x]+");
|
||||
if (dimensions.length == 2) {
|
||||
try {
|
||||
videoWidth = Integer.parseInt(dimensions[0]);
|
||||
videoHeight = Integer.parseInt(dimensions[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
videoWidth = 0;
|
||||
videoHeight = 0;
|
||||
Log.e(TAG, "Wrong video resolution setting: " + resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get camera fps from settings.
|
||||
int cameraFps = 0;
|
||||
String fps = sharedPref.getString(keyprefFps, getString(R.string.pref_fps_default));
|
||||
String[] fpsValues = fps.split("[ x]+");
|
||||
if (fpsValues.length == 2) {
|
||||
try {
|
||||
cameraFps = Integer.parseInt(fpsValues[0]);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Wrong camera fps setting: " + fps);
|
||||
if (useValuesFromIntent) {
|
||||
cameraFps = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_FPS, 0);
|
||||
}
|
||||
if (cameraFps == 0) {
|
||||
String fps = sharedPref.getString(keyprefFps, getString(R.string.pref_fps_default));
|
||||
String[] fpsValues = fps.split("[ x]+");
|
||||
if (fpsValues.length == 2) {
|
||||
try {
|
||||
cameraFps = Integer.parseInt(fpsValues[0]);
|
||||
} catch (NumberFormatException e) {
|
||||
cameraFps = 0;
|
||||
Log.e(TAG, "Wrong camera fps setting: " + fps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check capture quality slider flag.
|
||||
boolean captureQualitySlider = sharedPref.getBoolean(keyprefCaptureQualitySlider,
|
||||
Boolean.valueOf(getString(R.string.pref_capturequalityslider_default)));
|
||||
boolean captureQualitySlider = sharedPrefGetBoolean(R.string.pref_capturequalityslider_key,
|
||||
CallActivity.EXTRA_VIDEO_CAPTUREQUALITYSLIDER_ENABLED,
|
||||
R.string.pref_capturequalityslider_default, useValuesFromIntent);
|
||||
|
||||
// Get video and audio start bitrate.
|
||||
int videoStartBitrate = 0;
|
||||
String bitrateTypeDefault = getString(R.string.pref_maxvideobitrate_default);
|
||||
String bitrateType = sharedPref.getString(keyprefVideoBitrateType, bitrateTypeDefault);
|
||||
if (!bitrateType.equals(bitrateTypeDefault)) {
|
||||
String bitrateValue = sharedPref.getString(
|
||||
keyprefVideoBitrateValue, getString(R.string.pref_maxvideobitratevalue_default));
|
||||
videoStartBitrate = Integer.parseInt(bitrateValue);
|
||||
if (useValuesFromIntent) {
|
||||
videoStartBitrate = getIntent().getIntExtra(CallActivity.EXTRA_VIDEO_BITRATE, 0);
|
||||
}
|
||||
if (videoStartBitrate == 0) {
|
||||
String bitrateTypeDefault = getString(R.string.pref_maxvideobitrate_default);
|
||||
String bitrateType = sharedPref.getString(keyprefVideoBitrateType, bitrateTypeDefault);
|
||||
if (!bitrateType.equals(bitrateTypeDefault)) {
|
||||
String bitrateValue = sharedPref.getString(
|
||||
keyprefVideoBitrateValue, getString(R.string.pref_maxvideobitratevalue_default));
|
||||
videoStartBitrate = Integer.parseInt(bitrateValue);
|
||||
}
|
||||
}
|
||||
|
||||
int audioStartBitrate = 0;
|
||||
bitrateTypeDefault = getString(R.string.pref_startaudiobitrate_default);
|
||||
bitrateType = sharedPref.getString(keyprefAudioBitrateType, bitrateTypeDefault);
|
||||
if (!bitrateType.equals(bitrateTypeDefault)) {
|
||||
String bitrateValue = sharedPref.getString(
|
||||
keyprefAudioBitrateValue, getString(R.string.pref_startaudiobitratevalue_default));
|
||||
audioStartBitrate = Integer.parseInt(bitrateValue);
|
||||
if (useValuesFromIntent) {
|
||||
audioStartBitrate = getIntent().getIntExtra(CallActivity.EXTRA_AUDIO_BITRATE, 0);
|
||||
}
|
||||
if (audioStartBitrate == 0) {
|
||||
String bitrateTypeDefault = getString(R.string.pref_startaudiobitrate_default);
|
||||
String bitrateType = sharedPref.getString(keyprefAudioBitrateType, bitrateTypeDefault);
|
||||
if (!bitrateType.equals(bitrateTypeDefault)) {
|
||||
String bitrateValue = sharedPref.getString(
|
||||
keyprefAudioBitrateValue, getString(R.string.pref_startaudiobitratevalue_default));
|
||||
audioStartBitrate = Integer.parseInt(bitrateValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Check statistics display option.
|
||||
boolean displayHud = sharedPref.getBoolean(
|
||||
keyprefDisplayHud, Boolean.valueOf(getString(R.string.pref_displayhud_default)));
|
||||
boolean displayHud = sharedPrefGetBoolean(R.string.pref_displayhud_key,
|
||||
CallActivity.EXTRA_DISPLAY_HUD, R.string.pref_displayhud_default, useValuesFromIntent);
|
||||
|
||||
boolean tracing = sharedPref.getBoolean(
|
||||
keyprefTracing, Boolean.valueOf(getString(R.string.pref_tracing_default)));
|
||||
boolean tracing = sharedPrefGetBoolean(R.string.pref_tracing_key, CallActivity.EXTRA_TRACING,
|
||||
R.string.pref_tracing_default, useValuesFromIntent);
|
||||
|
||||
// Start AppRTCMobile activity.
|
||||
Log.d(TAG, "Connecting to room " + roomId + " at URL " + roomUrl);
|
||||
@ -395,6 +461,32 @@ public class ConnectActivity extends Activity {
|
||||
intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun);
|
||||
intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs);
|
||||
|
||||
if (useValuesFromIntent) {
|
||||
if (getIntent().hasExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA)) {
|
||||
String videoFileAsCamera =
|
||||
getIntent().getStringExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA);
|
||||
intent.putExtra(CallActivity.EXTRA_VIDEO_FILE_AS_CAMERA, videoFileAsCamera);
|
||||
}
|
||||
|
||||
if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE)) {
|
||||
String saveRemoteVideoToFile =
|
||||
getIntent().getStringExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE);
|
||||
intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE, saveRemoteVideoToFile);
|
||||
}
|
||||
|
||||
if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH)) {
|
||||
int videoOutWidth =
|
||||
getIntent().getIntExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, 0);
|
||||
intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, videoOutWidth);
|
||||
}
|
||||
|
||||
if (getIntent().hasExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT)) {
|
||||
int videoOutHeight =
|
||||
getIntent().getIntExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, 0);
|
||||
intent.putExtra(CallActivity.EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, videoOutHeight);
|
||||
}
|
||||
}
|
||||
|
||||
startActivityForResult(intent, CONNECTION_REQUEST);
|
||||
}
|
||||
}
|
||||
@ -424,7 +516,7 @@ public class ConnectActivity extends Activity {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
String roomId = ((TextView) view).getText().toString();
|
||||
connectToRoom(roomId, false, false, 0);
|
||||
connectToRoom(roomId, false, false, false, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -442,7 +534,7 @@ public class ConnectActivity extends Activity {
|
||||
private final OnClickListener connectListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
connectToRoom(roomEditText.getText().toString(), false, false, 0);
|
||||
connectToRoom(roomEditText.getText().toString(), false, false, false, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -41,6 +41,9 @@ import org.webrtc.StatsObserver;
|
||||
import org.webrtc.StatsReport;
|
||||
import org.webrtc.VideoCapturer;
|
||||
import org.webrtc.VideoRenderer;
|
||||
import org.webrtc.VideoCapturerAndroid;
|
||||
import org.webrtc.CameraVideoCapturer;
|
||||
import org.webrtc.FileVideoCapturer;
|
||||
import org.webrtc.VideoSource;
|
||||
import org.webrtc.VideoTrack;
|
||||
import org.webrtc.voiceengine.WebRtcAudioManager;
|
||||
@ -48,8 +51,10 @@ import org.webrtc.voiceengine.WebRtcAudioUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -107,7 +112,7 @@ public class PeerConnectionClient {
|
||||
private boolean isError;
|
||||
private Timer statsTimer;
|
||||
private VideoRenderer.Callbacks localRender;
|
||||
private VideoRenderer.Callbacks remoteRender;
|
||||
private List<VideoRenderer.Callbacks> remoteRenders;
|
||||
private SignalingParameters signalingParameters;
|
||||
private MediaConstraints pcConstraints;
|
||||
private int videoWidth;
|
||||
@ -126,7 +131,7 @@ public class PeerConnectionClient {
|
||||
private SessionDescription localSdp; // either offer or answer SDP
|
||||
private MediaStream mediaStream;
|
||||
private int numberOfCameras;
|
||||
private CameraVideoCapturer videoCapturer;
|
||||
private VideoCapturer videoCapturer;
|
||||
// enableVideo is set to true if video should be rendered and sent.
|
||||
private boolean renderVideo;
|
||||
private VideoTrack localVideoTrack;
|
||||
@ -143,14 +148,12 @@ public class PeerConnectionClient {
|
||||
public final boolean videoCallEnabled;
|
||||
public final boolean loopback;
|
||||
public final boolean tracing;
|
||||
public final boolean useCamera2;
|
||||
public final int videoWidth;
|
||||
public final int videoHeight;
|
||||
public final int videoFps;
|
||||
public final int videoMaxBitrate;
|
||||
public final String videoCodec;
|
||||
public final boolean videoCodecHwAcceleration;
|
||||
public final boolean captureToTexture;
|
||||
public final int audioStartBitrate;
|
||||
public final String audioCodec;
|
||||
public final boolean noAudioProcessing;
|
||||
@ -162,13 +165,11 @@ public class PeerConnectionClient {
|
||||
public final boolean enableLevelControl;
|
||||
|
||||
public PeerConnectionParameters(boolean videoCallEnabled, boolean loopback, boolean tracing,
|
||||
boolean useCamera2, int videoWidth, int videoHeight, int videoFps, int videoMaxBitrate,
|
||||
String videoCodec, boolean videoCodecHwAcceleration, boolean captureToTexture,
|
||||
int audioStartBitrate, String audioCodec, boolean noAudioProcessing, boolean aecDump,
|
||||
boolean useOpenSLES, boolean disableBuiltInAEC, boolean disableBuiltInAGC,
|
||||
boolean disableBuiltInNS, boolean enableLevelControl) {
|
||||
int videoWidth, int videoHeight, int videoFps, int videoMaxBitrate, String videoCodec,
|
||||
boolean videoCodecHwAcceleration, int audioStartBitrate, String audioCodec,
|
||||
boolean noAudioProcessing, boolean aecDump, boolean useOpenSLES, boolean disableBuiltInAEC,
|
||||
boolean disableBuiltInAGC, boolean disableBuiltInNS, boolean enableLevelControl) {
|
||||
this.videoCallEnabled = videoCallEnabled;
|
||||
this.useCamera2 = useCamera2;
|
||||
this.loopback = loopback;
|
||||
this.tracing = tracing;
|
||||
this.videoWidth = videoWidth;
|
||||
@ -177,7 +178,6 @@ public class PeerConnectionClient {
|
||||
this.videoMaxBitrate = videoMaxBitrate;
|
||||
this.videoCodec = videoCodec;
|
||||
this.videoCodecHwAcceleration = videoCodecHwAcceleration;
|
||||
this.captureToTexture = captureToTexture;
|
||||
this.audioStartBitrate = audioStartBitrate;
|
||||
this.audioCodec = audioCodec;
|
||||
this.noAudioProcessing = noAudioProcessing;
|
||||
@ -286,13 +286,20 @@ public class PeerConnectionClient {
|
||||
|
||||
public void createPeerConnection(final EglBase.Context renderEGLContext,
|
||||
final VideoRenderer.Callbacks localRender, final VideoRenderer.Callbacks remoteRender,
|
||||
final SignalingParameters signalingParameters) {
|
||||
final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) {
|
||||
createPeerConnection(renderEGLContext, localRender, Collections.singletonList(remoteRender),
|
||||
videoCapturer, signalingParameters);
|
||||
}
|
||||
public void createPeerConnection(final EglBase.Context renderEGLContext,
|
||||
final VideoRenderer.Callbacks localRender, final List<VideoRenderer.Callbacks> remoteRenders,
|
||||
final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) {
|
||||
if (peerConnectionParameters == null) {
|
||||
Log.e(TAG, "Creating peer connection without initializing factory.");
|
||||
return;
|
||||
}
|
||||
this.localRender = localRender;
|
||||
this.remoteRender = remoteRender;
|
||||
this.remoteRenders = remoteRenders;
|
||||
this.videoCapturer = videoCapturer;
|
||||
this.signalingParameters = signalingParameters;
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
@ -468,36 +475,6 @@ public class PeerConnectionClient {
|
||||
}
|
||||
}
|
||||
|
||||
private void createCapturer(CameraEnumerator enumerator) {
|
||||
final String[] deviceNames = enumerator.getDeviceNames();
|
||||
|
||||
// First, try to find front facing camera
|
||||
Logging.d(TAG, "Looking for front facing cameras.");
|
||||
for (String deviceName : deviceNames) {
|
||||
if (enumerator.isFrontFacing(deviceName)) {
|
||||
Logging.d(TAG, "Creating front facing camera capturer.");
|
||||
videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Front facing camera not found, try something else
|
||||
Logging.d(TAG, "Looking for other cameras.");
|
||||
for (String deviceName : deviceNames) {
|
||||
if (!enumerator.isFrontFacing(deviceName)) {
|
||||
Logging.d(TAG, "Creating other camera capturer.");
|
||||
videoCapturer = enumerator.createCapturer(deviceName, null);
|
||||
|
||||
if (videoCapturer != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createPeerConnectionInternal(EglBase.Context renderEGLContext) {
|
||||
if (factory == null || isError) {
|
||||
Log.e(TAG, "Peerconnection factory is not created");
|
||||
@ -534,23 +511,6 @@ public class PeerConnectionClient {
|
||||
|
||||
mediaStream = factory.createLocalMediaStream("ARDAMS");
|
||||
if (videoCallEnabled) {
|
||||
if (peerConnectionParameters.useCamera2) {
|
||||
if (!peerConnectionParameters.captureToTexture) {
|
||||
reportError(context.getString(R.string.camera2_texture_only_error));
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.d(TAG, "Creating capturer using camera2 API.");
|
||||
createCapturer(new Camera2Enumerator(context));
|
||||
} else {
|
||||
Logging.d(TAG, "Creating capturer using camera1 API.");
|
||||
createCapturer(new Camera1Enumerator(peerConnectionParameters.captureToTexture));
|
||||
}
|
||||
|
||||
if (videoCapturer == null) {
|
||||
reportError("Failed to open camera");
|
||||
return;
|
||||
}
|
||||
mediaStream.addTrack(createVideoTrack(videoCapturer));
|
||||
}
|
||||
|
||||
@ -1003,13 +963,18 @@ public class PeerConnectionClient {
|
||||
}
|
||||
|
||||
private void switchCameraInternal() {
|
||||
if (!videoCallEnabled || numberOfCameras < 2 || isError || videoCapturer == null) {
|
||||
Log.e(TAG, "Failed to switch camera. Video: " + videoCallEnabled + ". Error : " + isError
|
||||
+ ". Number of cameras: " + numberOfCameras);
|
||||
return; // No video is sent or only one camera is available or error happened.
|
||||
if (videoCapturer instanceof CameraVideoCapturer) {
|
||||
if (!videoCallEnabled || numberOfCameras < 2 || isError || videoCapturer == null) {
|
||||
Log.e(TAG, "Failed to switch camera. Video: " + videoCallEnabled + ". Error : " + isError
|
||||
+ ". Number of cameras: " + numberOfCameras);
|
||||
return; // No video is sent or only one camera is available or error happened.
|
||||
}
|
||||
Log.d(TAG, "Switch camera");
|
||||
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
|
||||
cameraVideoCapturer.switchCamera(null);
|
||||
} else {
|
||||
Log.d(TAG, "Will not switch camera, video caputurer is not a camera");
|
||||
}
|
||||
Log.d(TAG, "Switch camera");
|
||||
videoCapturer.switchCamera(null);
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
@ -1109,7 +1074,9 @@ public class PeerConnectionClient {
|
||||
if (stream.videoTracks.size() == 1) {
|
||||
remoteVideoTrack = stream.videoTracks.get(0);
|
||||
remoteVideoTrack.setEnabled(renderVideo);
|
||||
remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender));
|
||||
for (VideoRenderer.Callbacks remoteRender : remoteRenders) {
|
||||
remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user