mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 19:49:33 +01:00
Some work
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
526e4d1f9e
commit
f26c38444b
@ -20,21 +20,39 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.activities;
|
package com.nextcloud.talk.activities;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.bluelinelabs.conductor.Conductor;
|
import com.gun0912.tedpermission.PermissionListener;
|
||||||
import com.bluelinelabs.conductor.Router;
|
import com.gun0912.tedpermission.TedPermission;
|
||||||
import com.bluelinelabs.conductor.RouterTransaction;
|
|
||||||
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
|
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.CallController;
|
import com.nextcloud.talk.webrtc.MagicPeerConnectionObserver;
|
||||||
import com.nextcloud.talk.utils.bundle.BundleBuilder;
|
import com.nextcloud.talk.webrtc.MagicSdpObserver;
|
||||||
|
|
||||||
|
import org.webrtc.AudioSource;
|
||||||
|
import org.webrtc.AudioTrack;
|
||||||
|
import org.webrtc.Camera1Enumerator;
|
||||||
|
import org.webrtc.CameraEnumerator;
|
||||||
|
import org.webrtc.IceCandidate;
|
||||||
|
import org.webrtc.Logging;
|
||||||
|
import org.webrtc.MediaConstraints;
|
||||||
|
import org.webrtc.MediaStream;
|
||||||
|
import org.webrtc.PeerConnection;
|
||||||
|
import org.webrtc.PeerConnectionFactory;
|
||||||
|
import org.webrtc.SessionDescription;
|
||||||
|
import org.webrtc.SurfaceViewRenderer;
|
||||||
|
import org.webrtc.VideoCapturer;
|
||||||
|
import org.webrtc.VideoRenderer;
|
||||||
|
import org.webrtc.VideoSource;
|
||||||
|
import org.webrtc.VideoTrack;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
@ -44,14 +62,29 @@ import butterknife.ButterKnife;
|
|||||||
public class CallActivity extends AppCompatActivity {
|
public class CallActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "CallActivity";
|
private static final String TAG = "CallActivity";
|
||||||
|
|
||||||
@BindView(R.id.controller_container)
|
@BindView(R.id.pip_video_view)
|
||||||
ViewGroup container;
|
SurfaceViewRenderer pipVideoView;
|
||||||
|
|
||||||
private Router router;
|
@BindView(R.id.fullscreen_video_view)
|
||||||
|
SurfaceViewRenderer fullScreenVideoView;
|
||||||
|
|
||||||
private String roomToken;
|
private String roomToken;
|
||||||
private String userDisplayName;
|
private String userDisplayName;
|
||||||
|
|
||||||
|
PeerConnectionFactory peerConnectionFactory;
|
||||||
|
MediaConstraints audioConstraints;
|
||||||
|
MediaConstraints videoConstraints;
|
||||||
|
MediaConstraints sdpConstraints;
|
||||||
|
VideoSource videoSource;
|
||||||
|
VideoTrack localVideoTrack;
|
||||||
|
AudioSource audioSource;
|
||||||
|
AudioTrack localAudioTrack;
|
||||||
|
|
||||||
|
VideoRenderer localRenderer;
|
||||||
|
VideoRenderer remoteRenderer;
|
||||||
|
|
||||||
|
PeerConnection localPeer, remotePeer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -70,26 +103,221 @@ public class CallActivity extends AppCompatActivity {
|
|||||||
roomToken = getIntent().getExtras().getString("roomToken", "");
|
roomToken = getIntent().getExtras().getString("roomToken", "");
|
||||||
userDisplayName = getIntent().getExtras().getString("userDisplayName", "");
|
userDisplayName = getIntent().getExtras().getString("userDisplayName", "");
|
||||||
|
|
||||||
router = Conductor.attachRouter(this, container, savedInstanceState);
|
|
||||||
|
|
||||||
if (!router.hasRootController()) {
|
PermissionListener permissionlistener = new PermissionListener() {
|
||||||
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
|
@Override
|
||||||
bundleBuilder.putString("roomToken", roomToken);
|
public void onPermissionGranted() {
|
||||||
bundleBuilder.putString("userDisplayName", userDisplayName);
|
start();
|
||||||
|
call();
|
||||||
|
}
|
||||||
|
|
||||||
router.setRoot(RouterTransaction.with(new CallController(bundleBuilder.build()))
|
@Override
|
||||||
.popChangeHandler(new SimpleSwapChangeHandler())
|
public void onPermissionDenied(ArrayList<String> deniedPermissions) {
|
||||||
.pushChangeHandler((new SimpleSwapChangeHandler())));
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TedPermission.with(this)
|
||||||
|
.setPermissionListener(permissionlistener)
|
||||||
|
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
|
||||||
|
.setPermissions(android.Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,
|
||||||
|
Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.ACCESS_NETWORK_STATE,
|
||||||
|
Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.INTERNET)
|
||||||
|
.check();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private VideoCapturer createVideoCapturer() {
|
||||||
|
VideoCapturer videoCapturer;
|
||||||
|
videoCapturer = createCameraCapturer(new Camera1Enumerator(false));
|
||||||
|
return videoCapturer;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
//Initialize PeerConnectionFactory globals.
|
||||||
|
//Params are context, initAudio,initVideo and videoCodecHwAcceleration
|
||||||
|
PeerConnectionFactory.initializeAndroidGlobals(this, true, true,
|
||||||
|
false);
|
||||||
|
|
||||||
|
//Create a new PeerConnectionFactory instance.
|
||||||
|
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
|
||||||
|
peerConnectionFactory = new PeerConnectionFactory(options);
|
||||||
|
|
||||||
|
//Now create a VideoCapturer instance. Callback methods are there if you want to do something! Duh!
|
||||||
|
VideoCapturer videoCapturerAndroid = createVideoCapturer();
|
||||||
|
|
||||||
|
//Create MediaConstraints - Will be useful for specifying video and audio constraints.
|
||||||
|
audioConstraints = new MediaConstraints();
|
||||||
|
videoConstraints = new MediaConstraints();
|
||||||
|
|
||||||
|
//Create a VideoSource instance
|
||||||
|
videoSource = peerConnectionFactory.createVideoSource(videoCapturerAndroid);
|
||||||
|
localVideoTrack = peerConnectionFactory.createVideoTrack("100", videoSource);
|
||||||
|
|
||||||
|
//create an AudioSource instance
|
||||||
|
audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
|
||||||
|
localAudioTrack = peerConnectionFactory.createAudioTrack("101", audioSource);
|
||||||
|
|
||||||
|
//create a videoRenderer based on SurfaceViewRenderer instance
|
||||||
|
localRenderer = new VideoRenderer(pipVideoView);
|
||||||
|
// And finally, with our VideoRenderer ready, we
|
||||||
|
// can add our renderer to the VideoTrack.
|
||||||
|
localVideoTrack.addRenderer(localRenderer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void call() {
|
||||||
|
//we already have video and audio tracks. Now create peerconnections
|
||||||
|
List<PeerConnection.IceServer> iceServers = new ArrayList<>();
|
||||||
|
iceServers.add(new PeerConnection.IceServer("stun:stun.nextcloud.com:443"));
|
||||||
|
|
||||||
|
//create sdpConstraints
|
||||||
|
sdpConstraints = new MediaConstraints();
|
||||||
|
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("offerToReceiveAudio", "true"));
|
||||||
|
sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("offerToReceiveVideo", "true"));
|
||||||
|
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("internalSctpDataChannels", "true"));
|
||||||
|
sdpConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
|
||||||
|
|
||||||
|
//creating localPeer
|
||||||
|
localPeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints,
|
||||||
|
new MagicPeerConnectionObserver() {
|
||||||
|
@Override
|
||||||
|
public void onIceCandidate(IceCandidate iceCandidate) {
|
||||||
|
super.onIceCandidate(iceCandidate);
|
||||||
|
onIceCandidateReceived(localPeer, iceCandidate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//creating remotePeer
|
||||||
|
remotePeer = peerConnectionFactory.createPeerConnection(iceServers, sdpConstraints,
|
||||||
|
new MagicPeerConnectionObserver() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIceCandidate(IceCandidate iceCandidate) {
|
||||||
|
super.onIceCandidate(iceCandidate);
|
||||||
|
onIceCandidateReceived(remotePeer, iceCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAddStream(MediaStream mediaStream) {
|
||||||
|
super.onAddStream(mediaStream);
|
||||||
|
gotRemoteStream(mediaStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
|
||||||
|
super.onIceGatheringChange(iceGatheringState);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//creating local mediastream
|
||||||
|
MediaStream stream = peerConnectionFactory.createLocalMediaStream("102");
|
||||||
|
stream.addTrack(localAudioTrack);
|
||||||
|
stream.addTrack(localVideoTrack);
|
||||||
|
localPeer.addStream(stream);
|
||||||
|
|
||||||
|
//creating Offer
|
||||||
|
localPeer.createOffer(new MagicSdpObserver(){
|
||||||
|
@Override
|
||||||
|
public void onCreateSuccess(SessionDescription sessionDescription) {
|
||||||
|
//we have localOffer. Set it as local desc for localpeer and remote desc for remote peer.
|
||||||
|
//try to create answer from the remote peer.
|
||||||
|
super.onCreateSuccess(sessionDescription);
|
||||||
|
localPeer.setLocalDescription(new MagicSdpObserver(), sessionDescription);
|
||||||
|
remotePeer.setRemoteDescription(new MagicSdpObserver(), sessionDescription);
|
||||||
|
remotePeer.createAnswer(new MagicSdpObserver() {
|
||||||
|
@Override
|
||||||
|
public void onCreateSuccess(SessionDescription sessionDescription) {
|
||||||
|
//remote answer generated. Now set it as local desc for remote peer and remote desc for local peer.
|
||||||
|
super.onCreateSuccess(sessionDescription);
|
||||||
|
remotePeer.setLocalDescription(new MagicSdpObserver(), sessionDescription);
|
||||||
|
localPeer.setRemoteDescription(new MagicSdpObserver(), sessionDescription);
|
||||||
|
|
||||||
|
}
|
||||||
|
},new MediaConstraints());
|
||||||
|
}
|
||||||
|
},sdpConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void hangup() {
|
||||||
|
if (localPeer != null) {
|
||||||
|
localPeer.close();
|
||||||
|
localPeer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remotePeer != null) {
|
||||||
|
remotePeer.close();
|
||||||
|
remotePeer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void gotRemoteStream(MediaStream stream) {
|
||||||
|
//we have remote video stream. add to the renderer.
|
||||||
|
final VideoTrack videoTrack = stream.videoTracks.getFirst();
|
||||||
|
AudioTrack audioTrack = stream.audioTracks.getFirst();
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
remoteRenderer = new VideoRenderer(fullScreenVideoView);
|
||||||
|
videoTrack.addRenderer(remoteRenderer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onIceCandidateReceived(PeerConnection peer, IceCandidate iceCandidate) {
|
||||||
|
//we have received ice candidate. We can set it to the other peer.
|
||||||
|
if (peer == localPeer) {
|
||||||
|
remotePeer.addIceCandidate(iceCandidate);
|
||||||
|
} else {
|
||||||
|
localPeer.addIceCandidate(iceCandidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onDestroy() {
|
||||||
if (!router.handleBack()) {
|
super.onDestroy();
|
||||||
super.onBackPressed();
|
hangup();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getSystemUiVisibility() {
|
private static int getSystemUiVisibility() {
|
||||||
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
|
int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||||
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||||
|
Loading…
Reference in New Issue
Block a user