from bitstring import BitArray, BitStream # convert amr payload to storage format # according RFC 4867 # http://tools.ietf.org/html/rfc4867 # see http://packages.python.org/bitstring/walkthrough.html # # RFC 4867 (Bandwidth-Efficient Mode) p22... # In the payload, no specific mode is requested (CMR=15), the speech # frame is not damaged at the IP origin (Q=1), and the coding mode is # AMR 7.4 kbps (FT=4). The encoded speech bits, d(0) to d(147), are # arranged in descending sensitivity order according to [2]. Finally, # two padding bits (P) are added to the end as padding to make the # payload octet aligned. # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | CMR=15|0| FT=4 |1|d(0) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | d(147)|P|P| # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- # # RFC 4867 Section 5.3 (AMR and AMR-WB Storage Format) # The following example shows an AMR frame in 5.9 kbps coding mode # (with 118 speech bits) in the storage format. # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |P| FT=2 |Q|P|P| | # +-+-+-+-+-+-+-+-+ + # | | # + Speech bits for frame-block n, channel k + # | | # + +-+-+ # | |P|P| # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- # def amrPayload2Storage_EfficientMode(payload): bitlen = [95,103,118,134,148,159,204,244,39] amr = BitArray(bytes=payload) cmr = amr[0:4] mode = amr[5:9] assert mode.uint >=0 and mode.uint <=8 qual = amr[9:10] voice = amr[10:10+bitlen[mode.uint]] #print("cmr=%d\tmod=%d\tqual=%d\tvoicebits=%d" % (cmr.uint,mode.uint,qual.uint,voice.len)) storage = BitArray(bin='0') storage.append(mode) storage.append(qual) storage.append('0b00') # padding assert storage.len==8,"check length of storage header is one byte" storage.append(voice) return storage.tobytes() #4.4.5.1. Basic Single-Channel Payload Carrying Multiple Frames # # The following diagram shows an octet aligned payload from a single # channel payload type that carries two AMR frames of 7.95 kbps coding # mode (FT=5). In the payload, a codec mode request is sent (CMR=6), # requesting the encoder at the receiver's side to use AMR 10.2 kbps # coding mode. No frame CRC, interleaving, or robust sorting is in # use. # # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | CMR=6 |R|R|R|R|1|FT#1=5 |Q|P|P|0|FT#2=5 |Q|P|P| f1(0..7) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | f1(8..15) | f1(16..23) | .... | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # : ... : # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | ... |f1(152..158) |P| f2(0..7) | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | f2(8..15) | f2(16..23) | .... | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # : ... : # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | ... |f2(152..158) |P| # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # def amrPayload2Storage_OctetAlignedMode(payload): try: # assume no interleaving, CRCs or bit re-ordering bitlen = [95,103,118,134,148,159,204,244,39] amr = BitArray(bytes=payload) cmr = amr[0:4] res = amr[4:8] assert res.uint==0,'amr[4:8] must be zero' f = amr[8] mode = amr[9:13] qual = amr[13:14] pad = amr[14:16] if mode.uint >=0 and mode.uint <= 8: assert amr.len >= 16+bitlen[mode.uint] voice = amr[16:16+bitlen[mode.uint]] storage = BitArray(bin='0') storage.append(mode) storage.append(qual) storage.append('0b00') # padding assert storage.len==8,"check length of storage header is one byte" storage.append(voice) return storage.tobytes() except: pdb.set_trace() return ''