我正在使用以下开源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)
});
如果有任何错误导致我无法在调试中找到它,我感到很困惑。记录这个非常难以阅读,因为它运行速度非常快,我无法捕捉到每一行。但显然,它一目了然。
请帮忙。感谢。
答案 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)
请从这里下载最新的libjingle
http://repo.spring.io/libs-release-remote/io/pristine/libjingle/