当前位置: 首页 > 工具软件 > owt > 使用案例 >

OWT-client-android源码分析

王杰
2023-12-01

一,本文目的

帮助理解OWT-client-android是如何使用webrtc 代码库的;

帮助理解OWT-client-android如何与OWT Server交互,接口协议的功能实现;

二,功能概述和模块关系

编译OWT android客户端,涉及https://github.com/open-webrtc-toolkit 的3个目录,刚开始容易让人不明白。

owt-deps-webrtc 是OWT项目用到的webrtc源码,目前版本是m88,主要增加支持了h265编码。

编译owt-client-native, 包含自动下载owt-deps-webrtc;

owt-client-native是OWT项目基于webrtc做的二次开发,主要实现了以下功能:

1,实现PeerConnectionChannel,主要封装了webrtc peerconnection

2, 在win和linux, 加入了msdk的外部编解码器,(调用intel GPU编解码器)

3,在win实现了videorendererd3d11, d3d11的render?

4, 实现了会议功能和呼叫,p2psdk/conference, sdk/p2p

5,实现了全部SDK模块的object C封装,sdk/base/objc, sdk/conference/objc, sdk/p2p/objc

编译owt-client-android,需要用到owt-client-native编译输出的so和jar文件;

oem@svr1804://home/oem/git/owt-client-android/dependencies/libwebrtc$ ll
total 8
drwxrwxr-x 2 oem oem 4096 4月  23 22:41 ./
drwxrwxr-x 3 oem oem 4096 4月  19 09:50 ../
lrwxrwxrwx 1 oem oem   49 4月  23 22:41 arm64-v8a -> /home/oem/git/native/src/out/dist/debug/arm64-v8a/
lrwxrwxrwx 1 oem oem   53 4月  23 22:41 libwebrtc.jar -> /home/oem/git/native/src/out/dist/debug/libwebrtc.jar

