Example #1
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration
        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)

        while True:
            read_bytes = min(header.bodyLength - msg_body_len, self.chunk_size)
            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.bodyLength:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()

        assert header.bodyLength == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))

        # Decode the message based on the datatype present in the header
        ret = {'msg': header.datatype}

        if ret['msg'] == DataTypes.NONE:
            return self.next()

        elif ret['msg'] == DataTypes.UNKNOWN:
            # ret['stream_id'] = header.streamId # contextual information use
            # try:
            # ret['unknown_type_char'] = body_stream.read_uchar()
            # except:
            # pass
            # try:
            # ret['unknown_type_long'] = body_stream.read_ulong()
            # except:
            # pass
            # try:
            # ret['unknown_type_short'] = body_stream.read_ushort()
            # except:
            # pass
            # ret['unknown_data'] = body_stream.read()
            pass

        elif ret['msg'] == DataTypes.USER_CONTROL:
            ret['stream_id'] = header.streamId  # contextual information use
            # ret['event_data_long'] = body_stream.read_ulong()
            # ret['event_data_char'] = body_stream.read_uchar()
            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()

        elif ret['msg'] == DataTypes.ACK:
            # ret['stream_id'] = header.streamId # contextual information use
            # try:
            # ret['ack_type_char'] = body_stream.read_uchar()
            # except:
            # pass
            # try:
            # ret['ack_type_long'] = body_stream.read_ulong()
            # except:
            # pass
            # try:
            # ret['ack_type_short'] = body_stream.read_ushort()
            # except:
            # pass
            # ret['ack_data'] = body_stream.read()
            pass

        elif ret['msg'] == DataTypes.WINDOW_ACK_SIZE:
            ret['window_ack_size'] = body_stream.read_ulong()

        elif ret['msg'] == DataTypes.SET_PEER_BANDWIDTH:
            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()

        elif ret['msg'] == DataTypes.SHARED_OBJECT:
            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)

            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                #event = self.read_shared_object_event(body_stream, decoder)
                event = RtmpReader.read_shared_object_event(
                    body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

        elif ret['msg'] == DataTypes.COMMAND:
            ret['stream_id'] = header.streamId  # contexutal information
            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands

        elif ret['msg'] == DataTypes.SET_CHUNK_SIZE:
            ret['chunk_size'] = body_stream.read_ulong()

        elif ret['msg'] == DataTypes.DATA:
            ret['stream_id'] = header.stream_id
            ret['metadata'] = message_body

        elif ret['msg'] == DataTypes.AUDIO:
            # ret['stream_id'] = header.streamId
            # ret['control'] = body_stream.read_uchar()
            # ret['data'] = body_stream.read()
            # ret['timestamp'] = header.timestamp

            # View individual header information
            # print(':RTMP HEADER:', '<type:>', header.datatype, '<channel id>:', header.channelId, '<stream id>:', header.streamId,
            # '<bodylength>:', header.bodyLength, '<timestamp>:', header.timestamp)

            # View individual body information
            # print(':RTMP BODY:', '<control>', ret['control'], '<audio data>', '...') # ret['data'] is the raw audio data
            pass

        elif ret['msg'] == DataTypes.VIDEO:
            # ret['stream_id'] = header.streamId
            # ret['control'] = body_stream.read_uchar()
            # ret['data'] = body_stream.read()
            # ret['timestamp'] = header.timestamp

            # View individual header information
            # print(':RTMP HEADER:', '<type:>', header.datatype, '<channel id>:', header.channelId, '<stream id>:', header.streamId,
            #      '<bodylength>:', header.bodyLength, '<timestamp>:', header.timestamp)
            # print("Control", ret['control'])

            # View individual body information
            # print(':RTMP BODY:', '<control>', ret['control'], '<video data>', '...') # ret['data'] is the raw video data
            pass

        else:
            assert False, header

        # logging.debug('recv %r', ret)
        return ret
Example #2
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration

        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)
        # FIXME: this should be really implemented inside header_decode
        if header.datatype == DataTypes.NONE:
            header = self.prv_header
        self.prv_header = header
        while True:
            read_bytes = min(header.bodyLength - msg_body_len, self.chunk_size)
            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.bodyLength:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()
            assert next_header.streamId == -1, (header, next_header)
            assert next_header.datatype == -1, (header, next_header)
            assert next_header.timestamp == -1, (header, next_header)
            assert next_header.bodyLength == -1, (header, next_header)
        assert header.bodyLength == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))

        # Decode the message based on the datatype present in the header
        ret = {'msg': header.datatype}
        if ret['msg'] == DataTypes.USER_CONTROL:
            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()
        elif ret['msg'] == DataTypes.WINDOW_ACK_SIZE:
            ret['window_ack_size'] = body_stream.read_ulong()
        elif ret['msg'] == DataTypes.SET_PEER_BANDWIDTH:
            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()
        elif ret['msg'] == DataTypes.SHARED_OBJECT:
            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)

            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                event = self.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events
        elif ret['msg'] == DataTypes.COMMAND:
            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands
        #elif ret['msg'] == DataTypes.NONE:
        #    print 'WARNING: message with no datatype received.', header
        #    return self.next()
        elif ret['msg'] == DataTypes.SET_CHUNK_SIZE:
            ret['chunk_size'] = body_stream.read_ulong()
        else:
            assert False, header

        logging.debug('recv %r', ret)
        return ret
