WebRTC Android库功能未被调用

时间:2014-12-18 20:15:00

标签: android webrtc

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

https://github.com/pchab/AndroidRTC

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

https://github.com/pchab/ProjectRTC

为此,我需要对上述AndroidRTC应用程序的两个类进行一些更改。在此之后,当我启动应用程序时,它没有调用'createOffer()'或'createAnswer()'函数,它是libjingle_peerconnection库的一部分。我很困惑这两个函数是不是被调用了还是他们无法使用'sendMessage()'函数。

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

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

我的服务器代码已用于webrtc Web应用程序。 Web应用程序成功使用此服务器进行调用。它应该适用于这个Android应用程序,只需对应用程序进行少量修改。

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

RTCActivity.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);
    }
  }
}

WebRTCClient.java

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;
  }
}

该代码能够接收来自其他方的优惠和候选人。它无法将答案或候选人作为回报发送给该方。

我没有修改其他两个类,可以在上面的android应用程序链接中找到。

以下是用nodejs编写的socket.io服务器代码片段:

    socket.on('create or join livehelp', function (room) {
        var numClients = socketio.sockets.clients(room.room).length;

        if (numClients === 0){
            socket.join(room.room);
            socket.set('nickname', room.username);    
            socket.emit('created', room);
        } else if (numClients < 2) {
            socket.join(room.room);
            socket.set('nickname', room.username);    
            socket.emit('joined', room);

            socket.broadcast.to(room.room).emit('join', room);

        } else { // max three clients
            socket.emit('full', room.room);
        }

        console.log(socketio.sockets.manager.rooms)
        console.log(room)

    });


    socket.on('message', function (message) {
        //console.log('Got message:', message);

        //socket.broadcast.emit('message', message);

        message.msg.from = socket.id;

        //socketio.sockets.in(message.room).emit('message', message.msg);
        socket.broadcast.to(message.room).emit('message', message.msg);
        //console.log('Got message:', message.msg);
        //console.log(socketio.sockets.manager.rooms)

    });

如果有任何错误导致我无法在调试中找到它,我感到很困惑。记录这个非常难以阅读,因为它运行速度非常快,我无法捕捉到每一行。但显然,它一目了然。

请帮忙。感谢。

3 个答案:

答案 0 :(得分:0)

我认为你无法产生答案,但你能够产生报价?如果是这种情况,请尝试添加

pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));

到您的电脑限制。

答案 1 :(得分:0)

希望这会有所帮助。
 client.on(&#39; message&#39;,function(details){           的console.log(&#39;消息&#39;,details.to);

       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.");
            }
        }
    });

答案 2 :(得分:0)