red5源碼分析---7

來源:互聯網
上載者:User

標籤:

red5源碼分析—用戶端處理connect命令並發送createStream命令

在《red5源碼分析—5》中提到過,當用戶端發送connect命令後,伺服器經過處理會將其connect命令返回,不同的是伺服器返回的結果包含了一些串連後需要發送給用戶端的資訊,包括伺服器版本、模式等等。當返回的資訊經過伺服器的發送過濾器RTMPMinaProtocolEncoder時,會調用其中的RTMPProtocolEncoder的encodeCommand函數,下面來看其中的一段代碼,

    protected void encodeCommand(IoBuffer out, ICommand command) {        Output output = new org.red5.io.amf.Output(out);        final IServiceCall call = command.getCall();        final boolean isPending = (call.getStatus() == Call.STATUS_PENDING);        if (!isPending) {            Serializer.serialize(output, call.isSuccess() ? "_result" : "_error");        } else {            final String action = (call.getServiceName() == null) ? call.getServiceMethodName() : call.getServiceName() + ‘.‘ + call.getServiceMethodName();            Serializer.serialize(output, action);        }        ...    }

這裡可以簡單看出,如果經過處理後的call的狀態不是STATUS_PENDING,並且處理成功,則返回”_result”,否則返回”_error”。是否處理成功由Call的isSuccess方法判斷,

    public boolean isSuccess() {        return (status == STATUS_SUCCESS_RESULT) || (status == STATUS_SUCCESS_NULL) || (status == STATUS_SUCCESS_VOID);    }

因此,只要Call的狀態是STATUS_SUCCESS_RESULT、STATUS_SUCCESS_NULL或者STATUS_SUCCESS_VOID就可以判定為處理成功了。如果call的狀態是STATUS_PENDING,則根據情況返回方法名,或者服務名加上方法名。
根據上面的分析結果回顧伺服器對connect命令的處理,如果串連成功串連上伺服器的某個scope後,便會設定Call的狀態為STATUS_SUCCESS_RESULT,也因此返回的方法名(serviceMethodName)為_result。因此,當伺服器處理完connect命令後訊息返回用戶端時,
便調用BaseRTMPClientHandler的onCommand函數,如下

    protected void onCommand(RTMPConnection conn, Channel channel, Header source, ICommand command) {        final IServiceCall call = command.getCall();        final String methodName = call.getServiceMethodName();        if ("_result".equals(methodName) || "_error".equals(methodName)) {            final IPendingServiceCall pendingCall = conn.getPendingCall(command.getTransactionId());            if (pendingCall != null) {                if ("connect".equals(methodName)) {                    Integer encoding = (Integer) connectionParams.get("objectEncoding");                    if (encoding != null && encoding.intValue() == 3) {                        conn.getState().setEncoding(IConnection.Encoding.AMF3);                    }                }            }            handlePendingCallResult(conn, (Invoke) command);            return;        }        ...    }

根據前面的分析,當伺服器返回的訊息到達用戶端後,最後會調用handlePendingCallResult函數進行處理,handlePendingCallResult定義在BaseRTMPHandler中,

    protected void handlePendingCallResult(RTMPConnection conn, Invoke invoke) {        final IServiceCall call = invoke.getCall();        final IPendingServiceCall pendingCall = conn.retrievePendingCall(invoke.getTransactionId());        if (pendingCall != null) {            Object[] args = call.getArguments();            if (args != null && args.length > 0) {                pendingCall.setResult(args[0]);            }            Set<IPendingServiceCallback> callbacks = pendingCall.getCallbacks();            if (!callbacks.isEmpty()) {                HashSet<IPendingServiceCallback> tmp = new HashSet<IPendingServiceCallback>();                tmp.addAll(callbacks);                for (IPendingServiceCallback callback : tmp) {                    try {                        callback.resultReceived(pendingCall);                    } catch (Exception e) {                    }                }            }        }    }

首先通過retrievePendingCall根據事務ID擷取pendingCall,

    public IPendingServiceCall retrievePendingCall(int invokeId) {        return pendingCalls.remove(invokeId);    }

該pendingCall是在TCP建立串連後的調用BaseRTMPClientHandler的connectionOpened中根據事務ID註冊的(《red5源碼分析—3》)。獲得PendingCall後,就設定結果,這裡注意一點,也就是伺服器最後設定的結果results經過RTMP的編解碼(amf)處理後到達這裡會變為參數params(具體的可以查看轉碼器RTMPProtocolEncoder和RTMPProtocolDecoder的對應關係)。最後通過resultReceived調用之前註冊的回呼函數,根據《red5源碼分析—1》,該註冊的回呼函數如下,

    public void resultReceived(IPendingServiceCall call) {         Object result = call.getResult();          if (result instanceof ObjectMap) {              if ("connect".equals(call.getServiceMethodName())) {                  createStream(this);              }        } else {              if ("createStream".equals(call.getServiceMethodName())) {                  if (result instanceof Integer) {                      Integer streamIdInt = (Integer) result;                      // int streamId = streamIdInt.intValue();                      // publish(streamId, "testgio2", "live", this);                      invoke("getRoomsInfo", this);                  } else {                      disconnect();                  }              } else if ("getRoomsInfo".equals(call.getServiceMethodName())) {                  ArrayList<String> list = (ArrayList<String>) result;                  for (int i = 0; i < list.size(); i++) {                      System.out.println(list.get(i));                  }              }          }      }

因此,用戶端再收到connect命令的結果後立即調用createStream來建立一個流,

    public void createStream(IPendingServiceCallback callback) {        IPendingServiceCallback wrapper = new CreateStreamCallBack(callback);        invoke("createStream", null, wrapper);    }

CreateStreamCallBack和處理回呼函數有關係,回頭再分析。下面就是發送一個”createStream”的命令給用戶端了。下一章看看伺服器是如何處理”createStream”命令的。

red5源碼分析---7

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.