def sendNetStreamPlayReset(self, stream, timestamp=0, stream_id=None): self.writeMessage( self.rtmp.make( 4, ( Rtmp.RTMP_TYPE_COMMAND, ( "onStatus", 0, [ Amf.encode(None), Amf.encode( { "level": "status", "code": "NetStream.Play.Reset", "description": "Playing and resetting %s." % stream.stream.getPath(), "details": stream.stream.getPath(), "clientid": self.id, } ), ], ), ), timestamp, stream_id, ) ) # 4 - stream.channel_id
def sendNetStreamPlayStreamNotFound(self, stream, file): self.writeMessage( self.rtmp.make( stream.channel_id, ( Rtmp.RTMP_TYPE_COMMAND, ( "onStatus", 0, [ Amf.encode(None), Amf.encode( { "level": "status", "code": "NetStream.Play.StreamNotFound", "details": file, "clientid": self.id, } ), ], ), ), 0, stream.id, ) )
def sendNetStreamUnpauseNotify(self, stream, timestamp=0, stream_id=None): self.writeMessage( self.rtmp.make( stream.channel_id, ( Rtmp.RTMP_TYPE_COMMAND, ( "onStatus", 0, [ Amf.encode(None), Amf.encode( { "level": "status", "code": "NetStream.Unpause.Notify", "description": "Unpausing %s." % stream.stream.getPath(), "details": stream.stream.getPath(), "clientid": self.id, } ), ], ), ), timestamp, stream_id, ) )
def sendNetStreamSeekNotify(self, stream, timestamp=0, stream_id=None): self.writeMessage( self.rtmp.make( stream.channel_id, ( Rtmp.RTMP_TYPE_COMMAND, ( "onStatus", 0, [ Amf.encode(None), Amf.encode( { "level": "status", "code": "NetStream.Seek.Notify", "description": "Seeking %d (stream ID: %d)." % (stream.seek_time, stream.id), "details": stream.stream.getPath(), "clientid": self.id, } ), ], ), ), timestamp, stream_id, ) )
def sendMetaData(self, stream, stream_id=None): # self.writeMessage(self.rtmp.make(stream.channel_id, (Rtmp.RTMP_TYPE_COMMAND, ("onMetaData", 0, [ # Amf.encode(None), # Amf.encode(stream.stream.getMetadata()) # ])), 0, stream_id)) output = BytesOutput(True) Amf.write(output, Amf.encode("onMetaData")) Amf.write(output, Amf.encode(stream.stream.getMetadata())) self.writeMessage(self.rtmp.make(stream.channel_id, (Rtmp.RTMP_TYPE_NOTIFY, output.getBytes()), 0, stream_id))
def sendNetConnectionConnectSuccess(self, info): self.writeMessage( self.rtmp.make( info[1][0], ( Rtmp.RTMP_TYPE_COMMAND, ( "_result", info[0], [ Amf.encode({"fmsVer": self.handler.server.getVersion(), "capabilities": 31.0, "mode": 1}), Amf.encode( { "level": "status", "code": "NetConnection.Connect.Success", "description": "Connection succeeded.", "objectEncoding": 0.0, } ), ], ), ), ) )
def sendMetaData(self, stream, stream_id=None): #self.writeMessage(self.rtmp.make(stream.channel_id, (Rtmp.RTMP_TYPE_COMMAND, ("onMetaData", 0, [ # Amf.encode(None), # Amf.encode(stream.stream.getMetadata()) #])), 0, stream_id)) output = BytesOutput(True) Amf.write(output, Amf.encode("onMetaData")) Amf.write(output, Amf.encode(stream.stream.getMetadata())) self.writeMessage( self.rtmp.make(stream.channel_id, (Rtmp.RTMP_TYPE_NOTIFY, output.getBytes()), 0, stream_id))
def checkArg(self, type, arg): if type == ARG_TYPE_NULL: if Amf.isnull(arg): return ARG_TYPE_NULL else: return None elif type == ARG_TYPE_NUMBER: return Amf.number(arg) elif type == ARG_TYPE_BOOL: return Amf.bool(arg) elif type == ARG_TYPE_STRING: return Amf.string(arg) elif type == ARG_TYPE_OBJECT: return Amf.object(arg) elif (type & 0xF0) == ARG_TYPE_OPTIONAL: if Amf.isnull(arg): return ARG_TYPE_NULL else: return self.checkArg(type & 0x0F, arg)
def checkArg(self, type, arg): if (type == ARG_TYPE_NULL): if Amf.isnull(arg): return ARG_TYPE_NULL else: return None elif type == ARG_TYPE_NUMBER: return Amf.number(arg) elif type == ARG_TYPE_BOOL: return Amf.bool(arg) elif type == ARG_TYPE_STRING: return Amf.string(arg) elif type == ARG_TYPE_OBJECT: return Amf.object(arg) elif (type & 0xF0) == ARG_TYPE_OPTIONAL: if Amf.isnull(arg): return ARG_TYPE_NULL else: return self.checkArg(type & 0x0F, arg)
def processBody(self, header, body): type = header[3] input = BytesInput(bytes=body, bigendian=True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: self.read_chunk_size = input.readUInt() return None # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: return (RTMP_TYPE_BYTES_READ, input.readUInt()) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control = None control_type = input.readUInt16() control_stream_id = input.readUInt() body_size = RTMP_CONTROL_SIZES[control_type] body_length = len(body) if (body_size is not None) and (body_length != (body_size + 6)): raise Exception, "Invalid control size(%s, %s)" % (type, len(body)) # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: control = (RTMP_CONTROL_CLEAR, ) # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: control = (RTMP_CONTROL_CLEAR_PLAY, ) # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: control = (RTMP_CONTROL_CLIENT_BUFFER, input.readUInt()) # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: control = (RTMP_CONTROL_RESET, ) # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: control = (RTMP_CONTROL_PING, input.readUInt()) # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: control = (RTMP_CONTROL_PONG, input.readUInt() ) #TODO - verify second value (, input.readUInt()) # Unknown else: if (body_length != 6) and (body_length != 10) and (body_length != 14): raise Exception, "Invalid control size(%s, %s)" % ( type, len(body)) value1 = None value2 = None if body_length > 6: value1 = input.readUInt() if body_length > 10: value2 = input.readUInt() control = (RTMP_CONTROL_UNKNOWN, control_type, value1, value2) return (RTMP_TYPE_CONTROL, (control_stream_id, control)) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: return (RTMP_TYPE_SERVER_BW, header[1]) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: return (RTMP_TYPE_CLIENT_BW, header[1]) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: return (RTMP_TYPE_AUDIO, body) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: return (RTMP_TYPE_VIDEO, body) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: return (RTMP_TYPE_NOTIFY, body) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: amf_type, name = Amf.read(input) if amf_type != Amf.AMF_VALUE_STRING: raise Exception, "Invalid Command Name" amf_type, command_id = Amf.read(input) if amf_type != Amf.AMF_VALUE_NUMBER: raise Exception, "Invalid Command ID" args = [] while 1: try: byte = input.readByte() except: break else: if byte is not None: args.append(Amf.readType(input, byte)) else: break return (RTMP_TYPE_COMMAND, (name, command_id, args)) # Unknown else: return (RTMP_TYPE_UNKNOWN, (type, body))
def make(self, channel_id, packet, timestamp=0, stream_id=0): type = packet[0] header = [channel_id, timestamp, None, type, stream_id] data = BytesOutput(True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: data.writeUInt(packet[1]) # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: data.writeUInt(packet[1]) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control_stream_id, control = packet[1] control_type = control[0] value1 = None value2 = None # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: pass # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: pass # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: value1 = control[1] # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: pass # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: value1 = control[1] # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: value1 = control[1] # Unknown elif control_type == RTMP_CONTROL_UNKNOWN: control_type = control[1] value1 = control[2] value2 = control[3] data.writeUInt16(control_type) data.writeUInt(control_stream_id) if value1 is not None: data.writeUInt(value1) if value2 is not None: data.writeUInt(value2) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: data.writeUInt(0x002625A0) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: data.writeUInt(0x002625A0) data.writeByte(0x02) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: data.write(packet[1]) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: data.write(packet[1]) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: data.writeString(packet[1]) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: name, id, args = packet[1] Amf.write(data, (3, name)) #Command name Amf.write(data, (1, id)) #Command id for arg in args: # Args (Amf Values) Amf.write(data, arg) # Unknown elif type == RTMP_TYPE_UNKNOWN: type, body = packet[1] header[4] = type data.write(body) # Other else: header[4] = None data = data.getBytes() length = len(data) header[2] = length output = BytesOutput(True) output.write(self.makeHeader(header)) if length > 0: pos = self.write_chunk_size if length <= pos: output.write(data) else: output.write(buffer(data, 0, pos)) length -= pos while length > 0: output.writeByte(header[0] | (headerSizeToByte(1) << 6)) n = (length, self.write_chunk_size)[length > self.write_chunk_size] output.write(buffer(data, pos, n)) pos += n length -= n return output.getBytes()
def sendNetStreamDataStart(self, stream, stream_id=None): output = BytesOutput(True) Amf.write(output, Amf.encode("onStatus")) Amf.write(output, Amf.encode({"code": "NetStream.Data.Start"})) self.writeMessage(self.rtmp.make(5, (Rtmp.RTMP_TYPE_NOTIFY, output.getBytes()), 0, stream_id))
def sendRtmpSampleAccess(self, stream, stream_id=None): output = BytesOutput(True) Amf.write(output, Amf.encode("|RtmpSampleAccess")) Amf.write(output, Amf.encode(False)) Amf.write(output, Amf.encode(False)) self.writeMessage(self.rtmp.make(5, (Rtmp.RTMP_TYPE_NOTIFY, output.getBytes()), 0, stream_id))
def sendOnBWDone(self, info): self.writeMessage( self.rtmp.make(info[1][0], (Rtmp.RTMP_TYPE_COMMAND, ("onBWDone", 0, [Amf.encode(None)]))))
def make(self, channel_id, packet, timestamp = 0, stream_id = 0): type = packet[0] header = [channel_id, timestamp, None, type, stream_id] data = BytesOutput(True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: data.writeUInt(packet[1]) # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: data.writeUInt(packet[1]) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control_stream_id, control = packet[1] control_type = control[0] value1 = None value2 = None # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: pass # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: pass # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: value1 = control[1] # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: pass # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: value1 = control[1] # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: value1 = control[1] # Unknown elif control_type == RTMP_CONTROL_UNKNOWN: control_type = control[1] value1 = control[2] value2 = control[3] data.writeUInt16(control_type) data.writeUInt(control_stream_id) if value1 is not None: data.writeUInt(value1) if value2 is not None: data.writeUInt(value2) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: data.writeUInt(0x002625A0) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: data.writeUInt(0x002625A0) data.writeByte(0x02) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: data.write(packet[1]) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: data.write(packet[1]) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: data.writeString(packet[1]) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: name, id, args = packet[1] Amf.write(data, (3, name)) #Command name Amf.write(data, (1, id)) #Command id for arg in args: # Args (Amf Values) Amf.write(data, arg) # Unknown elif type == RTMP_TYPE_UNKNOWN: type, body = packet[1] header[4] = type data.write(body) # Other else: header[4] = None data = data.getBytes() length = len(data) header[2] = length output = BytesOutput(True) output.write(self.makeHeader(header)) if length > 0: pos = self.write_chunk_size if length <= pos: output.write(data) else: output.write(buffer(data, 0, pos)) length -= pos while length > 0: output.writeByte(header[0] | (headerSizeToByte(1) << 6)) n = (length, self.write_chunk_size)[length > self.write_chunk_size] output.write(buffer(data, pos, n)) pos += n length -= n return output.getBytes()
def processBody(self, header, body): type = header[3] input = BytesInput(bytes=body, bigendian=True) # 0x01 - Chunk Size if type == RTMP_TYPE_CHUNK_SIZE: self.read_chunk_size = input.readUInt() return None # 0x03 - Bytes Read elif type == RTMP_TYPE_BYTES_READ: return (RTMP_TYPE_BYTES_READ, input.readUInt()) # 0x04 - Control elif type == RTMP_TYPE_CONTROL: control = None control_type = input.readUInt16() control_stream_id = input.readUInt() body_size = RTMP_CONTROL_SIZES[control_type] body_length = len(body) if (body_size is not None) and (body_length != (body_size + 6)): raise Exception, "Invalid control size(%s, %s)" % (type, len(body)) # 0x00 - Clear if control_type == RTMP_CONTROL_CLEAR: control = (RTMP_CONTROL_CLEAR,) # 0x01 - Clear Play elif control_type == RTMP_CONTROL_CLEAR_PLAY: control = (RTMP_CONTROL_CLEAR_PLAY,) # 0x03 - Client Buffer elif control_type == RTMP_CONTROL_CLIENT_BUFFER: control = (RTMP_CONTROL_CLIENT_BUFFER, input.readUInt()) # 0x04 - Reset elif control_type == RTMP_CONTROL_RESET: control = (RTMP_CONTROL_RESET,) # 0x06 - Ping elif control_type == RTMP_CONTROL_PING: control = (RTMP_CONTROL_PING, input.readUInt()) # 0x07 - Pong elif control_type == RTMP_CONTROL_PONG: control = (RTMP_CONTROL_PONG, input.readUInt()) #TODO - verify second value (, input.readUInt()) # Unknown else: if (body_length != 6) and (body_length != 10) and (body_length != 14): raise Exception, "Invalid control size(%s, %s)" % (type, len(body)) value1 = None value2 = None if body_length > 6: value1 = input.readUInt() if body_length > 10: value2 = input.readUInt() control = (RTMP_CONTROL_UNKNOWN, control_type, value1, value2) return (RTMP_TYPE_CONTROL, (control_stream_id, control)) # 0x05 - Server BW elif type == RTMP_TYPE_SERVER_BW: return (RTMP_TYPE_SERVER_BW, header[1]) # 0x06 - Client BW elif type == RTMP_TYPE_CLIENT_BW: return (RTMP_TYPE_CLIENT_BW, header[1]) # 0x08 - Audio elif type == RTMP_TYPE_AUDIO: return (RTMP_TYPE_AUDIO, body) # 0x09 - Video elif type == RTMP_TYPE_VIDEO: return (RTMP_TYPE_VIDEO, body) # 0x12 - Notify elif type == RTMP_TYPE_NOTIFY: return (RTMP_TYPE_NOTIFY, body) # 0x13 - Shared elif type == RTMP_TYPE_SHARED: raise Exception, "Not implemented" #TODO -> Shared Object functions # 0x14 - Command elif type == RTMP_TYPE_COMMAND: amf_type, name = Amf.read(input) if amf_type != Amf.AMF_VALUE_STRING: raise Exception, "Invalid Command Name" amf_type, command_id = Amf.read(input) if amf_type != Amf.AMF_VALUE_NUMBER: raise Exception, "Invalid Command ID" args = [] while 1: try: byte = input.readByte() except: break else: if byte is not None: args.append(Amf.readType(input, byte)) else: break return (RTMP_TYPE_COMMAND, (name, command_id, args)) # Unknown else: return (RTMP_TYPE_UNKNOWN, (type, body))
def sendCreateStreamResponse(self, info, stream_id): self.writeMessage( self.rtmp.make( info[1][0], (Rtmp.RTMP_TYPE_COMMAND, ("_result", info[0], [Amf.encode(None), Amf.encode(stream_id)])) ) )
def sendOnBWDone(self, info): self.writeMessage(self.rtmp.make(info[1][0], (Rtmp.RTMP_TYPE_COMMAND, ("onBWDone", 0, [Amf.encode(None)]))))