MagicPeerConnectionWrapper.java 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Nextcloud Talk application
  3. *
  4. * @author Mario Danic
  5. * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.talk.webrtc;
  21. import android.util.Log;
  22. import com.bluelinelabs.logansquare.LoganSquare;
  23. import com.nextcloud.talk.api.models.json.signaling.DataChannelMessage;
  24. import com.nextcloud.talk.api.models.json.signaling.NCIceCandidate;
  25. import com.nextcloud.talk.events.MediaStreamEvent;
  26. import com.nextcloud.talk.events.SessionDescriptionSendEvent;
  27. import org.greenrobot.eventbus.EventBus;
  28. import org.webrtc.DataChannel;
  29. import org.webrtc.IceCandidate;
  30. import org.webrtc.MediaConstraints;
  31. import org.webrtc.MediaStream;
  32. import org.webrtc.PeerConnection;
  33. import org.webrtc.PeerConnectionFactory;
  34. import org.webrtc.SessionDescription;
  35. import java.io.IOException;
  36. import java.nio.ByteBuffer;
  37. import java.util.ArrayList;
  38. import java.util.List;
  39. public class MagicPeerConnectionWrapper {
  40. private static String TAG = "MagicPeerConnectionWrapper";
  41. private static PeerConnection peerConnection;
  42. List<IceCandidate> iceCandidates = new ArrayList<>();
  43. List<PeerConnection.IceServer> iceServers;
  44. List<NCIceCandidate> localCandidates = new ArrayList<>();
  45. private String sessionId;
  46. private String nick;
  47. private MediaConstraints mediaConstraints;
  48. private DataChannel magicDataChannel;
  49. private MagicSdpObserver magicSdpObserver;
  50. private MagicPeerConnectionObserver magicPeerConnectionObserver;
  51. public MagicPeerConnectionWrapper(PeerConnectionFactory peerConnectionFactory,
  52. List<PeerConnection.IceServer> iceServerList,
  53. MediaConstraints mediaConstraints,
  54. String sessionId) {
  55. this.iceServers = iceServerList;
  56. magicPeerConnectionObserver = new MagicPeerConnectionObserver() {
  57. @Override
  58. public void onAddStream(MediaStream mediaStream) {
  59. EventBus.getDefault().post(new MediaStreamEvent(mediaStream, sessionId));
  60. }
  61. @Override
  62. public void onIceCandidate(IceCandidate iceCandidate) {
  63. NCIceCandidate ncIceCandidate = new NCIceCandidate();
  64. ncIceCandidate.setSdpMid(iceCandidate.sdpMid);
  65. ncIceCandidate.setSdpMLineIndex(iceCandidate.sdpMLineIndex);
  66. ncIceCandidate.setCandidate(iceCandidate.sdp);
  67. /*if (peerConnection.getRemoteDescription() == null) {
  68. localCandidates.add(ncIceCandidate);
  69. } else {
  70. EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId,
  71. "candidate", ncIceCandidate));
  72. }*/
  73. EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId,
  74. "candidate", ncIceCandidate));
  75. }
  76. };
  77. peerConnection = peerConnectionFactory.createPeerConnection(iceServerList, mediaConstraints,
  78. magicPeerConnectionObserver);
  79. DataChannel.Init init = new DataChannel.Init();
  80. init.negotiated = false;
  81. magicDataChannel = peerConnection.createDataChannel("status", init);
  82. magicDataChannel.registerObserver(new MagicDataChannelObserver());
  83. this.sessionId = sessionId;
  84. this.mediaConstraints = mediaConstraints;
  85. magicSdpObserver = new MagicSdpObserver() {
  86. @Override
  87. public void onCreateFailure(String s) {
  88. Log.d(TAG, s);
  89. }
  90. @Override
  91. public void onSetFailure(String s) {
  92. Log.d(TAG, s);
  93. }
  94. @Override
  95. public void onCreateSuccess(SessionDescription sessionDescription) {
  96. super.onCreateSuccess(sessionDescription);
  97. peerConnection.setLocalDescription(magicSdpObserver, sessionDescription);
  98. }
  99. @Override
  100. public void onSetSuccess() {
  101. if (peerConnection.getRemoteDescription() == null) {
  102. EventBus.getDefault().post(new SessionDescriptionSendEvent(peerConnection.getLocalDescription(), sessionId,
  103. peerConnection.getLocalDescription().type.canonicalForm(), null));
  104. } else if (peerConnection.getLocalDescription() == null && peerConnection.getRemoteDescription().type
  105. .canonicalForm().equals
  106. ("offer")) {
  107. peerConnection.createAnswer(magicSdpObserver, mediaConstraints);
  108. } else if ((peerConnection.getLocalDescription() != null && peerConnection.getRemoteDescription().type
  109. .canonicalForm().equals
  110. ("offer"))) {
  111. EventBus.getDefault().post(new SessionDescriptionSendEvent(peerConnection.getLocalDescription(), sessionId,
  112. peerConnection.getLocalDescription().type.canonicalForm(), null));
  113. } else if (peerConnection.getRemoteDescription() != null) {
  114. drainIceCandidates();
  115. sendLocalCandidates();
  116. }
  117. }
  118. };
  119. }
  120. public void sendLocalCandidates() {
  121. for (NCIceCandidate ncIceCandidate : localCandidates) {
  122. EventBus.getDefault().post(new SessionDescriptionSendEvent(null, sessionId,
  123. "candidate", ncIceCandidate));
  124. }
  125. localCandidates = new ArrayList<>();
  126. }
  127. public void drainIceCandidates() {
  128. for (IceCandidate iceCandidate : iceCandidates) {
  129. peerConnection.addIceCandidate(iceCandidate);
  130. }
  131. iceCandidates = new ArrayList<>();
  132. }
  133. public MagicSdpObserver getMagicSdpObserver() {
  134. return magicSdpObserver;
  135. }
  136. public void addCandidate(IceCandidate iceCandidate) {
  137. if (peerConnection.getRemoteDescription() != null) {
  138. peerConnection.addIceCandidate(iceCandidate);
  139. } else {
  140. iceCandidates.add(iceCandidate);
  141. }
  142. }
  143. private void sendChannelData(DataChannelMessage dataChannelMessage) {
  144. ByteBuffer buffer = null;
  145. try {
  146. buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
  147. magicDataChannel.send(new DataChannel.Buffer(buffer, false));
  148. } catch (IOException e) {
  149. e.printStackTrace();
  150. }
  151. }
  152. public PeerConnection getPeerConnection() {
  153. return peerConnection;
  154. }
  155. public static void setPeerConnection(PeerConnection peerConnection) {
  156. MagicPeerConnectionWrapper.peerConnection = peerConnection;
  157. }
  158. public String getSessionId() {
  159. return sessionId;
  160. }
  161. public void setSessionId(String sessionId) {
  162. this.sessionId = sessionId;
  163. }
  164. public String getNick() {
  165. return nick;
  166. }
  167. public void setNick(String nick) {
  168. this.nick = nick;
  169. }
  170. private class MagicDataChannelObserver implements DataChannel.Observer {
  171. @Override
  172. public void onBufferedAmountChange(long l) {
  173. }
  174. @Override
  175. public void onStateChange() {
  176. if (magicDataChannel.state().equals(DataChannel.State.OPEN) &&
  177. magicDataChannel.label().equals("status")) {
  178. sendChannelData(new DataChannelMessage("videoOn"));
  179. sendChannelData(new DataChannelMessage("audioOn"));
  180. }
  181. }
  182. @Override
  183. public void onMessage(DataChannel.Buffer buffer) {
  184. if (buffer.binary) {
  185. Log.d(TAG, "Received binary msg over " + TAG + " " + sessionId);
  186. return;
  187. }
  188. ByteBuffer data = buffer.data;
  189. final byte[] bytes = new byte[data.capacity()];
  190. data.get(bytes);
  191. String strData = new String(bytes);
  192. Log.d(TAG, "Got msg: " + strData + " over " + TAG + " " + sessionId);
  193. }
  194. }
  195. }