Example #3
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration
        
        # superDebugNotice("rtmp reader, reading incoming rtmp message from stream")
        
        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)
        
        # FIXME: this should be really implemented inside header_decode
        if header.datatype == DataTypes.NONE:
            header = self.prv_header
        self.prv_header = header

        # superDebug("header", header)

        while True:
            read_bytes = min(header.bodyLength - msg_body_len, self.chunk_size)
            # superDebug("read_bytes", read_bytes)

            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.bodyLength:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # superDebug("next_header", next_header)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            # superDebug("header.timestamp", header.timestamp)
            # superDebug("header.timestamp >= 0x00ffffff", header.timestamp >= 0x00ffffff)
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()
            assert next_header.streamId == -1, (header, next_header)
            assert next_header.datatype == -1, (header, next_header)
            assert next_header.timestamp == -1, (header, next_header)
            assert next_header.bodyLength == -1, (header, next_header)
        assert header.bodyLength == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))
        
        # superDebug("body_stream_contents", ''.join(message_body))
        # superDebug("message_body", message_body)
        # superDebug("msg_body_len", msg_body_len)

        # Decode the message based on the datatype present in the header
        ret = {'msg':header.datatype}
        # superDebug("ret", ret)
        if ret['msg'] == DataTypes.USER_CONTROL:
            # superDebug("header.datatype enum", "USER_CONTROL")

            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()

            # superDebug("event_type", ret['event_type'])
            # superDebug("event_data", ret['event_data'])
        elif ret['msg'] == DataTypes.WINDOW_ACK_SIZE:
            # superDebug("header.datatype enum", "WINDOW_ACK_SIZE")

            ret['window_ack_size'] = body_stream.read_ulong()

            # superDebug("window_ack_size", ret['window_ack_size'])
        elif ret['msg'] == DataTypes.SET_PEER_BANDWIDTH:
            # superDebug("header.datatype enum", "SET_PEER_BANDWIDTH")

            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()

            # superDebug("window_ack_size", ret['window_ack_size'])
            # superDebug("limit_type", ret['limit_type'])
        elif ret['msg'] == DataTypes.SHARED_OBJECT:
            # superDebug("header.datatype enum", "SHARED_OBJECT")

            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)

            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                event = self.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

            # superDebug("obj_name", ret['obj_name'])
            # superDebug("curr_version", ret['curr_version'])
            # superDebug("flags", ret['flags'])
            # superDebug("events", ret['events'])

        elif ret['msg'] == DataTypes.COMMAND:
            # superDebug("header.datatype enum", "COMMAND")

            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands
        
        elif ret['msg'] == DataTypes.SET_CHUNK_SIZE:
            # superDebug("header.datatype enum", "SET_CHUNK_SIZE")

            ret['chunk_size'] = body_stream.read_ulong()

            # superDebug("chunk_size", ret['chunk_size'])
        
        elif ret['msg'] == DataTypes.NONE:
           print('WARNING: message with no datatype received.', header)
           return self.next()

            # superDebug("command", ret['command'])
        
        else:
            # Raise assertion exception with header object.
            assert False, header

        # superDebugFooter()
        
        logging.debug('recv %r', ret)
        return ret
Example #4
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration

        # superDebugNotice("rtmp reader, reading incoming rtmp message from stream")

        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)

        self.prv_header = header

        # superDebug("header", header)

        while True:
            read_bytes = min(header.bodyLength - msg_body_len, self.chunk_size)
            # superDebug("read_bytes", read_bytes)

            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.bodyLength:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # superDebug("next_header", next_header)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            # superDebug("header.timestamp", header.timestamp)
            # superDebug("header.timestamp >= 0x00ffffff", header.timestamp >= 0x00ffffff)
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()
            # assert next_header.streamId == -1, (header, next_header)
            # assert next_header.datatype == -1, (header, next_header)
            # assert next_header.timestamp == -1, (header, next_header)
            # assert next_header.bodyLength == -1, (header, next_header)
        assert header.bodyLength == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))

        # superDebug("body_stream_contents", ''.join(message_body))
        # superDebug("message_body", message_body)
        # superDebug("msg_body_len", msg_body_len)

        # Decode the message based on the datatype present in the header
        ret = {'msg': header.datatype}
        # superDebug("ret", ret)
        if ret['msg'] == DataTypes.USER_CONTROL:
            # superDebug("header.datatype enum", "USER_CONTROL")

            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()

            # superDebug("event_type", ret['event_type'])
            # superDebug("event_data", ret['event_data'])
        elif ret['msg'] == DataTypes.WINDOW_ACK_SIZE:
            # superDebug("header.datatype enum", "WINDOW_ACK_SIZE")

            ret['window_ack_size'] = body_stream.read_ulong()

            # superDebug("window_ack_size", ret['window_ack_size'])
        elif ret['msg'] == DataTypes.SET_PEER_BANDWIDTH:
            # superDebug("header.datatype enum", "SET_PEER_BANDWIDTH")

            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()

            # superDebug("window_ack_size", ret['window_ack_size'])
            # superDebug("limit_type", ret['limit_type'])
        elif ret['msg'] == DataTypes.SHARED_OBJECT:
            # superDebug("header.datatype enum", "SHARED_OBJECT")

            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)

            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                event = self.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

            # superDebug("obj_name", ret['obj_name'])
            # superDebug("curr_version", ret['curr_version'])
            # superDebug("flags", ret['flags'])
            # superDebug("events", ret['events'])

        elif ret['msg'] == DataTypes.COMMAND:
            # superDebug("header.datatype enum", "COMMAND")

            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands

        elif ret['msg'] == DataTypes.DATA_MESSAGE:
            # superDebug("header.datatype enum", "COMMAND")

            ret['event_data'] = body_stream.read()

        elif ret['msg'] == DataTypes.SET_CHUNK_SIZE:
            # superDebug("header.datatype enum", "SET_CHUNK_SIZE")

            ret['chunk_size'] = body_stream.read_ulong()
            # print ret['chunk_size']
            self.chunk_size = ret['chunk_size']
            # superDebug("chunk_size", ret['chunk_size'])
        elif ret['msg'] == DataTypes.VIDEO_MESSAGE:
            ret['streamid'] = header.streamId
            ret['control'] = body_stream.read_uchar()
            # print ret['control']
            ret['video'] = body_stream.read()

        elif ret['msg'] == DataTypes.NONE:
            print('WARNING: message with no datatype received.', header)
            return self.next()

            # superDebug("command", ret['command'])

        else:
            # Raise assertion exception with header object.
            assert False, header

        # superDebugFooter()

        logging.debug('recv %r', ret)
        return ret