三,对象创建和初始化连接过程

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
protected void onCreate(Bundle savedInstanceState) {

        initConferenceClient();

private void initConferenceClient() {
        conferenceClient = new ConferenceClient(configuration);
        conferenceClient.addObserver(this);

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
 public ConferenceClient(ConferenceClientConfiguration configuration) {

Connect (join room)启动过程:

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
private View.OnClickListener joinRoom = new View.OnClickListener() {
//向服务器获取令牌,例如 uri=https://192.168.1.106:3004/createToken/, 提供username,room参数
        String uri = serverUrl + "/createToken/";
        String token = HttpUtils.request(uri, "POST", joinBody.toString(), true);

        conferenceClient.join(token, new ActionCallback<ConferenceInfo>() {

//创建SignalingChannel实例,保存token, 调用connect(
src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
    public synchronized void join(String token, ActionCallback<ConferenceInfo> callback) {
        signalingChannel = new SignalingChannel(token, this);
        signalingChannel.connect(configuration);
    }

src/sdk/conference/src/main/java/owt/conference/SignalingChannel.java
   SignalingChannel(String token, SignalingChannelObserver observer) {
        this.token = token;
        this.observer = observer;
    }

    void connect(final ConferenceClientConfiguration configuration) {
        try {
            //使用之前创建的令牌,创建IO.socket,例如 url= https://192.168.1.106:8080
            socketClient = IO.socket(url, opt);
            // Do not listen EVENT_DISCONNECT event on this phase.
            socketClient.on(Socket.EVENT_CONNECT, connectedCallback)
                    .on(Socket.EVENT_CONNECT_ERROR, connectErrorCallback)
                    .on(Socket.EVENT_RECONNECTING, reconnectingCallback)

            socketClient.connect();

Connect (join room)连接成功返回过程:

src/sdk/conference/src/main/java/owt/conference/SignalingChannel.java
    private final Listener connectedCallback = args -> callbackExecutor.execute(() -> {
                login();

//通过socket发送login,loginInfo参数:token,userAgent,protocol;
//登录房间成功,回调observer.onRoomConnected()
private void login() throws JSONException {
        socketClient.emit("login", loginInfo,
                (Ack) (Object... args) -> callbackExecutor.execute(() -> {
                        observer.onRoomConnected((JSONObject) args[1]);

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
public void onRoomConnected(final JSONObject info) {
        callbackExecutor.execute(() -> {
            ConferenceInfo conferenceInfo;
            try {
                    joinCallback.onSuccess(conferenceInfo);

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
public void onSuccess(ConferenceInfo conferenceInfo) {
                        requestPermission();

private void requestPermission() {
        onConnectSucceed();

//切换到会议界面
private void onConnectSucceed() {

四,publish发布流过程

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
    private View.OnClickListener publish = new View.OnClickListener() {
        public void onClick(View v) {
//创建capturer,并关联到localStream,localStream再附加到localRenderer;
                capturer = OwtVideoCapturer.create(vga ? 640 : 1280, vga ? 480 : 720, 30, true,
                        isCameraFront);
                localStream = new LocalStream(capturer,
                        new MediaConstraints.AudioTrackConstraints());
                localStream.attach(localRenderer);
//成功回调,调整UI,获取streams 
 ActionCallback<Publication> callback = new ActionCallback<Publication>() {
                    @Override
                    public void onSuccess(final Publication result) {
                        runOnUiThread(() -> {

                            String uri = serverUrl
                                    + "/rooms/" + conferenceInfo.id()
                                    + "/streams/" + result.id();

                    //失败返回,调整UI 
                    public void onFailure(final OwtError error) {


                conferenceClient.publish(localStream, setPublishOptions(), callback);

发出publish信令,执行publish;

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
    public synchronized void publish(final LocalStream localStream, final PublishOptions options,
            final ActionCallback<Publication> callback) {
//发送publish信令消息
        sendSignalingMessage("publish", publishMsg, args -> {
                if (extractMsg(0, args).equals("ok")) {
//创建一个只发送的ConferencePeerConnectionChannel,不接收音视频
                        // Do not receive video and audio for publication cpcc.
                        ConferencePeerConnectionChannel pcChannel =
                                getPeerConnection(result.getString("id"), false, false);
//pcChannel执行publish
                        pcChannel.publish(localStream, options);

//发送publish信令消息
   void sendSignalingMessage(final String type, final JSONObject message, final Ack ack) {
            signalingChannel.sendMsg(type, message, ack);

src/sdk/conference/src/main/java/owt/conference/SignalingChannel.java
    void sendMsg(String type, JSONObject msg, Ack ack) {
                socketClient.emit(type, msg, ack);

//pcChannel执行publish, addStream(), createOffer();
src/sdk/conference/src/main/java/owt/conference/ConferencePeerConnectionChannel.java
   void publish(LocalStream localStream, PublishOptions options) {
        stream = localStream;
        addStream(GetMediaStream(localStream));
        createOffer();

src/sdk/base/src/main/java/owt/base/PeerConnectionChannel.java
//对peerConnection添加audioTracks,videoTracks, 关联audioRtpSenders,videoRtpSenders
protected void addStream(final MediaStream mediaStream) {

protected void createOffer() {
        peerConnection.createOffer(PeerConnectionChannel.this, sdpConstraints);

    public void onCreateSuccess(final SessionDescription sessionDescription) {
            observer.onLocalDescription(key, localSdp);

peerConnection.createOffer()成功返回之后的流程:

src/sdk/base/src/main/java/owt/base/PeerConnectionChannel.java
protected void createOffer() {
        peerConnection.createOffer(PeerConnectionChannel.this, sdpConstraints);

    public void onCreateSuccess(final SessionDescription sessionDescription) {
            observer.onLocalDescription(key, localSdp);

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
    public void onLocalDescription(final String id, final SessionDescription localSdp) {
            // send local SDP
            sendSignalingMessage("soac", msg, null);
//收到soac消息
    public void onProgressMessage(JSONObject msg) {
                case "soac":
                    pcChannel.processSignalingMessage(msg.getJSONObject("data"));
//收到soac消息, setRemoteDescription(), soac消息携带remote SDP ?
src/sdk/base/src/main/java/owt/base/PeerConnectionChannel.java
public void processSignalingMessage(JSONObject data) throws JSONException {
            setRemoteDescription(remoteSdp);

  private void setRemoteDescription(final SessionDescription remoteDescription) {
            peerConnection.setRemoteDescription(PeerConnectionChannel.this, remoteDescription);

//收到ready消息,publish成功完成

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
    public void onProgressMessage(JSONObject msg) {
                case "ready":
                    processAck(msg.getString("id"));

   private void processAck(final String id) {
            if (pubCallbacks.containsKey(id)) {
                callback.onSuccess(publication);
            }
            if (subCallbacks.containsKey(id)) {
                callback.onSuccess(subscription);
            }
   
//刷新界面
src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
private View.OnClickListener publish = new View.OnClickListener() {
                    public void onSuccess(final Publication result) {
                        runOnUiThread(() -> {

五,subscribe订阅流过程

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
    private View.OnClickListener subscribe = new View.OnClickListener() {
        public void onClick(View v) {
            //显示"Remote Stream List"对话框,选择一个stream,接着显示编码格式选择对话框
            singleChoiceDialog.setPositiveButton("ok",
                    (dialog, which) -> chooseCodec(

    public void chooseCodec(RemoteStream remoteStream) {
    //编码格式选择对话框
                    if (simulcastStreamMap.containsKey(remoteStream.id())) {
                        chooseRid(remoteStream, chooseVideoCodec);
                    } else {
                        subscribeForward(remoteStream, chooseVideoCodec, null);
                    }

    public void subscribeForward(RemoteStream remoteStream, String videoCodec, String rid) {
        conferenceClient.subscribe(remoteStream, options,
                new ActionCallback<Subscription>() {
                    //订阅成功
                    public void onSuccess(Subscription result) {
                        remoteStream.attach(remoteRenderer);
                        runOnUiThread(() -> {
                            subscribeBtn.setVisibility(View.GONE);
                            unSubscribeBtn.setVisibility(View.VISIBLE);
                    //订阅失败
                    public void onFailure(OwtError error) {

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java                
               sendSignalingMessage("subscribe", subscribeMsg, args -> {
 //发送"subscribe"信令,收到成功的‘ok’消息;创建pcChannel,调用 pcChannel.subscribe
                         ConferencePeerConnectionChannel pcChannel =
                                getPeerConnection(result.getString("id"), subVideo, subAudio);
                        pcChannel.subscribe(remoteStream, options);

src/sdk/conference/src/main/java/owt/conference/ConferencePeerConnectionChannel.java
    void subscribe(RemoteStream remoteStream, SubscribeOptions options) {
        createOffer();

    protected void createOffer() {
            peerConnection.createOffer(PeerConnectionChannel.this, sdpConstraints);

createOffer成功返回:

src/sdk/base/src/main/java/owt/base/PeerConnectionChannel.java
    public void onCreateSuccess(final SessionDescription sessionDescription) {
            observer.onLocalDescription(key, localSdp);
      peerConnection.setLocalDescription(PeerConnectionChannel.this, localSdp);

src/sdk/conference/src/main/java/owt/conference/ConferenceClient.java
    public void onLocalDescription(final String id, final SessionDescription localSdp) {
            // send SDP offer to OWT server
            sendSignalingMessage("soac", msg, null);

    public void onProgressMessage(JSONObject msg) {
            switch (msg.getString("status")) {
                case "soac":
                //收到SDP answer消息;
                    pcChannel.processSignalingMessage(msg.getJSONObject("data"));
                    break;
                case "ready":
                //收到ready消息,成功返回
                    processAck(msg.getString("id"));

    private void processAck(final String id) {
                callback.onSuccess(subscription);

src/sample/conference/src/main/java/owt/sample/conference/MainActivity.java
public void subscribeForward(RemoteStream remoteStream, String videoCodec, String rid) {
        conferenceClient.subscribe(remoteStream, options,
                public void onSuccess(Subscription result) {
               //subscribe remoteStream 成功,刷新界面,开始渲染视频
                        remoteStream.attach(remoteRenderer);
                        runOnUiThread(() -> {
                            subscribeBtn.setVisibility(View.GONE);
                            unSubscribeBtn.setVisibility(View.VISIBLE);

 类似资料: