|
|
|
package icsmediaconv
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"gitlab.com/ics_cinnamon/joy4/av"
|
|
|
|
"gitlab.com/ics_cinnamon/joy4/cgo/ffmpeg"
|
|
|
|
"gitlab.com/ics_cinnamon/joy4/codec"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icserror"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icslog"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icspacketparser"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
ICS_PT_MULAW = 0
|
|
|
|
ICS_PT_ALAW = 8
|
|
|
|
ICS_PT_G729 = 18
|
|
|
|
ICS_PT_END = ICS_PT_G729
|
|
|
|
)
|
|
|
|
|
|
|
|
const PCM_8K_16BIT_10MS_SIZE = 160
|
|
|
|
|
|
|
|
type Converter struct {
|
|
|
|
payloadtype icspacketparser.PayloadType
|
|
|
|
codec av.AudioCodecData
|
|
|
|
name string
|
|
|
|
decoder *ffmpeg.AudioDecoder
|
|
|
|
encoder *ffmpeg.AudioEncoder
|
|
|
|
|
|
|
|
samplingRate int
|
|
|
|
onePacketSize int
|
|
|
|
|
|
|
|
//frame *av.AudioFrame
|
|
|
|
|
|
|
|
isStart bool
|
|
|
|
m *sync.Mutex
|
|
|
|
|
|
|
|
ID int
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConverter(id int, pt icspacketparser.PayloadType, dec bool) (*Converter, *icserror.IcsError) {
|
|
|
|
conv := &Converter{payloadtype: pt}
|
|
|
|
|
|
|
|
conv.ID = id
|
|
|
|
conv.isStart = false
|
|
|
|
conv.m = &sync.Mutex{}
|
|
|
|
|
|
|
|
if dec { //decoding
|
|
|
|
switch pt {
|
|
|
|
case ICS_PT_MULAW:
|
|
|
|
conv.codec = codec.NewPCMMulawCodecData()
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 80
|
|
|
|
//conv.onePacketSize = 160
|
|
|
|
case ICS_PT_ALAW:
|
|
|
|
conv.codec = codec.NewPCMAlawCodecData()
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 80
|
|
|
|
//conv.onePacketSize = 160
|
|
|
|
case ICS_PT_G729:
|
|
|
|
conv.codec = codec.NewG729CodecData()
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 10
|
|
|
|
default:
|
|
|
|
return nil, icserror.ICSERRCONVNotSupportedCodec
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
conv.decoder, err = ffmpeg.NewAudioDecoder(conv.codec)
|
|
|
|
if err != nil {
|
|
|
|
icserror.ICSERRCONVNotSupportedCodec.SetError(err)
|
|
|
|
return nil, icserror.ICSERRCONVNotSupportedCodec
|
|
|
|
}
|
|
|
|
} else { //encoding
|
|
|
|
switch pt {
|
|
|
|
case ICS_PT_MULAW:
|
|
|
|
conv.codec = codec.NewPCMMulawCodecData()
|
|
|
|
conv.name = "mulaw"
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 160
|
|
|
|
case ICS_PT_ALAW:
|
|
|
|
conv.codec = codec.NewPCMAlawCodecData()
|
|
|
|
conv.name = "alaw"
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 160
|
|
|
|
case ICS_PT_G729:
|
|
|
|
conv.codec = codec.NewG729CodecData()
|
|
|
|
conv.name = "g729"
|
|
|
|
conv.samplingRate = 8000
|
|
|
|
conv.onePacketSize = 10
|
|
|
|
default:
|
|
|
|
return nil, icserror.ICSERRCONVNotSupportedCodec
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
conv.encoder, err = ffmpeg.NewAudioEncoderByCodecType(conv.codec.Type())
|
|
|
|
if err != nil {
|
|
|
|
// fmt.Println("########111", err)
|
|
|
|
icserror.ICSERRCONVNotSupportedCodec.SetError(err)
|
|
|
|
return nil, icserror.ICSERRCONVNotSupportedCodec
|
|
|
|
}
|
|
|
|
conv.encoder.SetChannelLayout(av.CH_MONO)
|
|
|
|
conv.encoder.SetSampleRate(conv.samplingRate)
|
|
|
|
conv.encoder.SetSampleFormat(av.S16)
|
|
|
|
// fmt.Println("########222", conv.name)
|
|
|
|
}
|
|
|
|
//ffmpeg.SetLogLevel(ffmpeg.QUIET)
|
|
|
|
|
|
|
|
conv.Start()
|
|
|
|
|
|
|
|
return conv, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) Start() {
|
|
|
|
c.m.Lock()
|
|
|
|
c.isStart = true
|
|
|
|
c.m.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) Stop() {
|
|
|
|
c.m.Lock()
|
|
|
|
c.isStart = false
|
|
|
|
c.m.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) IsStart() bool {
|
|
|
|
return c.isStart
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) Close() {
|
|
|
|
c.Stop()
|
|
|
|
if c.decoder != nil {
|
|
|
|
c.decoder.Close()
|
|
|
|
}
|
|
|
|
if c.encoder != nil {
|
|
|
|
c.encoder.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
l := icslog.GetIcsLog()
|
|
|
|
l.Print(icslog.LOG_LEVEL_INFO, c.ID, "Closed Converter")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) Decode(packet []byte) ([]byte, *icserror.IcsError) {
|
|
|
|
if c == nil {
|
|
|
|
return nil, icserror.ICSERRInvalidParam
|
|
|
|
}
|
|
|
|
//l := icslog.GetIcsLog()
|
|
|
|
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "converter### Decode() packet length: %d", len(packet))
|
|
|
|
|
|
|
|
retBuf := make([]byte, PCM_8K_16BIT_10MS_SIZE*2)
|
|
|
|
packetLen := len(packet)
|
|
|
|
iter := 0
|
|
|
|
for packetLen >= c.onePacketSize {
|
|
|
|
packetLen -= c.onePacketSize
|
|
|
|
|
|
|
|
//fmt.Printf("### Decode() iter(%d) packetlen(%d)\n", iter, packetLen)
|
|
|
|
buf := packet[c.onePacketSize*iter : c.onePacketSize*(iter+1)]
|
|
|
|
//fmt.Printf("### Decode() iter(%d), buf length %d %v\n", iter, len(buf), buf)
|
|
|
|
//l.Printf(icslog.LOG_LEVEL_DEBUG2, c.ID, "### Decode() iter(%d), buf length %d %v", iter, len(buf), buf)
|
|
|
|
|
|
|
|
c.m.Lock()
|
|
|
|
if c.IsStart() {
|
|
|
|
ok, frame, errDec := c.decoder.Decode(buf)
|
|
|
|
if !ok {
|
|
|
|
icserror.ICSERRCONVDecodeFail.SetError(errDec)
|
|
|
|
//icserror.ICSERRCONVDecodeFail.Print()
|
|
|
|
c.m.Unlock()
|
|
|
|
return nil, icserror.ICSERRCONVDecodeFail
|
|
|
|
}
|
|
|
|
|
|
|
|
//fmt.Println("###frame len", iter, PCM_8K_16BIT_10MS_SIZE*iter, PCM_8K_16BIT_10MS_SIZE*(iter+1))
|
|
|
|
//fmt.Println("###frame len", len(frame.Data[0]), len(frame.Data), frame)
|
|
|
|
copy(retBuf[PCM_8K_16BIT_10MS_SIZE*iter:PCM_8K_16BIT_10MS_SIZE*(iter+1)], frame.Data[0][:PCM_8K_16BIT_10MS_SIZE])
|
|
|
|
}
|
|
|
|
c.m.Unlock()
|
|
|
|
|
|
|
|
/*
|
|
|
|
f1, err := os.OpenFile("./tx.voice.raw", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
f1.Write(frame.Data[0][:PCM_8K_16BIT_10MS_SIZE])
|
|
|
|
f1.Sync()
|
|
|
|
f1.Close()
|
|
|
|
*/
|
|
|
|
|
|
|
|
iter++
|
|
|
|
}
|
|
|
|
//fmt.Println("###retBuf len", len(retBuf), retBuf)
|
|
|
|
|
|
|
|
return retBuf, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Converter) Encode(packet []byte) ([]byte, *icserror.IcsError) {
|
|
|
|
if c == nil {
|
|
|
|
return nil, icserror.ICSERRInvalidParam
|
|
|
|
}
|
|
|
|
//l := icslog.GetIcsLog()
|
|
|
|
//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "converter### Decode() packet length: %d", len(packet))
|
|
|
|
|
|
|
|
retBuf := make([]byte, PCM_8K_16BIT_10MS_SIZE)
|
|
|
|
//retBuf := make([]byte, PCM_8K_16BIT_10MS_SIZE*2)
|
|
|
|
packetLen := len(packet)
|
|
|
|
iter := 0
|
|
|
|
var onePacketSize int = c.onePacketSize
|
|
|
|
if c.codec.Type() == av.PCM_ALAW || c.codec.Type() == av.PCM_MULAW {
|
|
|
|
onePacketSize = onePacketSize
|
|
|
|
//onePacketSize = onePacketSize / 2
|
|
|
|
}
|
|
|
|
|
|
|
|
for packetLen >= onePacketSize {
|
|
|
|
packetLen -= onePacketSize
|
|
|
|
//for packetLen >= c.onePacketSize {
|
|
|
|
//packetLen -= c.onePacketSize
|
|
|
|
|
|
|
|
//fmt.Printf("### Decode() iter(%d) packetlen(%d)\n", iter, packetLen)
|
|
|
|
|
|
|
|
buf := packet[onePacketSize*iter : onePacketSize*(iter+1)]
|
|
|
|
//buf := packet[c.onePacketSize*iter : c.onePacketSize*(iter+1)]
|
|
|
|
|
|
|
|
//fmt.Printf("### Decode() iter(%d), buf length %d %v\n", iter, len(buf), buf)
|
|
|
|
//l.Printf(icslog.LOG_LEVEL_DEBUG2, c.ID, "### Decode() iter(%d), buf length %d %v", iter, len(buf), buf)
|
|
|
|
|
|
|
|
tbuf := make([][]byte, 1)
|
|
|
|
tbuf[0] = buf
|
|
|
|
|
|
|
|
frame := av.AudioFrame{
|
|
|
|
SampleFormat: av.S16,
|
|
|
|
ChannelLayout: av.CH_MONO,
|
|
|
|
SampleCount: c.onePacketSize / 2,
|
|
|
|
SampleRate: c.samplingRate,
|
|
|
|
Data: tbuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
//fmt.Printf(">>>%+v\n", frame)
|
|
|
|
|
|
|
|
c.m.Lock()
|
|
|
|
if c.IsStart() {
|
|
|
|
pcmFrame, errEnc := c.encoder.Encode(frame)
|
|
|
|
//ok, frame, errDec := c.decoder.Decode(buf)
|
|
|
|
if errEnc != nil {
|
|
|
|
icserror.ICSERRCONVEncodeFail.SetError(errEnc)
|
|
|
|
//icserror.ICSERRCONVDecodeFail.Print()
|
|
|
|
c.m.Unlock()
|
|
|
|
return nil, icserror.ICSERRCONVEncodeFail
|
|
|
|
}
|
|
|
|
|
|
|
|
//fmt.Println("###frame len", iter, PCM_8K_16BIT_10MS_SIZE*iter, PCM_8K_16BIT_10MS_SIZE*(iter+1))
|
|
|
|
//fmt.Println("###frame len", len(frame.Data[0]), len(frame.Data), frame)
|
|
|
|
copy(retBuf[(PCM_8K_16BIT_10MS_SIZE/2)*iter:(PCM_8K_16BIT_10MS_SIZE/2)*(iter+1)], pcmFrame[0][:(PCM_8K_16BIT_10MS_SIZE/2)])
|
|
|
|
//copy(retBuf[PCM_8K_16BIT_10MS_SIZE*iter:PCM_8K_16BIT_10MS_SIZE*(iter+1)], pcmFrame[0][:PCM_8K_16BIT_10MS_SIZE])
|
|
|
|
//fmt.Printf("%d$$$%v", len(pcmFrame[0]), pcmFrame[0])
|
|
|
|
}
|
|
|
|
c.m.Unlock()
|
|
|
|
|
|
|
|
iter++
|
|
|
|
}
|
|
|
|
//fmt.Println("###retBuf len", len(retBuf), retBuf)
|
|
|
|
|
|
|
|
return retBuf, nil
|
|
|
|
}
|