Example #5
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration
        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)
        log.debug('header %s' % header)

        # FIXME: this should really be implemented inside header_decode
        if header.data_type == types.DT_NONE:
            header = self.prv_header
        self.prv_header = header

        while True:
            read_bytes = min(header.body_length - msg_body_len, self.chunk_size)

            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.body_length:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()
            assert next_header.stream_id == -1, (header, next_header)
            assert next_header.data_type == -1, (header, next_header)
            assert next_header.timestamp == -1, (header, next_header)
            assert next_header.body_length == -1, (header, next_header)
        assert header.body_length == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))

        # Decode the message based on the datatype present in the header
        ret = {'msg': header.data_type}
        if ret['msg'] == types.DT_USER_CONTROL:
            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()

        elif ret['msg'] == types.DT_WINDOW_ACK_SIZE:
            ret['window_ack_size'] = body_stream.read_ulong()

        elif ret['msg'] == types.DT_SET_PEER_BANDWIDTH:
            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()

        elif ret['msg'] == types.DT_SHARED_OBJECT:
            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)
            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                event = self.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

        elif ret['msg'] == types.DT_AMF3_SHARED_OBJECT:
            decoder = pyamf.amf3.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)
            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                event = self.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

        elif ret['msg'] == types.DT_COMMAND:
            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands

        elif ret['msg'] == types.DT_AMF3_COMMAND:
            decoder = pyamf.amf3.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands

        elif ret['msg'] == types.DT_NONE:
            log.warning('WARNING: message with no datatype received: %s' % header)
            return self.next()

        elif ret['msg'] == types.DT_SET_CHUNK_SIZE:
            ret['chunk_size'] = body_stream.read_ulong()
        else:
            assert False, header

        log.debug('recv %r', ret)
        return ret
