class TestServer: def __init__(self, client, dqID): self.dqID = dqID self.fileName = "../Server/svc.file" self.pack = packet.packet(self.fileName, 400, 177, dqID) self.client = client self.serverLog = Log("serverLog.txt") def startSend(self): lossFile = file("lost_" + str(self.dqID) + ".txt") lineContent = lossFile.readline() if lineContent: lossPktNo = int(lineContent) else: lossPktNo = -1 one_packet = self.pack.get_one_packet() curPktNo = 1 self.bEnd = False self.bPause = False while one_packet and not self.bEnd: if curPktNo == lossPktNo: #remove it #print "remove pktno ", curPktNo lineContent = lossFile.readline() if lineContent: try: lossPktNo = int(lineContent) except: lossPktNo = -1 else: lossPktNo = -1 else: #deliver it to client self.client.receive_one_packet(one_packet) if self.dqID == 16: pass elif self.dqID == 1: time.sleep(0.01) else: time.sleep(0.015) self.serverLog.LogStr("pktNo %d len %d" % (curPktNo, len(one_packet))) curPktNo += 1 one_packet = self.pack.get_one_packet() while self.bPause and not self.bEnd: time.sleep(0.1) time.sleep(0.01) def stopSend(self): self.bEnd = True def pauseSend(self): self.bPause = True def resumeSend(self): self.bPause = False
class Client(object): def __init__(self): self.dataChannel = None self.ctlChannel = None self.ctlChannel = ClientControl(2, self.freqAssignCB, self.freqReleaseACKCB) self.stateLock = threading.Lock() self.state = Idle self.log = Log('ClientLog.txt') pass def startDataChannel(self, dataWidth, dqID): self.log.LogStr("start data channel") if fake: self.dataChannel = ClientDataFake(dataWidth, dqID) else: self.dataChannel = ClientData(dataWidth, dqID) self.dataChannel.start() def endDataChannel(self): if self.dataChannel: self.log.LogStr("stop data channel") self.dataChannel.stop() self.dataChannel.deconstruction() del self.dataChannel self.dataChannel = None else: self.log.LogStr("endDataChannel but dataChannel is none") def freqAssignThreadCB(self, width): self.log.LogStr("freqAssignThread call callback width %d" % width) self.stateLock.acquire() self.log.LogStr("the state is %d" % (self.state)) if width == 1: dataWidth = 80 dqID = 16 elif width == 2: dataWidth = 64 dqID = 1 else: dataWidth = 48 dqID = 0 if self.state == GetFreq: self.endCtlChannel() self.startDataChannel(dataWidth, dqID) self.state = StartData self.stateLock.release() def freqReleaseACKCB(self, payload): print "receive freq release ack" self.stateLock.acquire() if self.state == FreqRelease: self.endCtlChannel() self.ctlChannel.finishFreqReq() self.state = Idle self.stateLock.release() def userInteractThreadCB(self): while True: command = raw_input("command:") if command == 'start': self.stateLock.acquire() if self.state == Idle: self.startCtlChannel() self.sendCtlChannelRequest() self.state = WaitAssign self.freqReqTimer = Timer(TimerDuration, self.freqReqTimeoutCB) self.freqReqTimer.start() self.stateLock.release() elif command == 'end': self.stateLock.acquire() if self.state == WaitAssign: self.ctlChannel.sendFreqRelease() elif self.state == GetFreq: self.ctlChannel.sendFreqRelease() elif self.state == StartData: self.endDataChannel() time.sleep(3) self.startCtlChannel() self.ctlChannel.sendFreqRelease() else: continue self.state = FreqRelease self.stateLock.release() self.freqReleaseTimer = Timer(TimerDuration, self.freqReleaseTimeoutCB) self.freqReleaseTimer.start() elif command == 'quit': self.stateLock.acquire() if self.state == Idle: self.ctlChannel = None break self.stateLock.release() break elif command == "help": print "start: start control channel and send request" print "end: end control channel and data channel" print "quit: end the client" print "help: show this message" def freqReqTimeoutCB(self): print "freq request timeout" self.stateLock.acquire() if self.state == WaitAssign: self.sendCtlChannelRequest() self.freqReqTimer = Timer(TimerDuration, self.freqReqTimeoutCB) self.freqReqTimer.start() self.stateLock.release() def freqReleaseTimeoutCB(self): print "freq release timeout" self.stateLock.acquire() if self.state == FreqRelease: self.ctlChannel.sendFreqRelease() self.freqReleaseTimer = Timer(TimerDuration, self.freqReleaseTimeoutCB) self.freqReleaseTimer.start() self.stateLock.release() def freqAssignCB(self, width): #1 is big 2 is small self.stateLock.acquire() if self.state == WaitAssign: self.freqAssignThread = threading.Thread( target=self.freqAssignThreadCB, args=[width]) self.freqAssignThread.start() self.state = GetFreq self.stateLock.release() def startCtlChannel(self): print "start ctl channel" self.ctlChannel.construct() self.ctlChannel.start() def sendCtlChannelRequest(self): if self.ctlChannel: print "send control channel request" self.ctlChannel.sendFreqReq() def endCtlChannel(self): print "end ctl channel" self.ctlChannel.stop() self.ctlChannel.deconstruct() def endAll(self): if self.ctlChannel: self.endCtlChannel() self.ctlChannel = None if self.dataChannel: self.endDataChannel() def reqTimeoutCB(self): self.timeoutNumber += 1 if self.state != 1: return if self.timeoutNumber > 10: self.state = 3 else: self.state = 0 self.dealWithStateMachine()
class unpacket: def __init__(self): self.nals = [] self.next_rtp = None self.rtp_con = threading.Condition() self.rtp_buffer = [] self.rtp_end = False self.unpacketLog = Log("unpacketLog.txt") def get_one_rtp(self): self.rtp_con.acquire() while len(self.rtp_buffer) == 0: if self.rtp_end: self.rtp_con.release() return None #wait will release the contition and acquire it after time expire self.rtp_con.wait(1) one_rtp = self.rtp_buffer[0] self.rtp_buffer = self.rtp_buffer[1:] self.rtp_con.release() return one_rtp def put_one_rtp(self, rtp): self.rtp_con.acquire() self.rtp_buffer.append(rtp) self.rtp_con.notify() self.rtp_con.release() def end_rtp(self): self.rtp_end = True def get_rtp_type(self, rtp_payload): fb = struct.unpack('!B', rtp_payload[0:1])[0] rtp_type = fb & 31 return rtp_type def extract_nal_from_nor_rtp(self, rtp_payload): return rtp_payload def extract_nal_from_fu_a_rtp(self, rtp_payloads, rtps): nal = '' if not check_rtp_fu_as(rtps): self.unpacketLog.LogStr('fu check error') return nal self.unpacketLog.LogStr('fu check succeed') for i in range(len(rtp_payloads)): nal += rtp_payloads[i][2:] return nal def extract_nal_from_stap_a_rtp(self, rtp_payload): rtp_payload = rtp_payload[1:] nals = [] while len(rtp_payload) > 0: now_nal_size = struct.unpack('!H', rtp_payload[0:2])[0] nals.append(rtp_payload[2:now_nal_size + 2]) rtp_payload = rtp_payload[now_nal_size + 2:] self.unpacketLog.LogStr('extract nal from stap, nal number: ' + str(len(nals))) return nals def get_one_nal(self): #pdb.set_trace() if len(self.nals) > 0: res = self.nals[0] self.nals = self.nals[1:] return res else: if self.next_rtp == None: now_rtp = self.get_one_rtp() if now_rtp == None: return None else: now_rtp = self.next_rtp self.next_rtp = None header_len = get_rtp_header_len(now_rtp) now_payload = now_rtp[header_len:] rtp_type = self.get_rtp_type(now_payload) if rtp_type <= 23: self.unpacketLog.LogStr("receive one nor rtp") res = self.extract_nal_from_nor_rtp(now_payload) return res elif rtp_type == 24: self.unpacketLog.LogStr('receive one stap_a rtp') self.nals = self.extract_nal_from_stap_a_rtp(now_payload) res = self.nals[0] self.nals = self.nals[1:] return res elif rtp_type == 28: #pdb.set_trace() self.unpacketLog.LogStr('receive one fu_a rtp') rtp_payloads = [] rtps = [] now_seq_num = get_seq_num(now_rtp) self.unpacketLog.LogStr('fu_a start seq num ' + str(now_seq_num)) fu_a_end = False while now_rtp != None and (not fu_a_end): header_len = get_rtp_header_len(now_rtp) now_payload = now_rtp[header_len:] rtp_type = self.get_rtp_type(now_payload) if rtp_type != 28: self.next_rtp = now_rtp fu_a_end = True else: fu_header = get_fu_a_header(now_payload) if len(rtps) > 0: if fu_header & (1 << 7) > 0: self.next_rtp = now_rtp fu_a_end = True else: rtps.append(now_rtp) rtp_payloads.append(now_payload) if fu_header & (1 << 6) > 0: fu_a_end = True else: now_rtp = self.get_one_rtp() else: rtps.append(now_rtp) rtp_payloads.append(now_payload) now_rtp = self.get_one_rtp() now_seq_num = get_seq_num(rtps[-1]) self.unpacketLog.LogStr('fu_a end seq num ' + str(now_seq_num)) res = self.extract_nal_from_fu_a_rtp(rtp_payloads, rtps) return res else: print "error rtp_type" pass
class packet: def __init__(self, file_name, mtu_size, ssrc, dqID): read_video.file_name = file_name read_video.init_file(read_video.file_name) self.mtu_size = mtu_size self.seq_num = 1 self.ssrc = ssrc self.timestamp = 0 self.nals = [] self.left_nal = "" self.first_byte = 0 self.nal_num = 0 self.accessUnitID = 0 self.dqID = dqID self.packetLog = Log("packetLog.txt") self.packetNumber = 1 def end(self): read_video.close_file() def extractNalsBydqID(self, nals): res = [] for nal in nals: self.packetLog.LogStr('get one nal with dqID %d' % nal.nal_dqID) if nal.nal_dqID <= self.dqID: res.append(nal) return res def get_one_packet(self): self.packetLog.LogStr( '************* packet id %d **********************' % self.packetNumber) self.packetNumber += 1 consume_nal_num = 0 header = self.build_rtp_header() left_space = self.mtu_size - len(header) #deal with fu_a if len(self.left_nal) != 0: (consume_size, payload) = self.build_fu_a_payload(self.left_nal, left_space, 0) self.left_nal = self.left_nal[consume_size:] return header + payload #deal with new nal while len(self.nals) == 0: self.packetLog.LogStr('read one access unit access unit id ' + str(self.accessUnitID)) self.accessUnitID += 1 au = read_video.read_one_access_unit() if au == None: return None self.packetLog.LogStr('access unit id ' + str(self.accessUnitID) + ' nals number: ' + str(len(au.nals))) self.nals += self.extractNalsBydqID(au.nals) self.nal_num = len(self.nals) curr_nal = self.nals[0] if len(curr_nal.video_byte) > left_space: self.packetLog.LogStr('one large nal: nal size ' + str(len(curr_nal.video_byte))) self.left_nal = curr_nal.video_byte self.first_byte = struct.unpack('!B', self.left_nal[0:1])[0] (consume_size, payload) = self.build_fu_a_payload(self.left_nal, left_space, 1) self.left_nal = self.left_nal[consume_size:] consume_nal_num = 1 else: num = self.cal_stap_a_nal_num(self.nals, left_space) if num <= 1: payload = self.build_nor_payload(curr_nal) consume_nal_num = 1 else: consume_nal_num = num payload = self.build_stap_a_payload(self.nals[0:num]) self.nals = self.nals[consume_nal_num:] return header + payload def cal_stap_a_nal_num(self, au_left_nals, left_space): num = 0 left_space -= 1 next_id = 0 while left_space >= 0 and next_id < len(au_left_nals): left_space -= len(au_left_nals[next_id].video_byte) + 2 next_id += 1 num += 1 if left_space < 0: num -= 1 return num def build_stap_a_payload(self, nals): fb = 0 for i in range(len(nals)): fb |= struct.unpack('!B', nals[i].video_byte[0:1])[0] fb &= 255 - 31 fb |= 24 payload = "" payload += struct.pack("!B", fb) for i in range(len(nals)): self.packetLog.LogStr('stap_a one nal size:' + str(len(nals[i].video_byte))) payload += struct.pack("!H", len(nals[i].video_byte)) payload += nals[i].video_byte return payload def build_fu_a_payload(self, left_nal, left_space, start): self.packetLog.LogStr('fu_a start ' + str(start)) left_space -= 2 payload = '' fb = self.first_byte fb = fb & (255 - 31) fb = fb | 28 sb = start << 7 if len(left_nal) <= left_space: left_space = len(left_nal) sb |= 1 << 6 sb = sb | (self.first_byte & 31) self.packetLog.LogStr('fu_header ' + str(sb)) payload = struct.pack('!BB', fb, sb) payload += left_nal[0:left_space] self.packetLog.LogStr('fu_a consume size ' + str(left_space)) return (left_space, payload) def build_nor_payload(self, nal): self.packetLog.LogStr('nor consume size ' + str(len(nal.video_byte))) return nal.video_byte def build_rtp_header(self): fb = 0 v = 2 p = 0 x = 0 cc = 0 fb += cc + (x << 4) + (p << 5) + (v << 6) sb = 0 M = 0 pt = 0 sb += pt + (M << 7) header = "" self.packetLog.LogStr('seq num ' + str(self.seq_num)) header += struct.pack('!BBHII', fb, sb, self.seq_num, self.timestamp, self.ssrc) self.seq_num += 1 return header