Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/220.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
未调用WebRTC Android库函数_Android_Webrtc - Fatal编程技术网

未调用WebRTC Android库函数

未调用WebRTC Android库函数,android,webrtc,Android,Webrtc,我正在使用以下开源webrtc android应用程序: 我刚刚修改了此应用程序以使用我的socket.io服务器,而不是使用同一作者提供的以下服务器: 为此,我需要对上述AndroidTC应用程序的两个类进行一些更改。在此之后,当我启动应用程序时,它没有调用作为libjingle_peerconnection库一部分的“createOffer()”或“createAnswer()”函数。我不清楚这两个函数是没有被调用,还是不能使用“sendMessage()”函数 通过调试,我知道调用“c

我正在使用以下开源webrtc android应用程序:

我刚刚修改了此应用程序以使用我的socket.io服务器,而不是使用同一作者提供的以下服务器:

为此,我需要对上述AndroidTC应用程序的两个类进行一些更改。在此之后,当我启动应用程序时,它没有调用作为libjingle_peerconnection库一部分的“createOffer()”或“createAnswer()”函数。我不清楚这两个函数是没有被调用,还是不能使用“sendMessage()”函数

通过调试,我知道调用“createAnswer()”函数的行已成功到达。在此之后,我希望“createAnswer()”函数使用我的“sendMessage()”函数通过我的socket.io服务器将答案发送回另一方。我无法查看此“createAnswer()”函数的内部,因为它是库的一部分

在将上述应用程序更改为使用我自己的服务器之前,我已经使用auhtor提供的服务器对其进行了测试。它成功地运行了。当我使用自己的服务器打电话和握手时,我不知道出了什么问题。我只是修改了几行,以支持我在服务器上发送信号的方式

我的服务器代码已用于webrtc web应用程序。Web应用程序成功地使用此服务器进行调用。它应该也适用于这个android应用程序,对应用程序的修改很少

我在android应用程序中修改了以下两个类:

rtcsactivity.java

package fr.pchab.AndroidRTC;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Window;
import android.widget.Toast;
import org.json.JSONException;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.VideoRenderer;

import java.util.List;

public class RTCActivity extends Activity implements WebRtcClient.RTCListener{

  private final static int VIDEO_CALL_SENT = 666;
  private VideoStreamsView vsv;
  private WebRtcClient client;
  private String mSocketAddress;
  private String callerId;


  @Override
  public void onCreate(Bundle savedInstanceState) {


    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);


    mSocketAddress = "https://" + getResources().getString(R.string.host);
    mSocketAddress += (":"+getResources().getString(R.string.port)+"/");

    PeerConnectionFactory.initializeAndroidGlobals(this);

    // Camera display view
    Point displaySize = new Point();
    getWindowManager().getDefaultDisplay().getSize(displaySize);
    vsv = new VideoStreamsView(this, displaySize);


    client = new WebRtcClient(this, mSocketAddress);

    final Intent intent = getIntent();
    final String action = intent.getAction();

