Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add audio support to convert AAC to opus #6

Open
xiangxud opened this issue Jun 2, 2022 · 2 comments
Open

Add audio support to convert AAC to opus #6

xiangxud opened this issue Jun 2, 2022 · 2 comments

Comments

@xiangxud
Copy link

xiangxud commented Jun 2, 2022

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

}

@Sean-Der
Copy link
Owner

Sean-Der commented Jun 2, 2022

Hi @xiangxud

that’s fantastic! Would you mind opening a PR I can help get it merged

@xiangxud
Copy link
Author

xiangxud commented Jun 3, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants