您好我正在尝试保存从webrtc收到的远程流,我从git中获取了一些代码示例,尝试了各种方法来获取远程流,但是,无法从套接字或任何其他方式获取流,如果有人有任何想法请在这里建议我的WebRTCClient类的片段
这是我的班级:
package fr.pchab.webrtcclient;
import android.app.Activity;
import android.util.Log;
import android.widget.Toast;
import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioSource;
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.VideoCapturerAndroid;
import org.webrtc.VideoSource;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.LinkedList;
public class WebRtcClient {
private final static String TAG = "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<>();
private LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<>();
private PeerConnectionParameters pcParams;
private MediaConstraints pcConstraints = new MediaConstraints() {
};
private MediaStream localMS;
private VideoSource videoSource;
private RtcListener mListener;
private Socket client;
/**
* Implement this interface to be notified of events.
*/
public interface RtcListener {
void onCallReady(String callId);
void onStatusChanged(String newStatus);
void onLocalStream(MediaStream localStream);
void onAddRemoteStream(MediaStream remoteStream, int endPoint);
void onRemoveRemoteStream(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.e(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.e(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.e(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.e(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);
}
}
}
/**
* Send a message through the signaling server
*
* @param to id of recipient
* @param type type of message
* @param payload payload of message
* @throws JSONException
*/
public void sendMessage(String to, String type, JSONObject payload) throws JSONException {
JSONObject message = new JSONObject();
message.put("to", to);
message.put("type", type);
message.put("payload", payload);
client.emit("message", message);
}
private class MessageHandler {
private HashMap<String, Command> commandMap;
private MessageHandler() {
this.commandMap = new HashMap<>();
commandMap.put("init", new CreateOfferCommand());
commandMap.put("offer", new CreateAnswerCommand());
commandMap.put("answer", new SetRemoteSDPCommand());
commandMap.put("candidate", new AddIceCandidateCommand());
}
private Emitter.Listener onMessage = new Emitter.Listener() {
@Override
public void call(Object... args) {
JSONObject data = (JSONObject) args[0];
try {
String from = data.getString("from");
String type = data.getString("type");
JSONObject payload = null;
if (!type.equals("init")) {
payload = data.getJSONObject("payload");
}
// 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) {
Peer peer = addPeer(from, endPoint);
peer.pc.addStream(localMS);
commandMap.get(type).execute(from, payload);
}
} else {
commandMap.get(type).execute(from, payload);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
private Emitter.Listener onId = new Emitter.Listener() {
@Override
public void call(Object... args) {
String id = (String) args[0];
mListener.onCallReady(id);
}
};
}
private class Peer implements SdpObserver, PeerConnection.Observer, DataChannel.Observer {
private PeerConnection pc;
private String id;
private int endPoint;
@Override
public void onCreateSuccess(final SessionDescription sdp) {
// TODO: modify sdp to use pcParams prefered codecs
JSONObject payload = null;
try {
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();
}
Log.e("WebRtcClient", "WebRtcClient onCreateSuccess:" + payload);
}
@Override
public void onSetSuccess() {
Log.e("WebRtcClient", "WebRtcClient onSetSuccess:");
}
@Override
public void onCreateFailure(String s) {
Log.e("WebRtcClient", "WebRtcClient onCreateFailure:" + s);
}
@Override
public void onSetFailure(String s) {
Log.e("WebRtcClient", "WebRtcClient onSetFailure:" + s);
}
@Override
public void onSignalingChange(PeerConnection.SignalingState signalingState) {
Log.e("WebRtcClient", "WebRtcClient onSignalingChange:" + signalingState.name());
}
@Override
public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
removePeer(id);
mListener.onStatusChanged("DISCONNECTED");
} else if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED) {
}
Log.e("WebRtcClient", "WebRtcClient onIceConnectionChange:" + iceConnectionState);
}
@Override
public void onIceConnectionReceivingChange(boolean b) {
Log.e("WebRtcClient", "WebRtcClient onIceConnectionReceivingChange:" + b);
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
Log.e("WebRtcClient", "WebRtcClient onIceGatheringChange:" + iceGatheringState);
}
@Override
public void onIceCandidate(final IceCandidate candidate) {
JSONObject payload = null;
try {
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();
}
Log.e("WebRtcClient", "WebRtcClient onIceCandidate:" + payload);
}
@Override
public void onAddStream(MediaStream mediaStream) {
Log.e(TAG, "onAddStream " + mediaStream.label());
// remote streams are displayed from 1 to MAX_PEER (0 is localStream)
mListener.onAddRemoteStream(mediaStream, endPoint + 1);
Log.e("WebRtcClient", "WebRtcClient onAddStream:" + mediaStream.label());
}
@Override
public void onRemoveStream(MediaStream mediaStream) {
Log.e(TAG, "onRemoveStream " + mediaStream.label());
Log.e("WebRtcClient", "WebRtcClient onRemoveStream:" + mediaStream.label());
removePeer(id);
}
@Override
public void onRenegotiationNeeded() {
Log.e("WebRtcClient", "WebRtcClient onRenegotiationNeeded:");
}
@Override
public void onDataChannel(final DataChannel dataChannel) {
Log.e("onDataChannel", "onDataChannel:" + dataChannel.label());
dataChannel.registerObserver(this);
}
@Override
public void onMessage(DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
String command = new String(bytes);
Log.e(TAG, " onDataChannel-DcObserver " + command);
}
@Override
public void onStateChange() {
Log.e(TAG, "onDataChannel -DcObserver " + "onStateChange");
}
@Override
public void onBufferedAmountChange(long arg0) {
Log.e(TAG, " DcObserver " + arg0);
}
public Peer(String id, int endPoint) {
Log.e(TAG, "WebRtcClient new Peer: " + id + " " + endPoint);
this.pc = factory.createPeerConnection(iceServers, pcConstraints, this);
createDataChannel();
this.id = id;
this.endPoint = endPoint;
pc.addStream(localMS); //, new MediaConstraints()
mListener.onStatusChanged("CONNECTING");
}
private void createDataChannel() {
DataChannel.Init dcInit = new DataChannel.Init();
dcInit.id = 1;
dataChannel = pc.createDataChannel("sendDataChannel", dcInit);
dataChannel.registerObserver(this);
}
}
DataChannel dataChannel;
private Peer addPeer(String id, int endPoint) {
Peer peer = new Peer(id, endPoint);
peers.put(id, peer);
endPoints[endPoint] = true;
return peer;
}
private void removePeer(String id) {
Peer peer = peers.get(id);
mListener.onRemoveRemoteStream(peer.endPoint);
peer.pc.close();
peers.remove(peer.id);
endPoints[peer.endPoint] = false;
}
private Activity mContext;
public WebRtcClient(RtcListener listener, String host, PeerConnectionParameters params, Activity mContext) {
mListener = listener;
pcParams = params;
this.mContext = mContext;
PeerConnectionFactory.initializeAndroidGlobals(listener, true, true, true
/*params.videoCodecHwAcceleration, mEGLcontext*/);
factory = new PeerConnectionFactory();
MessageHandler messageHandler = new MessageHandler();
try {
client = IO.socket(host);
} catch (URISyntaxException e) {
e.printStackTrace();
}
client.on("id", messageHandler.onId);
client.on("message", messageHandler.onMessage);
client.connect();
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"));
pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
// pcConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "false"));
}
/**
* Call this method in Activity.onPause()
*/
public void onPause() {
if (videoSource != null) videoSource.stop();
}
/**
* Call this method in Activity.onResume()
*/
public void onResume() {
if (videoSource != null) videoSource.restart();
}
/**
* Call this method in Activity.onDestroy()
*/
public void onDestroy() {
for (Peer peer : peers.values()) {
peer.pc.dispose();
}
videoSource.dispose();
factory.dispose();
client.disconnect();
client.close();
}
private int findEndPoint() {
for (int i = 0; i < MAX_PEER; i++) if (!endPoints[i]) return i;
return MAX_PEER;
}
/**
* Start the client.
* <p>
* Set up the local stream and notify the signaling server.
* Call this method after onCallReady.
*
* @param name client name
*/
public void start(String name) {
setCamera();
try {
JSONObject message = new JSONObject();
message.put("name", name);
client.emit("readyToStream", message);
} catch (JSONException e) {
e.printStackTrace();
}
}
private void setCamera() {
localMS = factory.createLocalMediaStream("ARDAMS");
if (pcParams.videoCallEnabled) {
MediaConstraints videoConstraints = new MediaConstraints();
videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxHeight", Integer.toString(pcParams.videoHeight)));
videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxWidth", Integer.toString(pcParams.videoWidth)));
videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("maxFrameRate", Integer.toString(pcParams.videoFps)));
videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("minFrameRate", Integer.toString(pcParams.videoFps)));
VideoCapturer videoCapturer = getVideoCapturer();
if (videoCapturer != null) {
videoSource = factory.createVideoSource(videoCapturer, videoConstraints);
localMS.addTrack(factory.createVideoTrack("ARDAMSv0", videoSource));
} else {
}
}
AudioSource audioSource = factory.createAudioSource(new MediaConstraints());
localMS.addTrack(factory.createAudioTrack("ARDAMSa0", audioSource));
mListener.onLocalStream(localMS);
}
private void showMessage(final String msg) {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
});
}
private VideoCapturer getVideoCapturer() {
//Camera name empty will call the back cam bydefualt
return VideoCapturerAndroid.create("", new VideoCapturerAndroid.CameraEventsHandler() {
@Override
public void onCameraError(String s) {
Log.e("WebRtcClient", "WebRtcClient onCameraError:" + s);
}
@Override
public void onCameraFreezed(String s) {
Log.e("WebRtcClient", "WebRtcClient onCameraFreezed:" + s);
}
@Override
public void onCameraOpening(int i) {
Log.e("WebRtcClient", "WebRtcClient onCameraOpening:" + i);
// showMessage("Opening Camera id " + i);
}
@Override
public void onFirstFrameAvailable() {
Log.e("WebRtcClient", "WebRtcClient onFirstFrameAvailable:");
// showMessage("Camera onFirstFrameAvailable:");
}
@Override
public void onCameraClosed() {
Log.e("WebRtcClient", "WebRtcClient onCameraClosed:");
showMessage("Camera onCameraClosed");
}
});
}
}
引自link
答案 0 :(得分:0)
目前没有选项可以在Android上保存远程媒体流。您必须实现一个媒体服务器,它可以节省媒体流并在两个设备之间传递流。 Kurento是一个开源媒体服务器,我知道它提供了功能,但我没有使用它