rtmp-to-webrtc
rtmp-to-webrtc copied to clipboard
Add audio support to convert AAC to opus
hi: I added audio support to convert AAC to opus. Welcome to test add import package "github.com/Glimesh/go-fdkaac/fdkaac" opus "gopkg.in/hraban/opus.v2" please run in bash: apt install -y pkg-config build-essential libopusfile-dev libfdk-aac-dev libavutil-dev libavcodec-dev libswscale-dev
source code:
type Handler struct { rtmp.DefaultHandler peerConnection *webrtc.PeerConnection videoTrack, audioTrack *webrtc.TrackLocalStaticSample audioDecoder *fdkaac.AacDecoder audioEncoder *opus.Encoder audioBuffer []byte audioClockRate uint32 } func (h *Handler) SetOpusCtl() { h.audioEncoder.SetMaxBandwidth(opus.Bandwidth(2)) h.audioEncoder.SetComplexity(9) h.audioEncoder.SetBitrateToAuto() h.audioEncoder.SetInBandFEC(true) } func (h *Handler) initAudio(clockRate uint32) error { // h.audioSequencer = rtp.NewFixedSequencer(0) // ftl client says this should be changed to a random value // h.audioPacketizer = rtp.NewPacketizer(FTL_MTU, FTL_AUDIO_PT, uint32(h.channelID), &codecs.OpusPayloader{}, h.audioSequencer, clockRate) // if h.audioEncoder != nil && h.audioDecoder != nil { // return nil // } encoder, err := opus.NewEncoder(48000, 2, opus.AppAudio) if err != nil { println(err.Error()) return err } h.audioEncoder = encoder h.SetOpusCtl() // h.audioEncoder, err = opus.NewEncoder(int(clockRate), 32000, 2) // // h.audioEncoder, err = opus.NewEncoder(int(clockRate), 2, opus.AppVoIP) // if err != nil { // return err // } h.audioDecoder = fdkaac.NewAacDecoder()
return nil
} func (h *Handler) OnAudio(timestamp uint32, payload io.Reader) error { // Convert AAC to opus var audio flvtag.AudioData if err := flvtag.DecodeAudioData(payload, &audio); err != nil { return err }
// data, err := io.ReadAll(audio.Data)
// if err != nil {
// return err
// }
data := new(bytes.Buffer)
if _, err := io.Copy(data, audio.Data); err != nil {
return err
}
if data.Len() <= 0 {
log.Println("no audio datas", timestamp, payload)
return fmt.Errorf("no audio datas")
}
// log.Println("\r\ntimestamp->", timestamp, "\r\npayload->", payload, "\r\naudio data->", data.Bytes())
// return nil
datas := data.Bytes()
// log.Println("\r\naudio data len:", len(datas), "->") // hex.EncodeToString(datas))
// if audio.
if audio.AACPacketType == flvtag.AACPacketTypeSequenceHeader {
log.Println("Created new codec ", hex.EncodeToString(datas))
// return h.audioTrack.WriteSample(media.Sample{
// Data: datas, //data.Bytes(),
// Duration: 128 * time.Millisecond,
// })
err := h.initAudio(h.audioClockRate)
if err != nil {
log.Println(err, "error initializing Audio")
return fmt.Errorf("can't initialize codec with %s", err.Error())
}
err = h.audioDecoder.InitRaw(datas)
if err != nil {
log.Println(err, "error initializing stream")
return fmt.Errorf("can't initialize codec with %s", hex.EncodeToString(datas))
}
return nil
}
pcm, err := h.audioDecoder.Decode(datas)
if err != nil {
log.Println("decode error: ", hex.EncodeToString(datas), err)
return fmt.Errorf("decode error")
}
// log.Println("\r\npcm len ", len(pcm), " ->") //, pcm)
blockSize := 960
for h.audioBuffer = append(h.audioBuffer, pcm...); len(h.audioBuffer) >= blockSize*4; h.audioBuffer = h.audioBuffer[blockSize*4:] {
pcm16 := make([]int16, blockSize*2)
pcm16len := len(pcm16)
for i := 0; i < pcm16len; i++ {
pcm16[i] = int16(binary.LittleEndian.Uint16(h.audioBuffer[i*2:]))
}
bufferSize := 1024
opusData := make([]byte, bufferSize)
n, err := h.audioEncoder.Encode(pcm16, opusData)
// n, err := h.audioEncoder.ReadEncode(pcm16, opusData)
if err != nil {
return err
}
// WriteSample(media.Sample{Data: audio.Data, Duration: sampleDuration1})
opusOutput := opusData[:n]
// log.Println(" pcm len:", pcm16len, " data->", " opusData len", n, " data->")
if audioErr := h.audioTrack.WriteSample(media.Sample{
Data: opusOutput,
Duration: 20 * time.Millisecond,
}); audioErr != nil {
log.Println("WriteSample err", audioErr)
}
// packets := h.audioPacketizer.Packetize(opusOutput, uint32(blockSize))
// for _, p := range packets {
// h.audioPackets++
// if err := h.audioTrack.rtpTrack.WriteRTP(p); err != nil {
// h.log.Error(err)
// return err
// }
// }
}
return nil
}
Hi @xiangxud
that’s fantastic! Would you mind opening a PR I can help get it merged
It's my first PR,please forgive my poor skill
AAC convert to OPUS
Modify from source https://github.com/Glimesh/rtmp-ingest.git thanks Glimesh
macOS Development
brew install opusfile fdk-aac
Ubuntu / Linux Development
apt install -y pkg-config build-essential libopusfile-dev libfdk-aac-dev libavutil-dev libavcodec-dev libswscale-dev