Android WebRTC setRemoteDescription

时间:2016-01-19 14:57:54

标签: java android websocket webrtc

我试图在我的Android应用中实施RTC。 我的Android客户端就是这个优惠。

我使用setLocalDescription并发送我的SessionDescription。 问题是当我创建自己的SessionDescription并尝试使用setRemoteDescription时 - 我得到一个响应,即我的SessionDescription为空,尽管它不是。 请参阅以下代码。

public class OfferActivity extends AppCompatActivity implements View.OnClickListener {

    final private String TAG = "App";

    private PeerConnectionFactory mFactory;
    private PeerConnection mPeerConnection;
    private DataChannel mDataChannel;
    private MediaConstraints mConstraints;

    PeerConnection.Observer mPeerConnectionObserver = new PeerConnection.Observer() {
        @Override
        public void onIceCandidate(IceCandidate iceCandidate) {
            IceCandidate candidate = new IceCandidate(iceCandidate.sdpMid, iceCandidate.sdpMLineIndex, "candidate");  // TODO: Edit
            Log.d(TAG, "pcObserver1 onIceCandidate() param: " + candidate.toString());
            mPeerConnection.addIceCandidate(candidate);
        }

        @Override
        public void onSignalingChange(PeerConnection.SignalingState signalingState) {
        }

        @Override
        public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        }

        @Override
        public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
        }

        @Override
        public void onAddStream(MediaStream mediaStream) {
        }

        @Override
        public void onRemoveStream(MediaStream mediaStream) {
        }

        @Override
        public void onDataChannel(DataChannel dataChannel) {
            mDataChannel = dataChannel;
            mDataChannel.registerObserver(mDataChannelObserver);
        }

        @Override
        public void onRenegotiationNeeded() {
        }
    };

    DataChannel.Observer mDataChannelObserver = new DataChannel.Observer() {
        @Override
        public void onStateChange() {
            Log.d(TAG, "mDataChannelObserver onStateChange() " + mDataChannel.state().name());

            if (mDataChannel.state() == DataChannel.State.OPEN) {
                String data = mEt.getText().toString();
                ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
                mDataChannel.send(new DataChannel.Buffer(buffer, false));
            }
        }

        @Override
        public void onMessage(DataChannel.Buffer buffer) {
            Log.d(TAG, "mDataChannelObserver onMessage()");
            if (buffer.binary == false) {
                int limit = buffer.data.limit();
                byte[] datas = new byte[limit];
                buffer.data.get(datas);
                final String tmp = new String(datas);
                Log.d(TAG, "mDataChannelObserver onMessage: " + tmp);
                addText("mDataChannelObserver", tmp);
            }
        }
    };

    SdpObserver mSdpLocalObserver = new SdpObserver() {
        @Override
        public void onCreateSuccess(SessionDescription desc) {

            final SessionDescription.Type typeEnum = desc.type;
            final String type = typeEnum.canonicalForm();
            final String sdp = desc.description;

            if (typeEnum == SessionDescription.Type.OFFER) {
                mPeerConnection.setLocalDescription(mSdpLocalObserver, desc);
                // TODO: Here we will have the code that gets the other peer sdp
            } else if (typeEnum == SessionDescription.Type.ANSWER) {
                mPeerConnection.setRemoteDescription(mSdpLocalObserver, desc);
            } else {


                Log.d(TAG, "Something else was found at onCreateSuccess");
            }
            // TODO: This is debug only. the "setLocalDescription" does not need javascript interfaces (JSON)
            try {
                final JSONObject json = new JSONObject();
                json.put("type", type);
                json.put("sdp", sdp);
                Log.d(TAG, "mSdpLocalObserver onCreateSuccess() > sdp: " + json.toString());
            } catch (org.json.JSONException ex) {
            }
        }

        @Override
        public void onSetSuccess() {
            Log.d(TAG, "mSdpLocalObserver onCreateSuccess()");
        }

        @Override
        public void onCreateFailure(String s) {
            Log.d(TAG, "mSdpLocalObserver onCreateFailure() " + s);
        }

        @Override
        public void onSetFailure(String s) {
            Log.d(TAG, "mSdpLocalObserver onSetFailure() " + s);
        }
    };

    private TextView mTv;
    private EditText mEt;
    private Button mBtn;
    private EditText mEtRegister;
    private Button mBtnRegister;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTv = (TextView) findViewById(R.id.mTv);
        mEt = (EditText) findViewById(R.id.mEt);
        mBtn = (Button) findViewById(R.id.mBtn);
        mEtRegister = (EditText) findViewById(R.id.mEtRegister);
        mBtnRegister = (Button) findViewById(R.id.mBtnRegister);
        mBtn.setOnClickListener(this);
        mBtnRegister.setOnClickListener(this);

        PeerConnectionFactory.initializeAndroidGlobals(getApplicationContext(), true, true, true, null);
        mFactory = new PeerConnectionFactory();

        final List<PeerConnection.IceServer> iceServers = new LinkedList<>();
        iceServers.add(new PeerConnection.IceServer("stun:xx.xx.xxx.xxx")); // TODO: Edit

        mConstraints = new MediaConstraints();
        mConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        mConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));

        mPeerConnecti

                on = mFactory.createPeerConnection(iceServers, mConstraints, mPeerConnectionObserver);

        mDataChannel = mPeerConnection.createDataChannel("test", new DataChannel.Init()); // TODO: Edit


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy()");
        if (mDataChannel != null) {
            mDataChannel.close();
            mDataChannel.unregisterObserver();
        }
        if (mPeerConnection != null) {
            mPeerConnection.close();


        }
    }

    @Override
    public void onClick(View v) {
        if (v == mBtnRegister) {
            String text = mEtRegister.getText().toString(); // .replace("\\r\\n","");
            final SessionDescription description = new SessionDescription(SessionDescription.Type.ANSWER, text);
            mPeerConnection.setRemoteDescription(mSdpLocalObserver, null);
        }
    }

    private DataChannel.Buffer send(String data) {
        ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
        return new DataChannel.Buffer(buffer, false);
    }

    private void addText(final String who, final String what) {
        OfferActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                final String text = mTv.getText().toString() + "\n";
                mTv.setText(text + who + ": " + what);
                mEt.setText("");
            }
        });
    }

}

我的日志:

01-19 16:12:51.447 9171-9239/com.walkme.rtc D/sample: pcObserver1 onRenegotiationNeeded()
01-19 16:12:51.879 9171-9239/com.walkme.rtc D/sample: pcObserver1 onSignalingChange() HAVE_LOCAL_OFFER
01-19 16:12:51.881 9171-9239/com.walkme.rtc D/sample: mSdpLocalObserver onCreateSuccess() > sdp: {"type":"offer","sdp":"v=0\r\no=- 8050881100630094562 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE data\r\na=msid-semantic: WMS\r\nm=application 9 RTP\/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:+f0buF4V2OXNT4sI\r\na=ice-pwd:\/QDilxDBndczNuvgPIBXZ7je\r\na=fingerprint:sha-256 E4:FB:1E:80:16:B8:4E:F9:B1:E3:81:B6:09:83:95:F3:B3:C2:34:DC:88:F4:C8:DF:9B:50:8A:00:0E:4D:AC:75\r\na=setup:actpass\r\na=mid:data\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:101 google-data\/90000\r\na=ssrc:1715303496 cname:NVNcmn2VpGpsfyFJ\r\na=ssrc:1715303496 msid:test test\r\na=ssrc:1715303496 mslabel:test\r\na=ssrc:1715303496 label:test\r\n"}
01-19 16:12:51.882 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() GATHERING
01-19 16:12:51.883 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() GATHERING
01-19 16:12:51.883 9171-9239/com.walkme.rtc D/sample: sdpObserver1 onCreateSuccess()
01-19 16:12:51.884 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:51.885 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:51.985 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:51.986 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:52.038 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:52.039 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:12:52.039 9171-9239/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() COMPLETE
01-19 16:13:32.985 9171-9239/com.walkme.rtc D/sample: sdpObserver1 onSetFailure() SessionDescription is NULL.
01-19 16:14:16.864 11776-11844/com.walkme.rtc D/sample: pcObserver1 onRenegotiationNeeded()
01-19 16:14:16.974 11776-11844/com.walkme.rtc D/sample: pcObserver1 onSignalingChange() HAVE_LOCAL_OFFER
01-19 16:14:16.977 11776-11844/com.walkme.rtc D/sample: mSdpLocalObserver onCreateSuccess() > sdp: {"type":"offer","sdp":"v=0\r\no=- 3146545619962464613 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE data\r\na=msid-semantic: WMS\r\nm=application 9 RTP\/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:W3sKNep8dXP\/Ind5\r\na=ice-pwd:oOy9NblGeZxRWL\/bxSnFU8KD\r\na=fingerprint:sha-256 78:2E:EF:58:AD:11:E3:29:34:7C:94:48:E7:DC:98:90:17:D6:5E:0B:DC:72:3E:4A:5A:35:7F:C5:F8:D4:06:81\r\na=setup:actpass\r\na=mid:data\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:101 google-data\/90000\r\na=ssrc:3989867427 cname:JKXfZ0vrlT1jdURT\r\na=ssrc:3989867427 msid:test test\r\na=ssrc:3989867427 mslabel:test\r\na=ssrc:3989867427 label:test\r\n"}
01-19 16:14:16.978 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() GATHERING
01-19 16:14:16.978 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() GATHERING
01-19 16:14:16.978 11776-11844/com.walkme.rtc D/sample: sdpObserver1 onCreateSuccess()
01-19 16:14:16.980 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:16.981 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:17.082 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:17.082 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:17.136 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:17.137 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceCandidate() param: data:0:candidate
01-19 16:14:17.138 11776-11844/com.walkme.rtc D/sample: pcObserver1 onIceGatheringChange() COMPLETE
01-19 16:14:22.769 11776-11844/com.walkme.rtc D/sample: sdpObserver1 onSetFailure() SessionDescription is NULL.
01-19 16:31:51.241 29355-29414/com.walkme.rtc D/sample: pcObserver1 onRenegotiationNeeded()

修改

经过进一步检查,问题出在编解码器上。 我所做的只是将数据作为json字符串获取,然后使用JsonObject。

2 个答案:

答案 0 :(得分:1)

您可以检查收到的sdp类型。 Web浏览器的webrtc库使用JSON对象作为sdp格式,但使用android的字符串。因此,当您从远程接收sdp字符串时,它可能包含JSON代码。

打印您的sdp字符串。如果它看起来像JSON格式,则将其转换为JSON对象并在其中获取sdp字符串。

//data is JSONObject received from signal server.
try {
    sdpJSON = new JSONObject(data.optString("sdp"));
} catch (JSONException e) {
    e.printStackTrace();
}
String sdp = sdpJSON.optString("sdp");

答案 1 :(得分:0)

我在setLocalSDP时遇到了类似的问题,并且使用了#34;会话为空&#34;得到了一个setFailure。 我检查了我的代码,发现我设置的AudioTrack和AudioSource ID字符串包含空格。随着我删除空间,问题解决了。 一堆问题sdp: a = ssrc:736062433 msid:媒体流1音轨a = ssrc:736062433 mslabel:媒体流1 a = ssrc:736062433标签:音轨1 然后将字符串更改为:

   private static final String AUDIO_TRACK_ID ="audio_track_1" ;

    private static final String LOCAL_MEDIA_STREAM_ID ="media_stream_1" ;``