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 ''