Я пытаюсь отправить аудио-видео с Android на код в c #, для этого я использовал 2 примера Интернета:
WebRtc.NET: WebRTC для C # & C ++ /CLI: https://github.com/radioman/WebRtc.NET
Y
WebRTC android: https://github.com/NG-Studio-Development/vidiochat-rtc/blob/master/app/src/main/java/fr/pchab/androidrtc/RtcActivity.java
Чтобы это работало, я изменил очень мало элементарных строк на Android Webrtc, оставив что-то вроде этого:
package fr.pchab.webrtcclient;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import org.webrtc.*;
public class WebRtcClient {
private final static String TAG = WebRtcClient.class.getCanonicalName();
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 AudioSource audioSource;
private RtcListener mListener;
URI url = new URI("ws://192.168.1.8:9000");
Map<String, Command> commandMap = new HashMap<String, Command>();
WebSocketClient mWebSocketClient = new WebSocketClient(url) {
@Override
public void onOpen(ServerHandshake handshakedata) {
}
@Override
public void onMessage(String message) {
String from = null;
commandMap.put("init", new CreateOfferCommand());
commandMap.put("offer", new CreateAnswerCommand());
commandMap.put("OnSuccessAnswer", new SetRemoteSDPCommand());
commandMap.put("OnIceCandidate", new AddIceCandidateCommand());
JSONObject payload = null;
JSONObject data = null;
try {
data = new JSONObject(message);
} catch (JSONException e) {
e.printStackTrace();
}
try {
String type = data.getString("command");
if(type.equals("init")) {mListener.onCallReady("43343");
from = data.getString("from");
}
if(!peers.containsKey(from)) {
int endPoint = findEndPoint();
if(endPoint != MAX_PEER) {
try {
Peer peer = addPeer(from, endPoint);
peer.pc.addStream(localMS);
commandMap.get(type).execute(from, null);
}catch (Exception e) {
}
}
} else {
commandMap.get(type).execute(from, data);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
}
@Override
public void onError(Exception ex) {
}
};
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) {
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("sdp_mid"),
payload.getInt("sdp_mline_index"),
payload.getString("sdp")
);
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("command", type);
if (type.equals("OnIceCandidate")) {
message.put("candidate", payload);
} else {
message.put("desc", payload);
}
mWebSocketClient.send(String.valueOf(message));
}
private class Peer implements SdpObserver, PeerConnection.Observer {
public PeerConnection pc;
private PeerConnection pcss;
private String id;
private int endPoint;
@Override
public void onCreateSuccess(final SessionDescription sdp) {
// TODO: modify sdp to use pcParams prefered codecs
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 onIceConnectionReceivingChange(boolean b) {
}
@Override
public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
}
@Override
public void onIceCandidate(final IceCandidate candidate) {
try {
JSONObject payload = new JSONObject();
payload.put("sdpMLineIndex", candidate.sdpMLineIndex);
payload.put("sdpMid", candidate.sdpMid);
payload.put("candidate", candidate.sdp);
sendMessage(id,"OnIceCandidate",payload);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onAddStream(MediaStream mediaStream) {
Log.d(TAG, "onAddStream " + mediaStream.label());
mListener.onAddRemoteStream(mediaStream, endPoint + 1);
}
@Override
public void onRemoveStream(MediaStream mediaStream) {
Log.d(TAG, "onRemoveStream " + mediaStream.label());
removePeer(id);
}
@Override
public void onDataChannel(DataChannel dataChannel) {
}
@Override
public void onRenegotiationNeeded() {
}
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(localMS); //, new MediaConstraints()
mListener.onStatusChanged("CONNECTING");
}
}
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;
}
public WebRtcClient(RtcListener listener, PeerConnectionParameters params, EglBase.Context mEGLcontext) throws URISyntaxException {
mListener = listener;
pcParams = params;
PeerConnectionFactory.initializeAndroidGlobals(listener, true, true,
params.videoCodecHwAcceleration);
factory = new PeerConnectionFactory();
mWebSocketClient.connect();
iceServers.add(new PeerConnection.IceServer("stun:stun.stunprotocol.org:3478"));
iceServers.add(new PeerConnection.IceServer("stun:23.21.150.121"));iceServers.add(new PeerConnection.IceServer("stun:stun.anyfirewall.com:3478"));
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"));
}
/**
* 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.close();
}
factory.dispose();
mWebSocketClient.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
*/
public void start() {
setCamera();
}
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)));
videoSource = factory.createVideoSource(getVideoCapturer(), videoConstraints);
localMS.addTrack(factory.createVideoTrack("ARDAMSv0", videoSource));
}
audioSource = factory.createAudioSource(new MediaConstraints());
localMS.addTrack(factory.createAudioTrack("ARDAMSa0", audioSource));
mListener.onLocalStream(localMS);
}
private VideoCapturerAndroid getVideoCapturer() {
int numberOfCameras = CameraEnumerationAndroid.getDeviceCount();
if (numberOfCameras == 0) {
if (BuildConfig.DEBUG) {
Log.w(TAG, "Failed to open camera.");
}
return null;
} else {
String deviceName = null;
deviceName = CameraEnumerationAndroid.getNameOfFrontFacingDevice();
if (deviceName == null) {
deviceName = CameraEnumerationAndroid.getDeviceName(0);
}
VideoCapturerAndroid videoCapturer = VideoCapturerAndroid.create(deviceName, new VideoCapturerAndroid.CameraEventsHandler() {
@Override
public void onCameraError(String s) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCameraError: " + s);
}
}
@Override
public void onCameraFreezed(String s) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCameraFreezed: " + s);
}
}
@Override
public void onCameraOpening(int i) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCameraOpening: " + i);
}
}
@Override
public void onFirstFrameAvailable() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onFirstFrameAvailable: ");
}
}
@Override
public void onCameraClosed() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onCameraClosed: ");
}
}
});
return videoCapturer;
}
}
}
И в коде C # я добавил только несколько строк:
WebRTCServer.cs:
> server = new WebSocketServer(URL);
> server.Start(socket =>
> {
> socket.OnOpen = () =>
> {
> try
> {
> OnConnected(socket);
> JsonData j = new JsonData();
> j["command"] = "init";
> j["payload"] = "null";
> j["from"] = "dssdd";
> socket.Send(j.ToJson());
> }
> catch (Exception ex)
> {
> Debug.WriteLine($"OnConnected: {ex}");
> }
> };
> socket.OnMessage = message =>
Все работает:
Android подключается к C #, и это отправляет идентификатор, Android создает предложение, C # отвечает "ответ", Android отправляет кандидатов "OniceCandidate" и C # отправляет их, но я не могусмотрите видео андроида в c # ...
В чем ошибка?
Это SDP примера, который включен в проект c # webrtc, отправляемый браузером, когда все работает:
{"command": "offer", "desc": {"type": "offer", "sdp": "v = 0 \ r \ no = - 3749671025623748892 2 В IP4127.0.0.1 \ г \ нс= - \ r \ nt = 0 0 \ r \ na = группа: аудио-видео данные BUNDLE \ r \ na = семантическая семантика: WMS 95wgyGJiiigDyFS5umgHbvIDNV8tXSnuaJvw \ r \ nm = аудио 9 UDP / TLS / RTP / SAVPF 111 103 104 9 08 110 112 113 126 \ r \ nc = IN IP4 0.0.0.0 \ r \ na = rtcp: 9 IN IP4 0.0.0.0 \ r \ na = ice-ufrag: Qu5t \ r \ na = ice-pwd: GR / 7nOSN3iX6a +/ zijGFnAJm \ r \ na = варианты льда: струйка \ r \ na = отпечаток пальца: sha-256 C2: B6: 71: 98: 54: B1: 7F: 8C: 36: 18: 67: 24: 91: C0:E3: 04: D6: EC: B3: 59: 6E: D0: 17: D3: 45: 67: C5: 9F: D0: B0: BC: 1D \ г \ па = настройка: actpass \ г \ па = середина:audio \ r \ na = extmap: 1 urn: ietf: params: rtp-hdrext: ssrc-audio-level \ r \ na = recvonly \ r \ na = rtcp-mux \ r \ na = rtpmap: 111 opus / 48000 /2 \ r \ na = rtcp-fb: 111 transport-cc \ r \ na = fmtp: 111 minptime = 10; useinbandfec = 1 \ r \ na = rtpmap: 103 ISAC / 16000 \ r \ na = rtpmap: 104 ISAC /32000 \ r \ na = rtpmap: 9 G722 / 8000 \ r \ na = rtpmap: 0 PCMU / 8000 \ r \ na = rtpmap: 8 PCMA / 8000 \ r \ na = rtpmap: 110 телефонных событий / 48000 \ r \na = rtpmap: 112 телефонных событий / 32000 \ r \ na = rtpmap: 113 телефонных событий / 16000 \ r \ na = rtpmap: 126 телефонных событий / 8000 \ r \ nm = видео 9 UDP / TLS / RTP / SAVPF96 97 98 99 100 101 102 122 127 121 125 107 108109 124 120 123 119 114 \ r \ nc = IN IP4 0.0.0.0 \ r \ na = rtcp: 9 IN IP4 0.0.0.0 \ r \ na = ice-ufrag: Qu5t \ r \ na = ice-pwd: GR /7nOSN3iX6a + / zijGFnAJm \ r \ na = параметры льда: струйка \ r \ na = отпечаток пальца: sha-256 C2: B6: 71: 98: 54: B1: 7F: 8C: 36: 18: 67: 24: 91: C0: E3: 04: D6: EC: B3: 59: 6E: D0: 17: D3: 45: 67: C5: 9F: D0: B0: BC: 1D \ г \ па = настройка: actpass \ г \ па = середина: video \ r \ na = extmap: 2 urn: ietf: params: rtp-hdrext: toffset \ r \ na = extmap: 3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn: 3gpp: видео-ориентация \ r \ na = extmap: 5http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8 / 90000 \ r \ na = rtcp-fb: 96 Гуг-Ремб \ r \ na = rtcp-fb: 96transport-cc \ r \ na = rtcp-fb: 96 см3 пихты \ r \ na = rtcp-fb: 96 nack \ r \ na = rtcp-fb: 96 nack pli \ r \ na = rtpmap: 97 rtx / 90000 \r \ na = fmtp: 97 apt = 96 \ r \ na = rtpmap: 98 VP9 / 90000 \ r \ na = rtcp-fb: 98 goog-remb \ r \ na = rtcp-fb: 98 transport-cc \ r \na = rtcp-fb: 98 см3 ели \ r \ na = rtcp-fb: 98 nack \ r \ na = rtcp-fb: 98 nack pli \ r \ na = fmtp: 98 x-google-profile-id = 0 \r \ na = rtpmap: 99 rtx / 90000 \ r \ na = fmtp: 99 apt = 98 \ r \ na = rtpmap: 100 H264 / 90000 \ r \ na = rtcp-fb: 100 Гуг-Ремб \ r \ na =rtcp-fb: 100 транспорт-cc \ r \ na = rtcp-fb: 100 см 3-ой \ r \ na = rtcp-fb: 100 nack \ r \ na = rtcp-fb: 100 nack pli \ r \ na = fmtp: 100 допускается асимметрия уровня = 1; режим пакетирования = 1; идентификатор уровня профиля = 42001f \r \ na = rtpmap: 101 rtx / 90000 \ r \ na = fmtp: 101 apt = 100 \ r \ na = rtpmap: 102 H264 / 90000 \ r \ na = rtcp-fb: 102 Гуг-Ремб \ r \ na =rtcp-fb: 102 transport-cc \ r \ na = rtcp-fb: 102 куб. см ель \ r \ na = rtcp-fb: 102 nack \ r \ na = rtcp-fb: 102 nack pli \ r \ na = fmtp:102 level-асимметрия-разрешено = 1; режим пакетирования = 0; ID-уровня профиля = 42001f \ r \ na = rtpmap: 122 rtx / 90000 \ r \ na = fmtp: 122 apt = 102 \ r \ na = rtpmap: 127 H264 / 90000 \ r \ na = rtcp-fb: 127 Гуг-Ремб \ r \ na = rtcp-fb: 127 transport-cc \ r \ na = rtcp-fb: 127 куб.см пихты \ r \ na = rtcp-fb: 127 nack \ r \ na = rtcp-fb: 127 nack pli \ r \ na = fmtp: 127 level-асимметрия разрешена = 1; режим пакетирования = 1; идентификатор уровня профиля = 42e01f \ r \ na =rtpmap: 121 rtx / 90000 \ r \ na = fmtp: 121 apt = 127 \ r \ na = rtpmap: 125 H264 / 90000 \ r \ na = rtcp-fb: 125 goog-remb \ r \ na = rtcp-fb:125transport-cc \ r \ na = rtcp-fb: 125 см 3 ели \ r \ na = rtcp-fb: 125 nack \ r \ na = rtcp-fb: 125 nack pli \ r \ na = fmtp: 125 асимметрия уровняразрешено = 1; режим пакетирования = 0; идентификатор уровня профиля = 42e01f \ r \ na = rtpmap: 107 rtx / 90000 \ r \ na = fmtp: 107 apt = 125 \ r \ na = rtpmap: 108 H264 / 90000\ r \ na = rtcp-fb: 108 goog-remb \ r \ na = rtcp-fb: 108 transport-cc \ r \ na = rtcp-fb: 108 см3 пихты \ r \ na = rtcp-fb: 108 nack \r \ na = rtcp-fb: 108 nack pli \ r \ na = fmtp: 108 уровень-асимметрия-разрешено = 1; режим пакетирования = 1; идентификатор уровня профиля = 4d0032 \ r \ na = rtpmap: 109 RTX /90000 \ r \ na = fmtp: 109 apt = 108 \ r \ na = rtpmap: 124 H264 / 90000 \ r \ na = rtcp-fb: 124 Гуг-Ремб \ r \ na = rtcp-fb: 124 transport-cc \r \ na = rtcp-fb: 124 см3 пихты \ r \ na = rtcp-fb: 124 nack \ r \ na = rtcp-fb: 124 nack pli \ r \ na = fmtp: 124 допускается асимметрия уровней = 1;режим пакетирования = 1; идентификатор уровня профиля = 640032 \ r \ na = rtpmap: 120 rtx / 90000 \ r \ na = fmtp: 120 apt = 124 \ r \ na = rtpmap: 123 красный / 90000 \ r \ na= rtpmap: 119 rtx / 90000 \ r \ na = fmtp: 119 apt = 123 \ r \ na = rtpmap: 114 ulpfec / 90000 \ r \ na = ssrc-group: FID 4194873059 100873727 \ r \ na = ssrc: 4194873059 cname: Ni0yVpvQbRjE7vuV \ г \ па = SSRC: 4194873059 MSID: 95wgyGJiiigDyFS5umgHbvIDNV8tXSnuaJvw 74489e91-cf6f-4b77-bad0-877ae827e956 \ г \ па = SSRC: 4194873059 mslabel: 95wgyGJiiigDyFS5umgHbvIDNV8tXSnuaJvw \ г \ па = SSRC: 4194873059 этикетки: 74489e91-cf6f-4b77-bad0-877ae827e956 \ г \ па = SSRC:100873727 CNAME: Ni0yVpvQbRjE7vuV \ г \ па = SSRC: 100873727 MSID: 95wgyGJiiigDyFS5umgHbvIDNV8tXSnuaJvw 74489e91-cf6f-4b77-bad0-877ae827e956 \ г \ па = SSRC: 100873727 mslabel: 95wgyGJiiigDyFS5umgHbvIDNV8tXSnuaJvw \ г \ па = SSRC: 100873727 этикетки: 74489e91-cf6f-4b77-bad0-877ae827e956 \ r \ nm = приложение 9 DTLS / SCTP 5000 \ r \ nc = IN IP4 0.0.0.0 \ r \ na = ice-ufrag: Qu5t \ r \ na = ice-pwd: GR / 7nOSN3iX6a + / zijGFnAJm \r \ na = варианты льда: струйка \ r \ na = отпечаток пальца: sha-256 C2: B6: 71: 98: 54: B1: 7F: 8C: 36: 18: 67: 24: 91: C0: E3: 04: D6: EC: B3: 59: 6E: D0: 17: D3: 45: 67: С5: 9F: D0: В0: БК: 1D \ г \ па = настройка: actpass \ г \ па = середина: данные \ г\ na = sctpmap: 5000 webrtc-datachannel 1024 \ r \ n "}}
И он отправляется Android, когда он не работает:
{" команда":" offer "," desc ": {" type ":" offer "," sdp ":" v = 0 \ r \ no = - 3249596690369492550 2 IN IP4 127.0.0.1 \ r \ ns = - \ r \ nt = 0 0 \ r \ na = группа: BUNDLE аудио-видео \ r \ na = msid-семантическая: WMS ARDAMS \ r \ nm = аудио 9 UDP / TLS / RTP/ SAVPF 111 103 9 102 0 8 106 105 13 127 126 \ r \ nc = IN IP4 0.0.0.0 \ r \ na = rtcp: 9 IN IP4 0.0.0.0 \ r \ na = ice-ufrag: jPCWe7 + gO1oQqWy4 \ r\ na = ice-pwd: w4wHHFbcmRUO9RfUeu6pMpaZ \ r \ na = отпечаток пальца: sha-256 88: 8E: 42: C5: 1E: A2: CE: CA: 61: 84: DD: F6: D8: 0B: CD: 84:83: 88: 62: 26: 46: 9D: С6: 1F: АВ: 47: 1A: 08: С2: FF: 99: 93 \ г \ па = настройка: actpass \ г \ па = середина: аудио \ г \na = extmap: 1 urn: ietf: params: rtp-hdrext: ssrc-audio-level \ r \ na = extmap: 3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus / 48000/2 \ r \ na = fmtp: 111 minptime = 10;useinbandfec = 1 \ r \ na = rtpmap: 103 ISAC / 16000 \ r \ na = rtpmap: 9 G722 / 8000 \ r \ na = rtpmap: 102 ILBC / 8000 \ r \ na = rtpmap: 0 PCMU / 8000 \ r \na = rtpmap: 8 PCMA / 8000 \ r \ na = rtpmap: 106 CN / 32000 \ r \ na = rtpmap: 105 CN / 16000 \ r \ na = rtpmap: 13 CN / 8000 \ r \ na = rtpmap: 127 красный/ 8000 \ r \ na = rtpmap: 126 телефонных событий / 8000 \ r \ na = maxptime: 60 \ r \ na = ssrc: 3529019873 cname: mOSyu2KsIeUHPgGT \ r \ na = ssrc: 3529019873 msid: ARDAMS ARDAMSa0 \ r \ na= ssrc: 3529019873 mslabel: ARDAMS \ r \ na = ssrc: 3529019873 метка: ARDAMSa0 \ r \ nm = видео 9 UDP / TLS / RTP / SAVPF 100 101 116 117 96 \ r \ nc = IN IP4 0.0.0.0 \ r \na = rtcp: 9 IN IP4 0.0.0.0 \ r \ na = ice-ufrag: jPCWe7 + gO1oQqWy4 \ r \ na = ice-pwd: w4wHHFbcmRUO9RfUeu6pMpaZ \ r \ na = отпечаток пальца: sha-256 88: 8E: 42: C5:1E: A2: CE: CA: 61: 84: DD: F6: D8: 0B: CD: 84: 83: 88: 62: 26: 46: 9D: С6: 1F: АВ: 47: 1A: 08: С2:FF: 99: 93 \ r \ na = setup: actpass \ r \ na = mid: video \ r \ na = extmap: 2 urn: ietf: params: rtp-hdrext: toffset \ r \ na = extmap: 3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn: 3gpp: видео-ориентация \ r \ na = sendrecv \ r \ na = rtcp-mux \ r \ na = rtpmap: 100 VP8 / 90000 \ r \ na = rtcp-fb: 100 см 3 ели \ r \ na =rtcp-fb: 100 nack \ r \ na = rtcp-fb: 100 nack pli \ r \ na= rtcp-fb: 100 goog-remb \ r \ na = rtcp-fb: 100 transport-cc \ r \ na = rtpmap: 101 VP9 / 90000 \ r \ na = rtcp-fb: 101 см 3 ели \ r \ na =rtcp-fb: 101 nack \ r \ na = rtcp-fb: 101 nack pli \ r \ na = rtcp-fb: 101 goog-remb \ r \ na = rtcp-fb: 101 transport-cc \ r \ na = rtpmap: 116 красных / 90000 \ r \ na = rtpmap: 117 ulpfec / 90000 \ r \ na = rtpmap: 96RTX / 90000 \ r \ na = fmtp: 96 apt = 100 \ r \ na = ssrc-группа: FID 628832251 3674354975 \ r \ na = ssrc: 628832251 cname: mOSyu2KsIeUHPgGT \ r \ na = ssrc: 628832SMS1r \ na = ssrc: 628832251 mslabel: ARDAMS \ r \ na = ssrc: 628832251 метка: ARDAMSv0 \ r \ na = ssrc: 3674354975 cname: mOSyu2KsIeUHPgGT \ r \ na = ssrc: 3674SRMS MSRSRSID ms: ssrc: rsdSrc: rsdSrc: rsdSrc: msgrr:: 3674354975 mslabel: ARDAMS \ r \ na = ssrc: 3674354975 метка: ARDAMSv0 \ r \ n "}}
Я обнаружил, что разница между ними:
Первыйговорит "recvonly", а второй (android) говорит: "recvsend" Это будет проблемой, несовместимы ли кодеки?
Моя цель - отправить видео с Android на c #.
Это «ответ» c #, когда он работает с браузером:
URL: i.stack.imgur.com/0gcNn.jpg
И это «ответ», когда онНЕ работает с android:
URL: i.stack.imgur.com/2nc65.jpg
Как мне это решить?