def sendData(self, data, timestamp): c = self.channel if timestamp < c.timestamp: relTimestamp = timestamp else: relTimestamp = timestamp - c.timestamp h = header.Header(c.channelId, relTimestamp, self.type, len(data), self.streamId) if self._lastHeader is None: h.full = True c.setHeader(h) c.append(data) header.encode(self.stream, h, self._lastHeader) self._lastHeader = h c.marshallOneFrame() while not c.complete(): self.stream.write(self._continuationHeader) c.marshallOneFrame() c.reset() s = self.stream.getvalue() self.output.write(s) self.encoder.bytes += len(s) self.stream.consume()
def __init__(self, encoder, streamId, output): self.encoder = encoder self.channel = self.encoder.acquireChannel() if self.channel is None: # todo: make this better raise RuntimeError('No streaming channel available') self.type = None self.streamId = streamId self.output = output self.stream = BufferedByteStream() self._lastHeader = None self._oldStream = self.channel.stream self.channel.stream = self.stream h = header.Header(self.channel.channelId) # encode a continuation header for speed header.encode(self.stream, h, h) self._continuationHeader = self.stream.getvalue() self.stream.consume()
def test_simple(self): """ Do a sanity check for a simple 4 frame 1 channel rtmp stream. """ def check_meta(meta, timestamp=10): self.assertEqual(meta.channelId, 3) self.assertEqual(meta.streamId, 1) self.assertEqual(meta.datatype, 2) self.assertEqual(meta.bodyLength, 500) self.assertEqual(meta.timestamp, timestamp) size = self.reader.frameSize full = header.Header(3, datatype=2, bodyLength=500, streamId=1, timestamp=10) header.encode(self.stream, full) self.stream.write('a' * size) header.encode(self.stream, full, full) self.stream.write('b' * size) header.encode(self.stream, full, full) self.stream.write('c' * size) header.encode(self.stream, full, full) self.stream.write('d' * (size - 12)) self.stream.seek(0) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'a' * self.reader.frameSize) self.assertFalse(complete) check_meta(meta) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'b' * self.reader.frameSize) self.assertFalse(complete) check_meta(meta, 10) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'c' * self.reader.frameSize) self.assertFalse(complete) check_meta(meta, 10) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'd' * (size - 12)) self.assertTrue(complete) check_meta(meta, 10) self.assertRaises(IOError, self.reader.readFrame)
def send(self, data, datatype, streamId, timestamp, whenDone=None): """ Queues an RTMP message to be encoded. Call C{next} to do the encoding. @param data: The raw data that will be marshalled into RTMP frames and sent to the peer. @type data: C{str} @param datatype: The type of data. See C{message} for a list of known RTMP types. @type datatype: C{int} @param streamId: The C{NetStream} id that this message is intended for. @type streamId: C{int} @param timestamp: The current timestamp for the stream that this message was sent. @type timestamp: C{int} """ if is_command_type(datatype): # we have to special case command types because a channel only be # busy with one message at a time. Command messages are always # written right away channel = self.getChannel(COMMAND_CHANNEL_ID) else: channel = self.acquireChannel() if not channel: self.pending.append((data, datatype, streamId, timestamp, whenDone)) return h = header.Header( channel.channelId, timestamp - channel.timestamp, datatype, len(data), streamId) if whenDone is not None: channel.setCallback(whenDone) channel.append(data) self.nextHeaders[channel] = h if channel.channelId == COMMAND_CHANNEL_ID: while not self._encodeOneFrame(channel): pass channel.reset() self.flush() return self.activeChannels[channel] = channel.channelId
def test_repr(self): h = header.Header(3) self.assertEquals( repr(h), '<rtmpy.protocol.rtmp.header.Header ' 'streamId=None datatype=None timestamp=None bodyLength=None ' 'channelId=3 full=False continuation=False at 0x%x>' % (id(h), )) d = { 'channelId': 1, 'timestamp': 50, 'datatype': 20, 'bodyLength': 2000, 'streamId': 98, } h = header.Header(**d) self.assertEquals( repr(h), '<rtmpy.protocol.rtmp.header.Header ' 'streamId=98 datatype=20 timestamp=50 bodyLength=2000 channelId=1 ' 'full=False continuation=False at 0x%x>' % (id(h), ))
def test_kwargs(self): d = { 'channelId': 1, 'timestamp': 50, 'datatype': 20, 'bodyLength': 2000, 'streamId': 98, } h = header.Header(**d) for k, v in d.items(): self.assertEqual(getattr(h, k), v)
def test_init(self): h = header.Header(3) expected_attrs = { 'channelId': 3, 'timestamp': -1, 'datatype': -1, 'bodyLength': -1, 'streamId': -1 } for k, v in expected_attrs.items(): self.assertEqual(getattr(h, k), v)
def test_reassign(self): """ Ensure that when a channel is complete it can be repurposed via a relative header. """ full_header = header.Header(52, datatype=2, timestamp=55, bodyLength=256, streamId=4) # only change the bodyLength and timestamp relative_header = header.Header(52, datatype=2, streamId=4, bodyLength=256, timestamp=45) header.encode(self.stream, full_header) self.stream.write('a' * self.reader.frameSize) header.encode(self.stream, relative_header, full_header) self.stream.write('b' * self.reader.frameSize) self.stream.seek(0) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'a' * 128) self.assertFalse(complete) self.assertEqual(meta.timestamp, 55) bytes, complete, meta = self.reader.readFrame() self.assertEqual(bytes, 'b' * 128) self.assertTrue(complete) self.assertEqual(meta.timestamp, 100)
def test_reset(self): full = header.Header(3, datatype=2, bodyLength=2, streamId=1, timestamp=10) header.encode(self.stream, full) self.stream.write('a' * 2) self.stream.seek(0) self.reader.readFrame() channel = self.channels[3] self.assertEqual(channel.bytes, 0)
def reset(self): self.old = header.Header(0, 3, 4, 5, 6) self.new = header.Header(0, 3, 4, 5, 6)
def setUp(self): self.absolute = header.Header(3, timestamp=1000, bodyLength=2000, datatype=3, streamId=243)