    if (Intent.ACTION_VIEW.equals(action)) {
      final List<String> segments = intent.getData().getPathSegments();
      callerId = segments.get(0);
    }
  }

  public void onConfigurationChanged(Configuration newConfig)
  {
    super.onConfigurationChanged(newConfig);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  }

  @Override
  public void onPause() {
    super.onPause();
    vsv.onPause();
  }

  @Override
  public void onResume() {
    super.onResume();
    vsv.onResume();
  }

  @Override
  public void onCallReady(String callId) {
      startCam();
  }

  public void answer(String callerId) throws JSONException {
    client.sendMessage(callerId, "init", null);
    startCam();
  }


  public void call(String callId) {
    Intent msg = new Intent(Intent.ACTION_SEND);
    msg.putExtra(Intent.EXTRA_TEXT, mSocketAddress + callId);
    msg.setType("text/plain");
    startActivityForResult(Intent.createChooser(msg, "Call someone :"), VIDEO_CALL_SENT);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(requestCode == VIDEO_CALL_SENT) {
      startCam();
    }
  }

  public void startCam() {
    setContentView(vsv);
    // Camera settings
    client.setCamera("front", "640", "480");
    client.start("android_test", true);
  }

  @Override
  public void onStatusChanged(final String newStatus) {
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Toast.makeText(getApplicationContext(), newStatus, Toast.LENGTH_SHORT).show();
      }
    });
  }

  @Override
  public void onLocalStream(MediaStream localStream) {
    localStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, 0)));
  }

  @Override
  public void onAddRemoteStream(MediaStream remoteStream, int endPoint) {
    remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, endPoint)));
    vsv.shouldDraw[endPoint] = true;
  }

  @Override
  public void onRemoveRemoteStream(MediaStream remoteStream, int endPoint) {
    remoteStream.videoTracks.get(0).dispose();
    vsv.shouldDraw[endPoint] = false;
  }

  // Implementation detail: bridge the VideoRenderer.Callbacks interface to the
  // VideoStreamsView implementation.
  private class VideoCallbacks implements VideoRenderer.Callbacks {
    private final VideoStreamsView view;
    private final int stream;

    public VideoCallbacks(VideoStreamsView view, int stream) {
      this.view = view;
      this.stream = stream;
    }

    @Override
    public void setSize(final int width, final int height) {
      view.queueEvent(new Runnable() {
        public void run() {
          view.setSize(stream, width, height);
        }
      });
    }

    @Override
    public void renderFrame(VideoRenderer.I420Frame frame) {
      view.queueFrame(stream, frame);
    }
  }
}
package fr.pchab.AndroidRTC;

import java.util.HashMap;
import java.util.LinkedList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;

import android.os.Handler;
import android.util.Log;

import com.koushikdutta.async.http.socketio.Acknowledge;
import com.koushikdutta.async.http.socketio.ConnectCallback;
import com.koushikdutta.async.http.socketio.EventCallback;
import com.koushikdutta.async.http.socketio.SocketIOClient;

class WebRtcClient {

  private final static int MAX_PEER = 2;
  private boolean[] endPoints = new boolean[MAX_PEER];
  private PeerConnectionFactory factory;
  private HashMap<String, Peer> peers = new HashMap<String, Peer>();
  private LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
  private MediaConstraints pcConstraints = new MediaConstraints();
  private MediaStream lMS;
  private RTCListener mListener;
  private SocketIOClient client;
  private final MessageHandler messageHandler = new MessageHandler();
  private final static String TAG = WebRtcClient.class.getCanonicalName();

  public interface RTCListener{
    void onCallReady(String callId);

    void onStatusChanged(String newStatus);

    void onLocalStream(MediaStream localStream);

    void onAddRemoteStream(MediaStream remoteStream, int endPoint);

    void onRemoveRemoteStream(MediaStream remoteStream, int endPoint);
  }

  private interface Command{
    void execute(String peerId, JSONObject payload) throws JSONException;
  }

