def test_many_headers(self): # OK, this test is a bit brittle, as we assume the following # properties of the encoder/muxer: # * it will allocate new chunk stream ids as long as we # provide it with unseen combinations of type and message # stream id # * the allocated ids will be consecutive numbers # * given the exactly same args to sendMessage the second call # will produce a bitstream of a message with completely # compressed header # # At the moment that seems the only reasonable way to force # muxer to use higher chunk stream ids, with different levels # of header compression, using only the public API... # for now, make sure we're using SimpleChunkProducer: class LocalTestMuxer(Muxer): chunk_producer_class = chunks.SimpleChunkProducer # first, generate and mux a whole bunch of messages tm = StringTransport() mux = LocalTestMuxer(tm) for i in range(256 + 64 + 1): mux.sendMessage(0, chunks.MSG_DATA, i, VecBuf([''])) mux.sendMessage(0, chunks.MSG_DATA, i, VecBuf([''])) # ... now demux the resulting binary data td = StringTransport() p = TestDemuxerProtocol() dmx = MessagePassingDemuxer(p) p.init_handler(dmx.gen_handler()) p.makeConnection(td) p.dataReceived(tm.value()) demuxed = p.pop_messages() # ... and check it maches the result we expect based on the # above assumptions first_csid = demuxed[0][0].cs_id for i in range(256 + 64 + 1): h, body = demuxed[2 * i] self.assertEquals((h.cs_id, h.real_time, h.real_size, h.real_type, h.real_ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals((h.cs_id, h.time, h.size, h.type, h.ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals(len(body), 0) h, body = demuxed[2 * i + 1] self.assertEquals((h.cs_id, h.real_time, h.real_size, h.real_type, h.real_ms_id), (i + first_csid, None, None, None, None)) self.assertEquals((h.cs_id, h.time, h.size, h.type, h.ms_id), (i + first_csid, 0, 0, 18, i)) self.assertEquals(len(body), 0)
def test_multiple_chunk_streams(self): c = chunks.Chunker() c1 = c(3, '\x00\x00\x00', VecBuf(['.' * 16])) c2 = c(4, '\x01\x01\x01', VecBuf([',' * 16])) i = 1 cs1, cs2 = [], [] while 1: c.set_chunk_size(i) try: (h1, b1), (h2, b2) = c1.next(), c2.next() except StopIteration: break cs1.append(h1 + flatten(b1)) cs2.append(h2 + flatten(b2)) i += 1 self.assertEquals(cs1, ['\x00\x00\x00' + '.', '\xc3' + '..', '\xc3' + '...', '\xc3' + '....', '\xc3' + '.....', '\xc3' + '.']) self.assertEquals(cs2, ['\x01\x01\x01' + ',', '\xc4' + ',,', '\xc4' + ',,,', '\xc4' + ',,,,', '\xc4' + ',,,,,', '\xc4' + ',']) self.assertRaises(StopIteration, c1.next) self.assertRaises(StopIteration, c2.next)
def test_read_write_mixed(self): b = VecBuf() b.write('abcd') self.assertMatches(b.read(4), 'abcd') self.assertRaises(VecBufEOB, b.read, 1)
def test_read_empty(self): b = VecBuf() self.assertMatches(b.read(0), '') self.assertRaises(VecBufEOB, b.read, 1) b.write('a') self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'a') self.assertRaises(VecBufEOB, b.read, 1)
def test_default_chunk_size(self): c = chunks.Chunker() chunk_size = chunks.DEFAULT_CHUNK_SIZE self.assertChunkerMatches(c(3, '\x00\x00\x00', VecBuf(['.' * chunk_size])), [('\x00\x00\x00', '.' * chunk_size)]) self.assertChunkerMatches(c(3, '\x00\x00\x00', VecBuf(['.' * (chunk_size + 5)])), [('\x00\x00\x00', '.' * chunk_size), ('\xc3', '.' * 5)])
def _make_rtmp_video_simple(self, gst_buf): flags = 0x10 if gst_buf.flags & gst.BUFFER_FLAG_DELTA_UNIT: flags = 0x20 return VecBuf( [_s_uchar.pack(flags | self.video_codec.codecId), buffer(gst_buf)])
def _make_rtmp_video_complex(self, gst_buf): flags = 0x10 if gst_buf.flags & gst.BUFFER_FLAG_DELTA_UNIT: flags = 0x20 return VecBuf([ _s_h264video.pack(flags | self.video_codec.codecId, 1, 0, 0), buffer(gst_buf) ])
def test_read_write_empty(self): b = VecBuf() self.assertMatches(b.read(0), '') b.write('') self.assertMatches(b.read(0), '') self.assertRaises(VecBufEOB, b.read, 1) b.write('') self.assertRaises(VecBufEOB, b.read, 1) self.assertMatches(b.read(0), '') self.assertRaises(VecBufEOB, b.read, 1)
def test_combined(self): d_in = {} d_out = {} type_reverse = { 1: chunks.PROTO_SET_CHUNK_SIZE, 4: chunks.PROTO_USER_CONTROL, 5: chunks.PROTO_WINDOW_SIZE, 6: chunks.PROTO_SET_BANDWIDTH, 8: chunks.MSG_AUDIO, 9: chunks.MSG_VIDEO, 20: chunks.MSG_COMMAND } # for now, make sure we're using SimpleChunkProducer: class LocalTestMuxer(Muxer): chunk_producer_class = chunks.SimpleChunkProducer # mux messages first tm = StringTransport() mux = LocalTestMuxer(tm) for msg in messages: if not msg: continue head, body = msg msg_type = type_reverse[head[4]] mux.sendMessage(head[1], msg_type, head[5], VecBuf([body])) if msg_type == chunks.PROTO_SET_CHUNK_SIZE: mux.set_chunk_size(int(body.encode('hex'), 16)) d_in.setdefault(head[4], []).append((head[1], head[4], head[5], body)) # ... now try to demux the resulting binary data td = StringTransport() p = TestDemuxerProtocol() dmx = MessagePassingDemuxer(p) p.init_handler(dmx.gen_handler()) p.makeConnection(td) p.dataReceived(tm.value()) demuxed = p.pop_messages() # we can't rely on the received messages to be in the exact # same order as the sent ones... for head, body in demuxed: d_out.setdefault(head.type, []).append((head.abs_time, head.type, head.ms_id, body.read(len(body)))) self.assertEquals(d_in, d_out)
def test_read_write_empty_something(self): b = VecBuf() b.write('') b.write('') b.write('abcd') self.assertMatches(b.read(4), 'abcd') self.assertRaises(VecBufEOB, b.read, 1)
def test_changing_chunk_size(self): c = chunks.Chunker() c.set_chunk_size(5) self.assertChunkerMatches(c(3, '\x00\x00\x00', VecBuf(['.' * 16])), [('\x00\x00\x00', '.....'), ('\xc3', '.....'), ('\xc3', '.....'), ('\xc3', '.')]) c1 = c(3, '\x00\x00\x00', VecBuf(['.' * 16])) c.set_chunk_size(1) self.assertChunkMatches(c1.next(), ('\x00\x00\x00', '.')) c.set_chunk_size(4) self.assertChunkMatches(c1.next(), ('\xc3', '....')) c.set_chunk_size(7) self.assertChunkMatches(c1.next(), ('\xc3', '.......')) c.set_chunk_size(128) self.assertChunkMatches(c1.next(), ('\xc3', '....')) self.assertRaises(StopIteration, c1.next)
def test_decode(self): data = [] # buf = VecBuf([''.join([p(r[0]) for r in simple_data])]) expected = [] for r in simple_data: data.append(p(r[0])) expected.extend(r[1]) buf = VecBuf([''.join(data)]) decoded = [] while buf: decoded.append(decode_one(buf)) self.assertEquals(decoded, expected)
def test_clone(self): b = VecBuf() fl = flatten b.write_seq(['ab', 'cd', '', 'ef', 'gh', 'ij']) self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'a') self.assertMatches(b.read(2), 'bc') b2 = b.read_clone(6) self.assertMatches(b.read(1), 'j') self.assertRaises(VecBufEOB, b.read, 1) self.assertMatches(b2.read(6), 'defghi') self.assertRaises(VecBufEOB, b2.read, 1)
def v(s): return VecBuf([p(s)])
def test_seq_read_empty(self): b = VecBuf() fl = flatten self.assertMatches(fl(b.read_seq(0)), '') self.assertRaises(VecBufEOB, b.read_seq, 1) b.write('') self.assertMatches(fl(b.read_seq(0)), '') self.assertRaises(VecBufEOB, b.read_seq, 1) b.write_seq(['']) self.assertMatches(fl(b.read_seq(0)), '') self.assertRaises(VecBufEOB, b.read_seq, 1) b.write_seq(['', '']) self.assertMatches(fl(b.read_seq(0)), '') self.assertRaises(VecBufEOB, b.read_seq, 1)
def make_rtmp_audio(self, gst_buf): return VecBuf([self._header_audio, buffer(gst_buf)])
def write_rtmp_video_headers(self, ts, codec_data): h = _s_h264video.pack(0x10 | self.video_codec.codecId, 0, 0, 0) for buf in codec_data: self._stream.write_video(ts, VecBuf([h, buf]))
def write_rtmp_audio_headers(self, ts, codec_data): h = _s_double_uchar.pack(self._ah1, 0) for buf in codec_data: self._stream.write_audio(ts, VecBuf([h, buf]))
def test_read_write_not_aligned(self): b = VecBuf() b.write('ab') b.write('cd') b.write('') b.write('ef') b.write('gh') b.write('ij') self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'a') self.assertMatches(b.read(2), 'bc') self.assertMatches(b.read(4), 'defg') self.assertMatches(b.read(0), '') self.assertMatches(b.read(2), 'hi') self.assertRaises(VecBufEOB, b.read, 2) self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'j') self.assertRaises(VecBufEOB, b.read, 1) b.write('') b.write('abcd') b.write('efgh') b.write('ijkl') b.write('mnop') self.assertMatches(b.read(2), 'ab') self.assertMatches(b.read(8), 'cdefghij') self.assertMatches(b.read(4), 'klmn') self.assertRaises(VecBufEOB, b.read, 3) self.assertMatches(b.read(2), 'op') self.assertMatches(b.read(0), '') self.assertRaises(VecBufEOB, b.read, 1)
def test_seq_read_write(self): b = VecBuf() fl = flatten b.write_seq(['ab', 'cd', '', 'ef', 'gh', 'ij']) self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'a') self.assertMatches(b.read(2), 'bc') self.assertMatches(b.read(4), 'defg') self.assertMatches(b.read(0), '') self.assertMatches(b.read(2), 'hi') self.assertRaises(VecBufEOB, b.read, 2) self.assertMatches(b.read(0), '') self.assertMatches(b.read(1), 'j') self.assertRaises(VecBufEOB, b.read, 1) b.write_seq(['', 'abcd', 'efgh', 'ijkl', 'mnop']) self.assertMatches(b.read(2), 'ab') self.assertMatches(fl(b.read_seq(8)), 'cdefghij') self.assertMatches(b.read(4), 'klmn') self.assertRaises(VecBufEOB, b.read_seq, 3) self.assertMatches(fl(b.read_seq(2)), 'op') self.assertRaises(VecBufEOB, b.read, 1)
def test_peek(self): b = VecBuf() fl = flatten self.assertMatches(b.peek(0), '') self.assertRaises(VecBufEOB, b.peek, 1) self.assertRaises(VecBufEOB, b.peek_seq, 1) self.assertRaises(VecBufEOB, b.read, 1) b.write('ab') b.write_seq(['cd', '', 'ef']) self.assertMatches(b.peek(3), 'abc') self.assertMatches(b.peek(3), 'abc') self.assertMatches(fl(b.peek_seq(3)), 'abc') self.assertMatches(b.read(1), 'a') self.assertMatches(b.read(2), 'bc') b.write_seq(['gh', 'ij']) self.assertMatches(fl(b.peek_seq(7)), 'defghij') self.assertMatches(b.peek(7), 'defghij') self.assertMatches(fl(b.peek_seq(7)), 'defghij') self.assertMatches(b.peek(7), 'defghij') self.assertMatches(fl(b.read_seq(7)), 'defghij') self.assertMatches(b.peek(0), '') self.assertRaises(VecBufEOB, b.peek, 1) self.assertRaises(VecBufEOB, b.peek_seq, 1) self.assertRaises(VecBufEOB, b.read, 1)
def vb(s): # TODO: add this functionality to the vecbuf/VecBuf itself return VecBuf([s])
def test_a_scenario(self): b = VecBuf() b.write('abcde') b.write_seq(['fgh', 'ijkl']) b.write('mnopqr') self.assertMatches(b.read(1), 'a') self.assertMatches(b.read(1), 'b') self.assertMatches(b.read(4), 'cdef') self.assertMatches(b.read(10), 'ghijklmnop') self.assertMatches(b.read(1), 'q') self.assertMatches(b.read(1), 'r') self.assertRaises(VecBufEOB, b.read, 1)
def vb_clone(vb): # TODO: add this functionality to the vecbuf/VecBuf itself return VecBuf(vb.peek_seq(len(vb)))
def controlMessageReceived(self, header, body): # also pass all protocol control messages to self.protocol as # normal messages body_clone = VecBuf(body.peek_seq(len(body))) Demuxer.controlMessageReceived(self, header, body) self.protocol.messageReceived(header, body_clone)