官方文档地址 https://github.com/meetecho/janus-gateway
由于官方提供的andorid demo 是基于http c++的实现(https://github.com/meetecho/janus-mobile-sdk)对于android 过于复杂和有bug 所有使用ws 要简单的多
ws 安装后有以下日志会输出为成功
[WARN] libwebsockets has been built without IPv6 support, will bind to IPv4 only
libwebsockets logging: 0
WebSockets server started (port 8188)...
implementation 'org.webrtc:google-webrtc:1.0.26131' 可以用最新的
implementation 'com.github.dfqin:grantor:2.5'
implementation "org.java-websocket:Java-WebSocket:1.3.8"
如果不熟悉android webrtc的开发的可以参考https://www.jianshu.com/p/8c10146afd6c
主要对webscoket 的消息进行发送和接收 并把sdp信息给webrtc peerconntion
package com.liiln.janus5.echo;
import android.util.Log;
import com.liiln.janus5.janus.MyTools;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.extensions.IExtension;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.protocols.IProtocol;
import org.java_websocket.protocols.Protocol;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.IceCandidate;
import org.webrtc.SessionDescription;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
public class EchoWebSocketChannel extends WebSocketClient {
private ConcurrentHashMap attachedPlugins = new ConcurrentHashMap();
private ConcurrentHashMap transactions = new ConcurrentHashMap();
private BigInteger sessionId = null;
private Delegate _delegate = null;
public EchoWebSocketChannel(URI serverUri, Draft protocolDraft) {
super(serverUri, protocolDraft);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
//
createSession();
}
@Override
public void onMessage(String message) {
Log.e("提示收到消息》》》",message);
//
try {
JSONObject msg = new JSONObject(message);
String janus = msg.getString("janus");
if(janus.equals("success")){
String tid = msg.getString("transaction");
ITransaction transaction = transactions.get(tid);
if(transaction!=null){
transactions.remove(tid);
transaction.onSuccess(msg);
}
}else if(janus.equals("error")){
String tid = msg.getString("transaction");
ITransaction transaction = transactions.get(tid);
if(transaction!=null){
transactions.remove(tid);
transaction.onError();
}
}else if(janus.equals("ack")){
}else{
if(msg.has("sender")) {
BigInteger sender = new BigInteger(msg.getString("sender"));
PlugHandle handle = attachedPlugins.get(sender);
if (handle != null) {
if (janus.equals("event")) {
JSONObject data = msg.getJSONObject("plugindata").getJSONObject("data");
JSONObject jsep = null;
if(msg.has("jsep")){
jsep = msg.getJSONObject("jsep");
}
_delegate.onMessage(sender, data, jsep); //
} else if (janus.equals("detached")) {
_delegate.onLeaving(sender);//
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
}
@Override
public void onError(Exception ex) {
}
public interface Delegate{
void onMessage(BigInteger handleId, JSONObject msg, JSONObject jsep);
void onLeaving(BigInteger handleId);
void onAttached(BigInteger handleId);
}
public void setDelegate(Delegate delegate){
_delegate =delegate;
}
public static EchoWebSocketChannel init(String url) {
EchoWebSocketChannel websocket = null;
try {
ArrayList protocols = new ArrayList();
protocols.add(new Protocol("janus-protocol"));
Draft_6455 proto_janus = new Draft_6455(Collections.emptyList(), protocols);
websocket = new EchoWebSocketChannel(new URI(url),proto_janus);
} catch (URISyntaxException e) {
e.printStackTrace();
}
websocket.connect();
return websocket;
}
public void disconnect(){
stopKeepAliveTimer();
super.close();
}
public void sendmessage(String message){
Log.e("提示","send==>>"+message);
send(message);
}
private volatile Thread keep_alive = null;
boolean connected = false;
private void startKeepAliveTimer(){
connected = true;
keep_alive = new Thread(new Runnable() {
@Override
public void run() {
Thread thisThread = Thread.currentThread();
while (keep_alive == thisThread) {
try {
thisThread.sleep(25000);
} catch (InterruptedException ex) {
}
if (!connected) {
return;
}
JSONObject obj = new JSONObject();
try {
obj.put("janus", "keepalive");
obj.put("session_id", sessionId);
obj.put("transaction", MyTools.randomString(12));
sendmessage(obj.toString());
} catch (JSONException e) {
connected = false;
return;
}
}
}
}, "KeepAlive");
Log.e("提示","socket end");
keep_alive.start();
}
private void stopKeepAliveTimer(){
keep_alive = null;
connected = false;
}
private void createSession(){
String tid = MyTools.randomString(12);
transactions.put(tid, new ITransaction(tid) {
@Override
public void onSuccess(JSONObject msg) throws Exception{
JSONObject data = msg.getJSONObject("data");
sessionId = new BigInteger(data.getString("id"));
Log.e("===>","收到sessionId"+sessionId);
startKeepAliveTimer();
createHandle();
/**
JSONObject objx = new JSONObject();
objx.put("janus", "info");
objx.put("transaction", stringGenerator.randomString(12));
sendmessage(objx.toString());
**/
}
});
try{
JSONObject obj = new JSONObject();
obj.put("janus", "create");
obj.put("transaction", tid);
sendmessage(obj.toString());
}catch (Exception e){
e.printStackTrace();
}
}
private void createHandle(){
String tid = MyTools.randomString(12);
transactions.put(tid, new ITransaction(tid) {
@Override
public void onSuccess(JSONObject msg) throws Exception{
JSONObject data = msg.getJSONObject("data");
BigInteger handleId = new BigInteger(data.getString("id"));
Log.e("===>","handleId="+handleId);
_delegate.onAttached(handleId);
PlugHandle handle = new PlugHandle(handleId);
attachedPlugins.put(handleId,handle);
//registerUsrname(handleId);
}
});
try{
JSONObject obj = new JSONObject();
obj.put("janus", "attach");
obj.put("transaction", tid);
obj.put("plugin", "janus.plugin.echotest");
obj.put("session_id",sessionId);
sendmessage(obj.toString());
}catch (Exception e){
e.printStackTrace();
}
}
public void publisherCreateOffer(final BigInteger handleId, final SessionDescription sdp) {
JSONObject publish = new JSONObject();
JSONObject jsep = new JSONObject();
JSONObject message = new JSONObject();
try {
publish.putOpt("request", "configure");
publish.putOpt("audio", true);
publish.putOpt("video", true);
jsep.putOpt("type", sdp.type);
jsep.putOpt("sdp", sdp.description);
message.putOpt("janus", "message");
message.putOpt("body", publish);
message.putOpt("jsep", jsep);
message.putOpt("transaction", MyTools.randomString(12) );
message.putOpt("session_id", sessionId);
message.putOpt("handle_id", handleId);
} catch (JSONException e) {
e.printStackTrace();
}
sendmessage(message.toString());
}
public void trickleCandidate(final BigInteger handleId, final IceCandidate iceCandidate) {
JSONObject candidate = new JSONObject();
JSONObject message = new JSONObject();
try {
candidate.putOpt("candidate", iceCandidate.sdp);
candidate.putOpt("sdpMid", iceCandidate.sdpMid);
candidate.putOpt("sdpMLineIndex", iceCandidate.sdpMLineIndex);
message.putOpt("janus", "trickle");
message.putOpt("candidate", candidate);
message.putOpt("transaction", MyTools.randomString(12));
message.putOpt("session_id", sessionId);
message.putOpt("handle_id", handleId);
} catch (JSONException e) {
e.printStackTrace();
}
sendmessage(message.toString());
}
public void trickleCandidateComplete(final BigInteger handleId) {
JSONObject candidate = new JSONObject();
JSONObject message = new JSONObject();
try {
candidate.putOpt("completed", true);
message.putOpt("janus", "trickle");
message.putOpt("candidate", candidate);
message.putOpt("transaction", MyTools.randomString(12));
message.putOpt("session_id", sessionId);
message.putOpt("handle_id", handleId);
} catch (JSONException e) {
e.printStackTrace();
}
sendmessage(message.toString());
}
}
//额外类
public abstract class ITransaction {
public String _tid = null;
public ITransaction(String tid){
_tid = tid;
}
public void onError(){};
public void onSuccess(JSONObject data)throws Exception{};
}
public class PlugHandle {
private BigInteger _handleId = null;
public PlugHandle(BigInteger handleId){
_handleId = handleId;
}
}
1.创建PeerConnectionFactory 、PeerConnection
2.peerConnection.addStream(mediaStream);
3.peerConnection.createOffer 成功后将sdp 发送
_websocket.publisherCreateOffer(handleId,sdp);
4.发送后webscoket会收到anwer的sdp信息设置给peerConnection
peerConnection.setRemoteDescription
5.设置后peerConnection 的onAddStream会返回 video数据 用webrtc.SurfaceViewRenderer显示就行了
VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
runOnUiThread(() -> {
if(remoteVideoTrack!=null) remoteVideoTrack.addSink(remoteView);
});
6.ice的调用
trickleCandidate(handleId, candidate);和trickleCandidateComplete(handleId); 发送