  private class CreateOfferCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"CreateOfferCommand");
      Peer peer = peers.get(peerId);
      peer.pc.createOffer(peer, pcConstraints);
    }
  }

  private class CreateAnswerCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"CreateAnswerCommand");
      Peer peer = peers.get(peerId);
      SessionDescription sdp = new SessionDescription(
                                                      SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                                                      payload.getString("sdp")
                                                      );
      peer.pc.setRemoteDescription(peer, sdp);
      peer.pc.createAnswer(peer, pcConstraints);
    }
  }

  private class SetRemoteSDPCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"SetRemoteSDPCommand");
      Peer peer = peers.get(peerId);
      SessionDescription sdp = new SessionDescription(
                                                      SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                                                      payload.getString("sdp")
                                                      );
      peer.pc.setRemoteDescription(peer, sdp);
    }
  }

  private class AddIceCandidateCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"AddIceCandidateCommand");
      PeerConnection pc = peers.get(peerId).pc;
      if (pc.getRemoteDescription() != null) {
        IceCandidate candidate = new IceCandidate(
                                                  payload.getString("id"),
                                                  payload.getInt("label"),
                                                  payload.getString("candidate")
                                                  );
        pc.addIceCandidate(candidate);
      }
    }
  }

  public void sendMessage(String to, String type, JSONObject payload) throws JSONException {
    JSONObject message = new JSONObject();
    //message.put("room", to);
    message.put("type", type);
    message.put("msg", payload);
    message.put("room", "sojharo");
    client.emit("message", new JSONArray().put(message));
  }

  private class MessageHandler implements EventCallback {
    private HashMap<String, Command> commandMap;

    public MessageHandler() {
      this.commandMap = new HashMap<String, Command>();
      commandMap.put("init", new CreateOfferCommand());
      commandMap.put("offer", new CreateAnswerCommand());
      commandMap.put("answer", new SetRemoteSDPCommand());
      commandMap.put("candidate", new AddIceCandidateCommand());
    }

    @Override
    public void onEvent(String s, JSONArray jsonArray, Acknowledge acknowledge) {
      try {
          Log.d(TAG,"MessageHandler.onEvent() "+ (s == null ? "nil" : s));
        if(s.equals("id")) {

            JSONObject message = new JSONObject();

            message.put("room", "sojharo");
            message.put("username", "android");

            client.emit("create or join livehelp",
                    new JSONArray().put(message));

        } else if (s.equals("joined")) {
            mListener.onCallReady("Not Initiator");
        } else {

          JSONObject json = jsonArray.getJSONObject(0);


          try{
                if(json.getString("msg").equals("got user media"))
                    return ;
            }catch(JSONException e){}

            String from = json.getString("from");
            String type = null;
            try{
                type = json.getString("type");
            }catch(JSONException e){}


          // if peer is unknown, try to add him
          if(!peers.containsKey(from)) {
            // if MAX_PEER is reach, ignore the call
            int endPoint = findEndPoint();
            if(endPoint != MAX_PEER) {
              addPeer(from, endPoint);

              commandMap.get(type).execute(from, json);
            }
          } else {
            commandMap.get(type).execute(from, json);
          }
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
  }

  private class Peer implements SdpObserver, PeerConnection.Observer{
    private PeerConnection pc;
    private String id;
    private int endPoint;

    @Override
    public void onCreateSuccess(final SessionDescription sdp) {
      try {
        JSONObject payload = new JSONObject();
        payload.put("type", sdp.type.canonicalForm());
        payload.put("sdp", sdp.description);
        sendMessage(id, sdp.type.canonicalForm(), payload);
        pc.setLocalDescription(Peer.this, sdp);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }

    @Override
    public void onSetSuccess() {}

    @Override
    public void onCreateFailure(String s) {}

    @Override
    public void onSetFailure(String s) {}

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {}

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
      if(iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
        removePeer(id);
        mListener.onStatusChanged("DISCONNECTED");
      }
    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {}

    @Override
    public void onIceCandidate(final IceCandidate candidate) {
      try {
        JSONObject payload = new JSONObject();
        payload.put("label", candidate.sdpMLineIndex);
        payload.put("id", candidate.sdpMid);
        payload.put("candidate", candidate.sdp);
        sendMessage(id, "candidate", payload);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }

    @Override
    public void onError() {}

    @Override
    public void onAddStream(MediaStream mediaStream) {
        Log.d(TAG,"onAddStream "+mediaStream.label());

      // remote streams are displayed from 1 to MAX_PEER (0 is localStream)
      mListener.onAddRemoteStream(mediaStream, endPoint+1);
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
      mListener.onRemoveRemoteStream(mediaStream, endPoint);

      removePeer(id);
    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {}

    public Peer(String id, int endPoint) {
        Log.d(TAG,"new Peer: "+id + " " + endPoint);
      this.pc = factory.createPeerConnection(iceServers, pcConstraints, this);
      this.id = id;
      this.endPoint = endPoint;

      pc.addStream(lMS, new MediaConstraints());

      mListener.onStatusChanged("CONNECTING");
    }
  }

  public WebRtcClient(RTCListener listener, String host) {
    mListener = listener;
    factory = new PeerConnectionFactory();

    SocketIOClient.connect(host, new ConnectCallback() {

      @Override
      public void onConnectCompleted(Exception ex, SocketIOClient socket) {
        if (ex != null) {
            Log.e(TAG,"WebRtcClient connect failed: "+ex.getMessage());
          return;
        }
        Log.d(TAG,"WebRtcClient connected.");
        client = socket;

        // specify which events you are interested in receiving
        client.addListener("id", messageHandler);
        client.addListener("message", messageHandler);
        client.addListener("joined", messageHandler);
      }
    }, new Handler());

    iceServers.add(new PeerConnection.IceServer("stun:23.21.150.121"));
    iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));

    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
  }

  public void setCamera(String cameraFacing, String height, String width){
    MediaConstraints videoConstraints = new MediaConstraints();
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight", height));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", width));

    VideoSource videoSource = factory.createVideoSource(getVideoCapturer(cameraFacing), videoConstraints);
    lMS = factory.createLocalMediaStream("ARDAMS");
    lMS.addTrack(factory.createVideoTrack("ARDAMSv0", videoSource));
    lMS.addTrack(factory.createAudioTrack("ARDAMSa0"));

    mListener.onLocalStream(lMS);
  }

  private int findEndPoint() {
    for(int i = 0; i < MAX_PEER; i++) {
      if(!endPoints[i]) return i;
    }
    return MAX_PEER;
  }

  public void start(String name, boolean privacy){
    try {
        JSONObject message = new JSONObject();
        message.put("msg", new JSONObject().put("msg", "got user media"));
        message.put("room", "sojharo");
        client.emit("message", new JSONArray().put(message));
    } catch (JSONException e) {
      e.printStackTrace();
    }
  }

  /*
   Cycle through likely device names for the camera and return the first
   capturer that works, or crash if none do.
   */
  private VideoCapturer getVideoCapturer(String cameraFacing) {
    int[] cameraIndex = { 0, 1 };
    int[] cameraOrientation = { 0, 90, 180, 270 };
    for (int index : cameraIndex) {
      for (int orientation : cameraOrientation) {
        String name = "Camera " + index + ", Facing " + cameraFacing +
        ", Orientation " + orientation;
        VideoCapturer capturer = VideoCapturer.create(name);
        if (capturer != null) {
          return capturer;
        }
      }
    }
    throw new RuntimeException("Failed to open capturer");
  }

  private void addPeer(String id, int endPoint) {
    Peer peer = new Peer(id, endPoint);
    peers.put(id, peer);

    endPoints[endPoint] = true;
  }

  private void removePeer(String id) {
    Peer peer = peers.get(id);
    peer.pc.close();
    peer.pc.dispose();
    peers.remove(peer.id);

    endPoints[peer.endPoint] = false;
  }
}
包装fr.pchab.AndroidRTC;
导入android.app.Activity;
导入android.content.Intent;
导入android.content.pm.ActivityInfo;
导入android.content.res.Configuration;
导入android.graphics.Point;
导入android.os.Bundle;
导入android.view.Window;
导入android.widget.Toast;
导入org.json.JSONException;
导入org.webrtc.MediaStream;
导入org.webrtc.PeerConnectionFactory;
导入org.webrtc.VideoRenderer;
导入java.util.List;
公共类RTCAvity扩展活动实现WebRtcClient.RTCLIENT{
专用最终静态int视频呼叫发送=666;
私人视频流视图vsv;
私有WebRTC客户端;
私有字符串mSocketAddress;
私有字符串callerId;
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(窗口。功能\u无\u标题);
mSocketAddress=“https://”+getResources().getString(R.string.host);
mSocketAddress+=(“:”+getResources().getString(R.string.port)+“/”;
PeerConnectionFactory.initializeAndroidGlobals(此);
//摄像机显示视图
点显示大小=新点();
getWindowManager().getDefaultDisplay().getSize(displaySize);
vsv=新的视频流视图(此,显示大小);
client=新的WebRtcClient(这是mSocketAddress);
最终意图=getIntent();
最后一个字符串action=intent.getAction();
if(意图、行动和视图等于(行动)){
最终列表段=intent.getData().getPathSegments();
callerId=segments.get(0);
}
}
公共无效OnConfiguration已更改(配置newConfig)
{
super.onConfigurationChanged(newConfig);
setRequestedOrientation(ActivityInfo.SCREEN\u ORIENTATION\u横向);
}
@凌驾
公共无效暂停(){
super.onPause();
onPause();
}
@凌驾
恢复时公开作废(){
super.onResume();
onResume();
}
@凌驾
public void onCallReady(字符串callId){
startCam();
}
公共void应答(字符串callerId)抛出JSONException{
sendMessage(callerId,“init”,null);
startCam();
}
公共无效调用(字符串callId){
Intent msg=新的Intent(Intent.ACTION\u SEND);
msg.putExtra(Intent.EXTRA_TEXT,mSocketAddress+callId);
msg.setType(“文本/普通”);
startActivityForResult(Intent.createChooser(msg,“呼叫某人:”),视频呼叫发送);
}
@凌驾
受保护的void onActivityResult(int请求代码、int结果代码、意图数据){
if(requestCode==视频通话发送){
startCam();
}
}
公共无效startCam(){
setContentView(vsv);
//摄像机设置
客户端。设置摄像头(“前”、“640”、“480”);
client.start(“android_测试”,true);
}
@凌驾
状态更改时的公共void(最终字符串newStatus){
runOnUiThread(新的Runnable(){
@凌驾
公开募捐{
Toast.makeText(getApplicationContext(),newStatus,Toast.LENGTH_SHORT).show();
}
});
}
@凌驾
public void onLocalStream(MediaStream localStream){
localStream.videoTracks.get(0.addRenderer)(新的VideoRenderer(新的VideoCallbacks(vsv,0)));
}
@凌驾
addremotestream(MediaStream-remoteStream,int-endPoint)上的公共void{
remoteStream.videoTracks.get(0.addRenderer)(新的VideoRenderer(新的VideoCallbacks(vsv,端点));
vsv.shouldDraw[endPoint]=true;
}
@凌驾
公共void onRemoveToTestStream(MediaStream remoteStream,int端点){
remoteStream.videoTracks.get(0.dispose();
vsv.shouldDraw[endPoint]=false;
}
//实现细节:将VideoRenderer.Callbacks接口连接到
//视频流视图实现。
私有类VideoCallbacks实现VideoRenderer.Callbacks{
私人最终视频流视图;
私有最终整数流;
公共视频回调(视频流视图、int流){
this.view=视图;
this.stream=流;
}
@凌驾
公共无效设置大小(最终整型宽度、最终整型高度){
view.queueEvent(新的Runnable(){
公开募捐{
视图。设置大小(流、宽度、高度);
}
});
}
@凌驾
公共无效渲染帧(VideoRenderer.I420Frame){
view.queueFrame(流、帧);
}
}
}
webrtclient.java

package fr.pchab.AndroidRTC;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Window;
import android.widget.Toast;
import org.json.JSONException;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.VideoRenderer;

import java.util.List;

public class RTCActivity extends Activity implements WebRtcClient.RTCListener{

  private final static int VIDEO_CALL_SENT = 666;
  private VideoStreamsView vsv;
  private WebRtcClient client;
  private String mSocketAddress;
  private String callerId;


  @Override
  public void onCreate(Bundle savedInstanceState) {


    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);


    mSocketAddress = "https://" + getResources().getString(R.string.host);
    mSocketAddress += (":"+getResources().getString(R.string.port)+"/");

    PeerConnectionFactory.initializeAndroidGlobals(this);

    // Camera display view
    Point displaySize = new Point();
    getWindowManager().getDefaultDisplay().getSize(displaySize);
    vsv = new VideoStreamsView(this, displaySize);


    client = new WebRtcClient(this, mSocketAddress);

    final Intent intent = getIntent();
    final String action = intent.getAction();

    if (Intent.ACTION_VIEW.equals(action)) {
      final List<String> segments = intent.getData().getPathSegments();
      callerId = segments.get(0);
    }
  }

  public void onConfigurationChanged(Configuration newConfig)
  {
    super.onConfigurationChanged(newConfig);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  }

  @Override
  public void onPause() {
    super.onPause();
    vsv.onPause();
  }

  @Override
  public void onResume() {
    super.onResume();
    vsv.onResume();
  }

  @Override
  public void onCallReady(String callId) {
      startCam();
  }

  public void answer(String callerId) throws JSONException {
    client.sendMessage(callerId, "init", null);
    startCam();
  }


  public void call(String callId) {
    Intent msg = new Intent(Intent.ACTION_SEND);
    msg.putExtra(Intent.EXTRA_TEXT, mSocketAddress + callId);
    msg.setType("text/plain");
    startActivityForResult(Intent.createChooser(msg, "Call someone :"), VIDEO_CALL_SENT);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(requestCode == VIDEO_CALL_SENT) {
      startCam();
    }
  }

  public void startCam() {
    setContentView(vsv);
    // Camera settings
    client.setCamera("front", "640", "480");
    client.start("android_test", true);
  }

  @Override
  public void onStatusChanged(final String newStatus) {
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        Toast.makeText(getApplicationContext(), newStatus, Toast.LENGTH_SHORT).show();
      }
    });
  }

  @Override
  public void onLocalStream(MediaStream localStream) {
    localStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, 0)));
  }

  @Override
  public void onAddRemoteStream(MediaStream remoteStream, int endPoint) {
    remoteStream.videoTracks.get(0).addRenderer(new VideoRenderer(new VideoCallbacks(vsv, endPoint)));
    vsv.shouldDraw[endPoint] = true;
  }

  @Override
  public void onRemoveRemoteStream(MediaStream remoteStream, int endPoint) {
    remoteStream.videoTracks.get(0).dispose();
    vsv.shouldDraw[endPoint] = false;
  }

  // Implementation detail: bridge the VideoRenderer.Callbacks interface to the
  // VideoStreamsView implementation.
  private class VideoCallbacks implements VideoRenderer.Callbacks {
    private final VideoStreamsView view;
    private final int stream;

    public VideoCallbacks(VideoStreamsView view, int stream) {
      this.view = view;
      this.stream = stream;
    }

    @Override
    public void setSize(final int width, final int height) {
      view.queueEvent(new Runnable() {
        public void run() {
          view.setSize(stream, width, height);
        }
      });
    }

    @Override
    public void renderFrame(VideoRenderer.I420Frame frame) {
      view.queueFrame(stream, frame);
    }
  }
}
package fr.pchab.AndroidRTC;