Example #6
0
    def next(self):
        """ Read one RTMP message from the stream and return it. """
        if self.stream.at_eof():
            raise StopIteration
        # Read the message into body_stream. The message may span a number of
        # chunks (each one with its own header).
        message_body = []
        msg_body_len = 0
        header = rtmp_protocol_base.header_decode(self.stream)

        while True:
            read_bytes = min(header.bodyLength - msg_body_len, self.chunk_size)
            message_body.append(self.stream.read(read_bytes))
            msg_body_len += read_bytes
            if msg_body_len >= header.bodyLength:
                break
            next_header = rtmp_protocol_base.header_decode(self.stream)
            # WORKAROUND: even though the RTMP specification states that the
            # extended timestamp field DOES NOT follow type 3 chunks, it seems
            # that Flash player 10.1.85.3 and Flash Media Server 3.0.2.217 send
            # and expect this field here.
            if header.timestamp >= 0x00ffffff:
                self.stream.read_ulong()

        assert header.bodyLength == msg_body_len, (header, msg_body_len)
        body_stream = pyamf.util.BufferedByteStream(''.join(message_body))

        # Decode the message based on the datatype present in the header
        ret = {'msg': header.datatype}

        if ret['msg'] == DataTypes.NONE:
            return self.next()

        elif ret['msg'] == DataTypes.UNKNOWN:
            # ret['stream_id'] = header.streamId # contextual information use
            # try:
                # ret['unknown_type_char'] = body_stream.read_uchar()
            # except:
                # pass
            # try:
                # ret['unknown_type_long'] = body_stream.read_ulong()
            # except:
                # pass
            # try:
                # ret['unknown_type_short'] = body_stream.read_ushort()
            # except:
                # pass
            # ret['unknown_data'] = body_stream.read()
            pass

        elif ret['msg'] == DataTypes.USER_CONTROL:
            ret['stream_id'] = header.streamId # contextual information use
            # ret['event_data_long'] = body_stream.read_ulong()
            # ret['event_data_char'] = body_stream.read_uchar()
            ret['event_type'] = body_stream.read_ushort()
            ret['event_data'] = body_stream.read()

        elif ret['msg'] == DataTypes.ACK:
            # ret['stream_id'] = header.streamId # contextual information use
            # try:
                # ret['ack_type_char'] = body_stream.read_uchar()
            # except:
                # pass
            # try:
                # ret['ack_type_long'] = body_stream.read_ulong()
            # except:
                # pass
            # try:
                # ret['ack_type_short'] = body_stream.read_ushort()
            # except:
                # pass
            # ret['ack_data'] = body_stream.read()
            pass

        elif ret['msg'] == DataTypes.WINDOW_ACK_SIZE:
            ret['window_ack_size'] = body_stream.read_ulong()

        elif ret['msg'] == DataTypes.SET_PEER_BANDWIDTH:
            ret['window_ack_size'] = body_stream.read_ulong()
            ret['limit_type'] = body_stream.read_uchar()

        elif ret['msg'] == DataTypes.SHARED_OBJECT:
            decoder = pyamf.amf0.Decoder(body_stream)
            obj_name = decoder.readString()
            curr_version = body_stream.read_ulong()
            flags = body_stream.read(8)

            # A shared object message may contain a number of events.
            events = []
            while not body_stream.at_eof():
                #event = self.read_shared_object_event(body_stream, decoder)
                event = RtmpReader.read_shared_object_event(body_stream, decoder)
                events.append(event)

            ret['obj_name'] = obj_name
            ret['curr_version'] = curr_version
            ret['flags'] = flags
            ret['events'] = events

        elif ret['msg'] == DataTypes.COMMAND:
            ret['stream_id'] = header.streamId # contexutal information
            decoder = pyamf.amf0.Decoder(body_stream)
            commands = []
            while not body_stream.at_eof():
                commands.append(decoder.readElement())
            ret['command'] = commands

        elif ret['msg'] == DataTypes.SET_CHUNK_SIZE:
            ret['chunk_size'] = body_stream.read_ulong()

        elif ret['msg'] == DataTypes.DATA:
            ret['stream_id'] = header.stream_id
            ret['metadata'] = message_body

        elif ret['msg'] == DataTypes.AUDIO:
            # ret['stream_id'] = header.streamId
            # ret['control'] = body_stream.read_uchar()
            # ret['data'] = body_stream.read()
            # ret['timestamp'] = header.timestamp

            # View individual header information
            # print(':RTMP HEADER:', '<type:>', header.datatype, '<channel id>:', header.channelId, '<stream id>:', header.streamId,
                # '<bodylength>:', header.bodyLength, '<timestamp>:', header.timestamp)

            # View individual body information
            # print(':RTMP BODY:', '<control>', ret['control'], '<audio data>', '...') # ret['data'] is the raw audio data
            pass

        elif ret['msg'] == DataTypes.VIDEO:
            # ret['stream_id'] = header.streamId
            # ret['control'] = body_stream.read_uchar()
            # ret['data'] = body_stream.read()
            # ret['timestamp'] = header.timestamp


            # View individual header information
            # print(':RTMP HEADER:', '<type:>', header.datatype, '<channel id>:', header.channelId, '<stream id>:', header.streamId,
            #      '<bodylength>:', header.bodyLength, '<timestamp>:', header.timestamp)
            # print("Control", ret['control'])

            # View individual body information
            # print(':RTMP BODY:', '<control>', ret['control'], '<video data>', '...') # ret['data'] is the raw video data
            pass

        else:
            assert False, header

        # logging.debug('recv %r', ret)
        return ret