red5源码分析---9

red5源码分析—客户端publish流

接着上一章的分析结果,参考《red5源码分析—7》的分析结论,当服务器返回steamId后,客户端会执行BaseRTMPClientHandler的onCommand函数,onCommand函数会根据返回的方法名”_result”开始执行handlePendingCallResult函数,handlePendingCallResult会获取之前注册的回调函数,根据《red5源码分析—7》,该回调函数就为CreateStreamCallBack,获取回调函数后,就会执行该回调函数的resultReceived函数,下面来看,

        public void resultReceived(IPendingServiceCall call) {
            Number streamId = (Number) call.getResult();
            if (conn != null && streamId != null) {
                NetStream stream = new NetStream(streamEventDispatcher);
                stream.setConnection(conn);
                stream.setStreamId(streamId);
                conn.addClientStream(stream);
                NetStreamPrivateData streamData = new NetStreamPrivateData();
                streamData.outputStream = conn.createOutputStream(streamId);
                streamData.connConsumer = new ConnectionConsumer(conn, streamData.outputStream.getVideo(), streamData.outputStream.getAudio(), streamData.outputStream.getData());
                streamDataMap.put(streamId, streamData);
            }
            wrapped.resultReceived(call);
        }

这里首先取出服务器分配的streamId,然后构造一个NetStream并进行相应的设置,NetStream用来处理后面有关流的事件,后面会分析到。接下来通过addClientStream向RTMPMinaConnection设置刚刚创建的NetStream,定义在其父类RTMPConnection中,

    public void addClientStream(IClientStream stream) {
        if (reservedStreams.add(stream.getStreamId().doubleValue())) {
            registerStream(stream);
        } else {

        }
    }

addClientStream首先向reservedStreams注册streamId,然后通过registerStream注册,

    private boolean registerStream(IClientStream stream) {
        if (streams.putIfAbsent(stream.getStreamId().doubleValue(), stream) == null) {
            usedStreams.incrementAndGet();
            return true;
        }
        return false;
    }

这里就是根据streamId注册该stream。

回到resultReceived中,接下来构造NetStreamPrivateData,接着通过createOutputStream函数创建输出流,

    public OutputStream createOutputStream(Number streamId) {
        int channelId = getChannelIdForStreamId(streamId);
        final Channel data = getChannel(channelId++);
        final Channel video = getChannel(channelId++);
        final Channel audio = getChannel(channelId++);
        return new OutputStream(video, audio, data);
    }

这里就是构造三个Channel,分别用来发送数据、音频和视频,然后构造OutputStream。

再回到resultReceived中,接下来创建ConnectionConsumer,并通过streamId设置进streamDataMap中,最后执行另一个回调函数resultReceived,

    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));
                }
            }
        }
    }

相比前几章,这里对resultReceived的createStream对应的方法部分作了相应的改写,注释了”getRoomsInfo”部分。

publish定义在BaseRTMPClientHandler中,

    public void publish(Number streamId, String name, String mode, INetStreamEventHandler handler) {
        if (handler != null) {
            NetStreamPrivateData streamData = streamDataMap.get(streamId);
            if (streamData != null) {
                streamData.handler = handler;
            } else {

            }
        }
        final Object[] params = new Object[2];
        params[0] = name;
        params[1] = mode;
        PendingCall pendingCall = new PendingCall("publish", params);
        conn.invoke(pendingCall, getChannelForStreamId(streamId));
    }

这里首先设置了事件监听器,然后构造PendingCall并发送给服务器了,发送的命令为”publish”,参数分别是name和mode。

下一章开始分析服务器是如何处理publish命令的。

时间: 2024-10-03 17:11:33

red5源码分析---9的相关文章

red5源码分析---10

red5源码分析-服务器处理publish命令 和前几章的分析一样,服务器接收到客户端发来的publish命令后,最终会执行RTMPHandler的onCommand函数,再参考<red5源码分析-8>的分析,最终会调用StreamService的publish方法,代码如下 public void publish(String name, String mode) { Map<String, String> params = null; if (name != null &

red5源码分析---6

red5源码分析-客户端和服务器的命令处理 在<red5源码分析-5>中可以知道,在RTMP握手完毕后,客户端会向服务器发送connect命令,connect命令的主要作用就是要和red5服务器上的某个Scope相连接,连接完成后,会向客户端发送带宽协调的指令,ping指令,和一个带宽检测指令.下面先分析ping指令. ping指令 服务端代码 这里先贴一下在服务器将客户端和某个Scope相连后发出的ping指令代码, ... conn.ping(new Ping(Ping.STREAM_BE

red5源码分析---12

red5源码分析-服务器处理视频数据 接着<red5源码分析-11>,本章假设客户端发来的是视频数据,下面就分析服务器如何处理这些数据的. 根据前面几章的分析,基于mina框架,数据到达服务器后,最终会到达RTMPHandler的messageReceived函数,messageReceived定义在RTMPHandler的父类BaseRTMPHandler中, public void messageReceived(RTMPConnection conn, Packet packet) th

red5源码分析---8

red5源码分析-服务器处理createStream命令 服务器接到createStream命令后,经过过滤器层层处理,最后会调用BaseRTMPHandler的messageReceived函数, public void messageReceived(RTMPConnection conn, Packet packet) throws Exception { if (conn != null) { IRTMPEvent message = null; try { message = pack

red5源码分析---7

red5源码分析-客户端处理connect命令并发送createStream命令 在<red5源码分析-5>中提到过,当客户端发送connect命令后,服务器经过处理会将其connect命令返回,不同的是服务器返回的结果包含了一些连接后需要发送给客户端的信息,包括服务器版本.模式等等.当返回的信息经过服务器的发送过滤器RTMPMinaProtocolEncoder时,会调用其中的RTMPProtocolEncoder的encodeCommand函数,下面来看其中的一段代码, protected

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线