import java.util.HashMap;
import java.util.LinkedList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;

import android.os.Handler;
import android.util.Log;

import com.koushikdutta.async.http.socketio.Acknowledge;
import com.koushikdutta.async.http.socketio.ConnectCallback;
import com.koushikdutta.async.http.socketio.EventCallback;
import com.koushikdutta.async.http.socketio.SocketIOClient;

class WebRtcClient {

  private final static int MAX_PEER = 2;
  private boolean[] endPoints = new boolean[MAX_PEER];
  private PeerConnectionFactory factory;
  private HashMap<String, Peer> peers = new HashMap<String, Peer>();
  private LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
  private MediaConstraints pcConstraints = new MediaConstraints();
  private MediaStream lMS;
  private RTCListener mListener;
  private SocketIOClient client;
  private final MessageHandler messageHandler = new MessageHandler();
  private final static String TAG = WebRtcClient.class.getCanonicalName();

  public interface RTCListener{
    void onCallReady(String callId);

    void onStatusChanged(String newStatus);

    void onLocalStream(MediaStream localStream);

    void onAddRemoteStream(MediaStream remoteStream, int endPoint);

    void onRemoveRemoteStream(MediaStream remoteStream, int endPoint);
  }

  private interface Command{
    void execute(String peerId, JSONObject payload) throws JSONException;
  }

  private class CreateOfferCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"CreateOfferCommand");
      Peer peer = peers.get(peerId);
      peer.pc.createOffer(peer, pcConstraints);
    }
  }

  private class CreateAnswerCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"CreateAnswerCommand");
      Peer peer = peers.get(peerId);
      SessionDescription sdp = new SessionDescription(
                                                      SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                                                      payload.getString("sdp")
                                                      );
      peer.pc.setRemoteDescription(peer, sdp);
      peer.pc.createAnswer(peer, pcConstraints);
    }
  }

  private class SetRemoteSDPCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"SetRemoteSDPCommand");
      Peer peer = peers.get(peerId);
      SessionDescription sdp = new SessionDescription(
                                                      SessionDescription.Type.fromCanonicalForm(payload.getString("type")),
                                                      payload.getString("sdp")
                                                      );
      peer.pc.setRemoteDescription(peer, sdp);
    }
  }

  private class AddIceCandidateCommand implements Command{
    public void execute(String peerId, JSONObject payload) throws JSONException {
        Log.d(TAG,"AddIceCandidateCommand");
      PeerConnection pc = peers.get(peerId).pc;
      if (pc.getRemoteDescription() != null) {
        IceCandidate candidate = new IceCandidate(
                                                  payload.getString("id"),
                                                  payload.getInt("label"),
                                                  payload.getString("candidate")
                                                  );
        pc.addIceCandidate(candidate);
      }
    }
  }

  public void sendMessage(String to, String type, JSONObject payload) throws JSONException {
    JSONObject message = new JSONObject();
    //message.put("room", to);
    message.put("type", type);
    message.put("msg", payload);
    message.put("room", "sojharo");
    client.emit("message", new JSONArray().put(message));
  }

  private class MessageHandler implements EventCallback {
    private HashMap<String, Command> commandMap;

    public MessageHandler() {
      this.commandMap = new HashMap<String, Command>();
      commandMap.put("init", new CreateOfferCommand());
      commandMap.put("offer", new CreateAnswerCommand());
      commandMap.put("answer", new SetRemoteSDPCommand());
      commandMap.put("candidate", new AddIceCandidateCommand());
    }

    @Override
    public void onEvent(String s, JSONArray jsonArray, Acknowledge acknowledge) {
      try {
          Log.d(TAG,"MessageHandler.onEvent() "+ (s == null ? "nil" : s));
        if(s.equals("id")) {

            JSONObject message = new JSONObject();

            message.put("room", "sojharo");
            message.put("username", "android");

            client.emit("create or join livehelp",
                    new JSONArray().put(message));

        } else if (s.equals("joined")) {
            mListener.onCallReady("Not Initiator");
        } else {

          JSONObject json = jsonArray.getJSONObject(0);


          try{
                if(json.getString("msg").equals("got user media"))
                    return ;
            }catch(JSONException e){}

            String from = json.getString("from");
            String type = null;
            try{
                type = json.getString("type");
            }catch(JSONException e){}


          // if peer is unknown, try to add him
          if(!peers.containsKey(from)) {
            // if MAX_PEER is reach, ignore the call
            int endPoint = findEndPoint();
            if(endPoint != MAX_PEER) {
              addPeer(from, endPoint);

              commandMap.get(type).execute(from, json);
            }
          } else {
            commandMap.get(type).execute(from, json);
          }
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
  }

  private class Peer implements SdpObserver, PeerConnection.Observer{
    private PeerConnection pc;
    private String id;
    private int endPoint;

    @Override
    public void onCreateSuccess(final SessionDescription sdp) {
      try {
        JSONObject payload = new JSONObject();
        payload.put("type", sdp.type.canonicalForm());
        payload.put("sdp", sdp.description);
        sendMessage(id, sdp.type.canonicalForm(), payload);
        pc.setLocalDescription(Peer.this, sdp);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }

    @Override
    public void onSetSuccess() {}

    @Override
    public void onCreateFailure(String s) {}

    @Override
    public void onSetFailure(String s) {}

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {}

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
      if(iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
        removePeer(id);
        mListener.onStatusChanged("DISCONNECTED");
      }
    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {}

    @Override
    public void onIceCandidate(final IceCandidate candidate) {
      try {
        JSONObject payload = new JSONObject();
        payload.put("label", candidate.sdpMLineIndex);
        payload.put("id", candidate.sdpMid);
        payload.put("candidate", candidate.sdp);
        sendMessage(id, "candidate", payload);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }

    @Override
    public void onError() {}

    @Override
    public void onAddStream(MediaStream mediaStream) {
        Log.d(TAG,"onAddStream "+mediaStream.label());

      // remote streams are displayed from 1 to MAX_PEER (0 is localStream)
      mListener.onAddRemoteStream(mediaStream, endPoint+1);
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
      mListener.onRemoveRemoteStream(mediaStream, endPoint);

      removePeer(id);
    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {}

    public Peer(String id, int endPoint) {
        Log.d(TAG,"new Peer: "+id + " " + endPoint);
      this.pc = factory.createPeerConnection(iceServers, pcConstraints, this);
      this.id = id;
      this.endPoint = endPoint;

      pc.addStream(lMS, new MediaConstraints());

      mListener.onStatusChanged("CONNECTING");
    }
  }

  public WebRtcClient(RTCListener listener, String host) {
    mListener = listener;
    factory = new PeerConnectionFactory();

    SocketIOClient.connect(host, new ConnectCallback() {

      @Override
      public void onConnectCompleted(Exception ex, SocketIOClient socket) {
        if (ex != null) {
            Log.e(TAG,"WebRtcClient connect failed: "+ex.getMessage());
          return;
        }
        Log.d(TAG,"WebRtcClient connected.");
        client = socket;

        // specify which events you are interested in receiving
        client.addListener("id", messageHandler);
        client.addListener("message", messageHandler);
        client.addListener("joined", messageHandler);
      }
    }, new Handler());

    iceServers.add(new PeerConnection.IceServer("stun:23.21.150.121"));
    iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302"));

    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
    pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
  }

  public void setCamera(String cameraFacing, String height, String width){
    MediaConstraints videoConstraints = new MediaConstraints();
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight", height));
    videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", width));

    VideoSource videoSource = factory.createVideoSource(getVideoCapturer(cameraFacing), videoConstraints);
    lMS = factory.createLocalMediaStream("ARDAMS");
    lMS.addTrack(factory.createVideoTrack("ARDAMSv0", videoSource));
    lMS.addTrack(factory.createAudioTrack("ARDAMSa0"));

    mListener.onLocalStream(lMS);
  }

  private int findEndPoint() {
    for(int i = 0; i < MAX_PEER; i++) {
      if(!endPoints[i]) return i;
    }
    return MAX_PEER;
  }

  public void start(String name, boolean privacy){
    try {
        JSONObject message = new JSONObject();
        message.put("msg", new JSONObject().put("msg", "got user media"));
        message.put("room", "sojharo");
        client.emit("message", new JSONArray().put(message));
    } catch (JSONException e) {
      e.printStackTrace();
    }
  }

  /*
   Cycle through likely device names for the camera and return the first
   capturer that works, or crash if none do.
   */
  private VideoCapturer getVideoCapturer(String cameraFacing) {
    int[] cameraIndex = { 0, 1 };
    int[] cameraOrientation = { 0, 90, 180, 270 };
    for (int index : cameraIndex) {
      for (int orientation : cameraOrientation) {
        String name = "Camera " + index + ", Facing " + cameraFacing +
        ", Orientation " + orientation;
        VideoCapturer capturer = VideoCapturer.create(name);
        if (capturer != null) {
          return capturer;
        }
      }
    }
    throw new RuntimeException("Failed to open capturer");
  }

  private void addPeer(String id, int endPoint) {
    Peer peer = new Peer(id, endPoint);
    peers.put(id, peer);

    endPoints[endPoint] = true;
  }

  private void removePeer(String id) {
    Peer peer = peers.get(id);
    peer.pc.close();
    peer.pc.dispose();
    peers.remove(peer.id);

    endPoints[peer.endPoint] = false;
  }
}
包装fr.pchab.AndroidRTC;
导入java.util.HashMap;
英普
       console.log(details.type);
       if(details.type !== 'init'){

            var otherClient = io.sockets.connected[details.to];

            if (!otherClient) {
              return;
            }

              delete details.to;
              details.from = client.id;
              otherClient.emit('message', details);

        }
        else
        {

            if (io.sockets.adapter.rooms[client.room] !== undefined ) {

                for(var member in io.sockets.adapter.rooms[client.room]){
                    console.log(member);
                    if(member !== client.id){
                        var otherClient = io.sockets.connected[member];

                        if (!otherClient) {
                          return;
                        }
                          delete details.to;
                          details.from = client.id;
                          otherClient.emit('message', details);
                      }
                      else{
                          console.log("no need to send self again!");
                      }
                }
            } else {
                    client.emit("update", "Please connect to a room.");
            }
        }
    });