Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2017-11-22 15:23:28 +01:00
parent 8eee14d32f
commit 855ed05cf6
7 changed files with 172 additions and 84 deletions

View File

@ -34,6 +34,8 @@ import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.GridLayout;
import android.widget.RelativeLayout;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
@ -52,7 +54,7 @@ import com.nextcloud.talk.events.MediaStreamEvent;
import com.nextcloud.talk.events.SessionDescriptionSendEvent; import com.nextcloud.talk.events.SessionDescriptionSendEvent;
import com.nextcloud.talk.persistence.entities.UserEntity; import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.webrtc.MagicAudioManager; import com.nextcloud.talk.webrtc.MagicAudioManager;
import com.nextcloud.talk.webrtc.PeerConnectionWrapper; import com.nextcloud.talk.webrtc.MagicPeerConnectionWrapper;
import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringEscapeUtils;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -104,8 +106,8 @@ public class CallActivity extends AppCompatActivity {
@BindView(R.id.pip_video_view) @BindView(R.id.pip_video_view)
SurfaceViewRenderer pipVideoView; SurfaceViewRenderer pipVideoView;
@BindView(R.id.fullscreen_video_view) @BindView(R.id.videos_grid_view)
SurfaceViewRenderer fullScreenVideoView; GridLayout videosGrid;
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@ -125,7 +127,9 @@ public class CallActivity extends AppCompatActivity {
VideoCapturer videoCapturer; VideoCapturer videoCapturer;
VideoRenderer localRenderer; VideoRenderer localRenderer;
VideoRenderer remoteRenderer; VideoRenderer remoteRenderer;
HashMap<String, VideoRenderer> videoRendererHashMap = new HashMap<>();
PeerConnection localPeer; PeerConnection localPeer;
EglBase rootEglBase;
boolean leavingCall = false; boolean leavingCall = false;
BooleanSupplier booleanSupplier = () -> leavingCall; BooleanSupplier booleanSupplier = () -> leavingCall;
Disposable signalingDisposable; Disposable signalingDisposable;
@ -138,7 +142,7 @@ public class CallActivity extends AppCompatActivity {
private MediaStream localMediaStream; private MediaStream localMediaStream;
private String credentials; private String credentials;
private List<PeerConnectionWrapper> peerConnectionWrapperList = new ArrayList<>(); private List<MagicPeerConnectionWrapper> magicPeerConnectionWrapperList = new ArrayList<>();
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;
@ -224,16 +228,11 @@ public class CallActivity extends AppCompatActivity {
public void initViews() { public void initViews() {
pipVideoView.setMirror(true); pipVideoView.setMirror(true);
fullScreenVideoView.setMirror(false); rootEglBase = EglBase.create();
EglBase rootEglBase = EglBase.create();
pipVideoView.init(rootEglBase.getEglBaseContext(), null); pipVideoView.init(rootEglBase.getEglBaseContext(), null);
pipVideoView.setZOrderMediaOverlay(true); pipVideoView.setZOrderMediaOverlay(true);
fullScreenVideoView.init(rootEglBase.getEglBaseContext(), null);
fullScreenVideoView.setZOrderMediaOverlay(true);
fullScreenVideoView.setEnableHardwareScaler(true);
pipVideoView.setEnableHardwareScaler(true); pipVideoView.setEnableHardwareScaler(true);
pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); pipVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
fullScreenVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
} }
public void start() { public void start() {
@ -435,7 +434,7 @@ public class CallActivity extends AppCompatActivity {
NCSignalingMessage ncSignalingMessage = LoganSquare.parse(signaling.getMessageWrapper().toString(), NCSignalingMessage ncSignalingMessage = LoganSquare.parse(signaling.getMessageWrapper().toString(),
NCSignalingMessage.class); NCSignalingMessage.class);
if (ncSignalingMessage.getRoomType().equals("video")) { if (ncSignalingMessage.getRoomType().equals("video")) {
PeerConnectionWrapper peerConnectionWrapper = alwaysGetPeerConnectionWrapperForSessionId MagicPeerConnectionWrapper magicPeerConnectionWrapper = alwaysGetPeerConnectionWrapperForSessionId
(ncSignalingMessage.getFrom(), ncSignalingMessage.getFrom().equals(callSession)); (ncSignalingMessage.getFrom(), ncSignalingMessage.getFrom().equals(callSession));
String type = null; String type = null;
@ -450,8 +449,8 @@ public class CallActivity extends AppCompatActivity {
switch (type) { switch (type) {
case "offer": case "offer":
case "answer": case "answer":
peerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick()); magicPeerConnectionWrapper.setNick(ncSignalingMessage.getPayload().getNick());
peerConnectionWrapper.getPeerConnection().setRemoteDescription(peerConnectionWrapper magicPeerConnectionWrapper.getPeerConnection().setRemoteDescription(magicPeerConnectionWrapper
.getMagicSdpObserver(), new SessionDescription(SessionDescription.Type.fromCanonicalForm(type), .getMagicSdpObserver(), new SessionDescription(SessionDescription.Type.fromCanonicalForm(type),
ncSignalingMessage.getPayload().getSdp())); ncSignalingMessage.getPayload().getSdp()));
break; break;
@ -459,11 +458,11 @@ public class CallActivity extends AppCompatActivity {
NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate(); NCIceCandidate ncIceCandidate = ncSignalingMessage.getPayload().getIceCandidate();
IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(), IceCandidate iceCandidate = new IceCandidate(ncIceCandidate.getSdpMid(),
ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate()); ncIceCandidate.getSdpMLineIndex(), ncIceCandidate.getCandidate());
peerConnectionWrapper.addCandidate(iceCandidate); magicPeerConnectionWrapper.addCandidate(iceCandidate);
break; break;
case "endOfCandidates": case "endOfCandidates":
peerConnectionWrapper.drainIceCandidates(); magicPeerConnectionWrapper.drainIceCandidates();
peerConnectionWrapper.sendLocalCandidates(); magicPeerConnectionWrapper.sendLocalCandidates();
break; break;
default: default:
break; break;
@ -496,9 +495,9 @@ public class CallActivity extends AppCompatActivity {
} }
} }
for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) { for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
if (!peerConnectionWrapper.getSessionId().equals(callSession)) { if (!magicPeerConnectionWrapper.getSessionId().equals(callSession)) {
oldSesssions.add(peerConnectionWrapper.getSessionId()); oldSesssions.add(magicPeerConnectionWrapper.getSessionId());
} }
} }
@ -513,12 +512,12 @@ public class CallActivity extends AppCompatActivity {
return; return;
} }
PeerConnectionWrapper peerConnectionWrapper; MagicPeerConnectionWrapper magicPeerConnectionWrapper;
for (String sessionId : newSessions) { for (String sessionId : newSessions) {
if (getPeerConnectionWrapperForSessionId(sessionId) == null) { if (getPeerConnectionWrapperForSessionId(sessionId) == null) {
if (sessionId.compareTo(callSession) < 0) { if (sessionId.compareTo(callSession) < 0) {
PeerConnectionWrapper connectionWrapper = alwaysGetPeerConnectionWrapperForSessionId(sessionId, MagicPeerConnectionWrapper connectionWrapper = alwaysGetPeerConnectionWrapperForSessionId(sessionId,
false); false);
if (connectionWrapper.getPeerConnection() != null) { if (connectionWrapper.getPeerConnection() != null) {
connectionWrapper.getPeerConnection().createOffer(connectionWrapper.getMagicSdpObserver(), connectionWrapper.getPeerConnection().createOffer(connectionWrapper.getMagicSdpObserver(),
@ -532,33 +531,33 @@ public class CallActivity extends AppCompatActivity {
} }
for (String sessionId : leftSessions) { for (String sessionId : leftSessions) {
if ((peerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null) { if ((magicPeerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null) {
if (peerConnectionWrapper.getPeerConnection() != null) { if (magicPeerConnectionWrapper.getPeerConnection() != null) {
peerConnectionWrapper.getPeerConnection().close(); magicPeerConnectionWrapper.getPeerConnection().close();
} }
peerConnectionWrapperList.remove(peerConnectionWrapper); magicPeerConnectionWrapperList.remove(magicPeerConnectionWrapper);
} }
} }
} }
private PeerConnectionWrapper alwaysGetPeerConnectionWrapperForSessionId(String sessionId, boolean isLocalPeer) { private MagicPeerConnectionWrapper alwaysGetPeerConnectionWrapperForSessionId(String sessionId, boolean isLocalPeer) {
PeerConnectionWrapper peerConnectionWrapper; MagicPeerConnectionWrapper magicPeerConnectionWrapper;
if ((peerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null) { if ((magicPeerConnectionWrapper = getPeerConnectionWrapperForSessionId(sessionId)) != null) {
return peerConnectionWrapper; return magicPeerConnectionWrapper;
} else { } else {
peerConnectionWrapper = new PeerConnectionWrapper(peerConnectionFactory, magicPeerConnectionWrapper = new MagicPeerConnectionWrapper(peerConnectionFactory,
iceServers, sdpConstraints, sessionId); iceServers, sdpConstraints, sessionId);
peerConnectionWrapper.getPeerConnection().addStream(localMediaStream); magicPeerConnectionWrapper.getPeerConnection().addStream(localMediaStream);
peerConnectionWrapperList.add(peerConnectionWrapper); magicPeerConnectionWrapperList.add(magicPeerConnectionWrapper);
return peerConnectionWrapper; return magicPeerConnectionWrapper;
} }
} }
private PeerConnectionWrapper getPeerConnectionWrapperForSessionId(String sessionId) { private MagicPeerConnectionWrapper getPeerConnectionWrapperForSessionId(String sessionId) {
for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) { for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
if (peerConnectionWrapper.getSessionId().equals(sessionId)) { if (magicPeerConnectionWrapper.getSessionId().equals(sessionId)) {
return peerConnectionWrapper; return magicPeerConnectionWrapper;
} }
} }
return null; return null;
@ -570,9 +569,9 @@ public class CallActivity extends AppCompatActivity {
dispose(null); dispose(null);
for (PeerConnectionWrapper peerConnectionWrapper : peerConnectionWrapperList) { for (MagicPeerConnectionWrapper magicPeerConnectionWrapper : magicPeerConnectionWrapperList) {
if (peerConnectionWrapper.getPeerConnection() != null) { if (magicPeerConnectionWrapper.getPeerConnection() != null) {
peerConnectionWrapper.getPeerConnection().close(); magicPeerConnectionWrapper.getPeerConnection().close();
} }
} }
@ -581,7 +580,6 @@ public class CallActivity extends AppCompatActivity {
} }
pipVideoView.release(); pipVideoView.release();
fullScreenVideoView.release();
String credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()); String credentials = ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken());
ncApi.leaveCall(credentials, ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken)) ncApi.leaveCall(credentials, ApiHelper.getUrlForCall(userEntity.getBaseUrl(), roomToken))
@ -610,7 +608,7 @@ public class CallActivity extends AppCompatActivity {
}); });
} }
private void gotRemoteStream(MediaStream stream) { private void gotRemoteStream(MediaStream stream, String session) {
//we have remote video stream. add to the renderer. //we have remote video stream. add to the renderer.
if (stream.videoTracks.size() < 2 && stream.audioTracks.size() < 2) { if (stream.videoTracks.size() < 2 && stream.audioTracks.size() < 2) {
if (stream.videoTracks.size() == 1) { if (stream.videoTracks.size() == 1) {
@ -621,8 +619,26 @@ public class CallActivity extends AppCompatActivity {
public void run() { public void run() {
if (stream.videoTracks.size() == 1) { if (stream.videoTracks.size() == 1) {
try { try {
remoteRenderer = new VideoRenderer(fullScreenVideoView); RelativeLayout relativeLayout = (RelativeLayout)
getLayoutInflater().inflate(R.layout.surface_renderer, videosGrid,
false);
relativeLayout.setTag(session);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id
.surface_view);
surfaceViewRenderer.setMirror(false);
surfaceViewRenderer.init(rootEglBase.getEglBaseContext(), null);
surfaceViewRenderer.setZOrderMediaOverlay(true);
surfaceViewRenderer.setEnableHardwareScaler(true);
surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
VideoRenderer remoteRenderer = new VideoRenderer(surfaceViewRenderer);
videoRendererHashMap.put(session, remoteRenderer);
videoTrack.addRenderer(remoteRenderer); videoTrack.addRenderer(remoteRenderer);
videosGrid.addView(relativeLayout);
GridLayout.LayoutParams param = new GridLayout.LayoutParams(GridLayout.spec(
GridLayout.UNDEFINED,GridLayout.FILL,1f),
GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f));
relativeLayout.setLayoutParams(param);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -676,7 +692,7 @@ public class CallActivity extends AppCompatActivity {
@Subscribe(threadMode = ThreadMode.BACKGROUND) @Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(MediaStreamEvent mediaStreamEvent) { public void onMessageEvent(MediaStreamEvent mediaStreamEvent) {
gotRemoteStream(mediaStreamEvent.getMediaStream()); gotRemoteStream(mediaStreamEvent.getMediaStream(), mediaStreamEvent.getSession());
} }
@Subscribe(threadMode = ThreadMode.BACKGROUND) @Subscribe(threadMode = ThreadMode.BACKGROUND)

View File

@ -33,4 +33,11 @@ public class DataChannelMessage {
@JsonField(name = "payload") @JsonField(name = "payload")
String payload; String payload;
public DataChannelMessage(String type) {
this.type = type;
}
public DataChannelMessage() {
}
} }

View File

@ -27,8 +27,10 @@ import lombok.Data;
@Data @Data
public class MediaStreamEvent { public class MediaStreamEvent {
private final MediaStream mediaStream; private final MediaStream mediaStream;
private final String session;
public MediaStreamEvent(MediaStream mediaStream) { public MediaStreamEvent(MediaStream mediaStream, String session) {
this.mediaStream = mediaStream; this.mediaStream = mediaStream;
this.session = session;
} }
} }

View File

@ -20,8 +20,6 @@
package com.nextcloud.talk.webrtc; package com.nextcloud.talk.webrtc;
import android.util.Log;
import org.webrtc.DataChannel; import org.webrtc.DataChannel;
import org.webrtc.IceCandidate; import org.webrtc.IceCandidate;
import org.webrtc.MediaStream; import org.webrtc.MediaStream;
@ -35,7 +33,6 @@ public class MagicPeerConnectionObserver implements PeerConnection.Observer {
@Override @Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) { public void onSignalingChange(PeerConnection.SignalingState signalingState) {
Log.d("MARIO", signalingState.name());
} }
@Override @Override

View File

@ -22,6 +22,7 @@ package com.nextcloud.talk.webrtc;
import android.util.Log; import android.util.Log;
import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.api.models.json.signaling.DataChannelMessage; import com.nextcloud.talk.api.models.json.signaling.DataChannelMessage;
import com.nextcloud.talk.api.models.json.signaling.NCIceCandidate; import com.nextcloud.talk.api.models.json.signaling.NCIceCandidate;
import com.nextcloud.talk.events.MediaStreamEvent; import com.nextcloud.talk.events.MediaStreamEvent;
@ -36,12 +37,13 @@ import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory; import org.webrtc.PeerConnectionFactory;
import org.webrtc.SessionDescription; import org.webrtc.SessionDescription;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PeerConnectionWrapper { public class MagicPeerConnectionWrapper {
private static String TAG = "PeerConnectionWrapper"; private static String TAG = "MagicPeerConnectionWrapper";
private static PeerConnection peerConnection; private static PeerConnection peerConnection;
List<IceCandidate> iceCandidates = new ArrayList<>(); List<IceCandidate> iceCandidates = new ArrayList<>();
List<PeerConnection.IceServer> iceServers; List<PeerConnection.IceServer> iceServers;
@ -49,11 +51,11 @@ public class PeerConnectionWrapper {
private String sessionId; private String sessionId;
private String nick; private String nick;
private MediaConstraints mediaConstraints; private MediaConstraints mediaConstraints;
private DataChannel dataChannel; private DataChannel magicDataChannel;
private MagicSdpObserver magicSdpObserver; private MagicSdpObserver magicSdpObserver;
private MagicPeerConnectionObserver magicPeerConnectionObserver; private MagicPeerConnectionObserver magicPeerConnectionObserver;
public PeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory, public MagicPeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory,
List<PeerConnection.IceServer> iceServerList, List<PeerConnection.IceServer> iceServerList,
MediaConstraints mediaConstraints, MediaConstraints mediaConstraints,
String sessionId) { String sessionId) {
@ -61,27 +63,9 @@ public class PeerConnectionWrapper {
this.iceServers = iceServerList; this.iceServers = iceServerList;
magicPeerConnectionObserver = new MagicPeerConnectionObserver() { magicPeerConnectionObserver = new MagicPeerConnectionObserver() {
@Override
public void onIceConnectionReceivingChange(boolean b) {
}
@Override
public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
}
@Override @Override
public void onAddStream(MediaStream mediaStream) { public void onAddStream(MediaStream mediaStream) {
EventBus.getDefault().post(new MediaStreamEvent(mediaStream)); EventBus.getDefault().post(new MediaStreamEvent(mediaStream, sessionId));
}
@Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) {
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
} }
@Override @Override
@ -90,12 +74,15 @@ public class PeerConnectionWrapper {
ncIceCandidate.setSdpMid(iceCandidate.sdpMid); ncIceCandidate.setSdpMid(iceCandidate.sdpMid);
ncIceCandidate.setSdpMLineIndex(iceCandidate.sdpMLineIndex); ncIceCandidate.setSdpMLineIndex(iceCandidate.sdpMLineIndex);
ncIceCandidate.setCandidate(iceCandidate.sdp); ncIceCandidate.setCandidate(iceCandidate.sdp);
if (peerConnection.getRemoteDescription() == null) { /*if (peerConnection.getRemoteDescription() == null) {
localCandidates.add(ncIceCandidate); localCandidates.add(ncIceCandidate);
} else { } else {
EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId, EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId,
"candidate", ncIceCandidate)); "candidate", ncIceCandidate));
} }*/
EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId,
"candidate", ncIceCandidate));
} }
}; };
@ -103,6 +90,11 @@ public class PeerConnectionWrapper {
peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints, peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints,
magicPeerConnectionObserver); magicPeerConnectionObserver);
DataChannel.Init init = new DataChannel.Init();
init.negotiated = false;
magicDataChannel = peerConnection.createDataChannel("status", init);
magicDataChannel.registerObserver(new MagicDataChannelObserver());
this.sessionId = sessionId; this.sessionId = sessionId;
this.mediaConstraints = mediaConstraints; this.mediaConstraints = mediaConstraints;
@ -120,6 +112,7 @@ public class PeerConnectionWrapper {
@Override @Override
public void onCreateSuccess(SessionDescription sessionDescription) { public void onCreateSuccess(SessionDescription sessionDescription) {
super.onCreateSuccess(sessionDescription); super.onCreateSuccess(sessionDescription);
peerConnection.setLocalDescription(magicSdpObserver, sessionDescription); peerConnection.setLocalDescription(magicSdpObserver, sessionDescription);
} }
@ -181,8 +174,13 @@ public class PeerConnectionWrapper {
} }
private void sendChannelData(DataChannelMessage dataChannelMessage) { private void sendChannelData(DataChannelMessage dataChannelMessage) {
ByteBuffer buffer = ByteBuffer.wrap(dataChannelMessage.toString().getBytes()); ByteBuffer buffer = null;
dataChannel.send(new DataChannel.Buffer(buffer, false)); try {
buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
magicDataChannel.send(new DataChannel.Buffer(buffer, false));
} catch (IOException e) {
e.printStackTrace();
}
} }
@ -191,7 +189,7 @@ public class PeerConnectionWrapper {
} }
public static void setPeerConnection(PeerConnection peerConnection) { public static void setPeerConnection(PeerConnection peerConnection) {
PeerConnectionWrapper.peerConnection = peerConnection; MagicPeerConnectionWrapper.peerConnection = peerConnection;
} }
public String getSessionId() { public String getSessionId() {
@ -209,4 +207,35 @@ public class PeerConnectionWrapper {
public void setNick(String nick) { public void setNick(String nick) {
this.nick = nick; this.nick = nick;
} }
private class MagicDataChannelObserver implements DataChannel.Observer {
@Override
public void onBufferedAmountChange(long l) {
}
@Override
public void onStateChange() {
if (magicDataChannel.state().equals(DataChannel.State.OPEN) &&
magicDataChannel.label().equals("status")) {
sendChannelData(new DataChannelMessage("videoOn"));
sendChannelData(new DataChannelMessage("audioOn"));
}
}
@Override
public void onMessage(DataChannel.Buffer buffer) {
if (buffer.binary) {
Log.d(TAG, "Received binary msg over " + TAG + " " + sessionId);
return;
}
ByteBuffer data = buffer.data;
final byte[] bytes = new byte[data.capacity()];
data.get(bytes);
String strData = new String(bytes);
Log.d(TAG, "Got msg: " + strData + " over " + TAG + " " + sessionId);
}
}
} }

View File

@ -26,6 +26,15 @@
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context=".activities.CallActivity"> tools:context=".activities.CallActivity">
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/videos_grid_view"
android:columnCount="4"
android:rowCount="2">
</GridLayout>
<org.webrtc.SurfaceViewRenderer <org.webrtc.SurfaceViewRenderer
android:id="@+id/pip_video_view" android:id="@+id/pip_video_view"
android:layout_width="120dp" android:layout_width="120dp"
@ -34,9 +43,4 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_margin="16dp"/> android:layout_margin="16dp"/>
<org.webrtc.SurfaceViewRenderer
android:id="@+id/fullscreen_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout> </RelativeLayout>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relative_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<org.webrtc.SurfaceViewRenderer
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/surface_view"/>
</RelativeLayout>