2022-02-18 09:46:52 +00:00
|
|
|
package hls
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/aler9/gortsplib"
|
|
|
|
"github.com/aler9/gortsplib/pkg/aac"
|
|
|
|
)
|
|
|
|
|
|
|
|
type clientAudioProcessorData struct {
|
|
|
|
data []byte
|
|
|
|
pts time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
type clientAudioProcessor struct {
|
2022-02-19 11:25:23 +00:00
|
|
|
ctx context.Context
|
2022-03-20 15:55:53 +00:00
|
|
|
onTrack func(*gortsplib.TrackAAC) error
|
2022-02-19 11:25:23 +00:00
|
|
|
onData func(time.Duration, [][]byte)
|
2022-02-18 09:46:52 +00:00
|
|
|
|
2022-02-19 11:25:23 +00:00
|
|
|
trackInitialized bool
|
|
|
|
queue chan clientAudioProcessorData
|
|
|
|
clockStartRTC time.Time
|
2022-02-18 09:46:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newClientAudioProcessor(
|
|
|
|
ctx context.Context,
|
2022-03-20 15:55:53 +00:00
|
|
|
onTrack func(*gortsplib.TrackAAC) error,
|
2022-02-19 11:25:23 +00:00
|
|
|
onData func(time.Duration, [][]byte),
|
2022-02-18 09:46:52 +00:00
|
|
|
) *clientAudioProcessor {
|
|
|
|
p := &clientAudioProcessor{
|
2022-02-19 11:25:23 +00:00
|
|
|
ctx: ctx,
|
|
|
|
onTrack: onTrack,
|
|
|
|
onData: onData,
|
|
|
|
queue: make(chan clientAudioProcessorData, clientQueueSize),
|
2022-02-18 09:46:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *clientAudioProcessor) run() error {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case item := <-p.queue:
|
|
|
|
err := p.doProcess(item.data, item.pts)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
case <-p.ctx.Done():
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *clientAudioProcessor) doProcess(
|
|
|
|
data []byte,
|
2022-04-07 10:50:35 +00:00
|
|
|
pts time.Duration,
|
|
|
|
) error {
|
2022-02-18 09:46:52 +00:00
|
|
|
adtsPkts, err := aac.DecodeADTS(data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
aus := make([][]byte, 0, len(adtsPkts))
|
|
|
|
|
2022-05-10 21:35:07 +00:00
|
|
|
elapsed := time.Since(p.clockStartRTC)
|
|
|
|
if pts > elapsed {
|
|
|
|
select {
|
|
|
|
case <-p.ctx.Done():
|
|
|
|
return fmt.Errorf("terminated")
|
|
|
|
case <-time.After(pts - elapsed):
|
2022-02-18 09:46:52 +00:00
|
|
|
}
|
2022-05-10 21:35:07 +00:00
|
|
|
}
|
2022-02-18 09:46:52 +00:00
|
|
|
|
2022-05-10 21:35:07 +00:00
|
|
|
for _, pkt := range adtsPkts {
|
2022-02-19 11:25:23 +00:00
|
|
|
if !p.trackInitialized {
|
|
|
|
p.trackInitialized = true
|
|
|
|
|
2022-04-15 11:17:00 +00:00
|
|
|
track, err := gortsplib.NewTrackAAC(97, pkt.Type, pkt.SampleRate, pkt.ChannelCount, nil, 13, 3, 3)
|
2022-02-18 09:46:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.onTrack(track)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aus = append(aus, pkt.AU)
|
|
|
|
}
|
|
|
|
|
2022-02-19 11:25:23 +00:00
|
|
|
p.onData(pts, aus)
|
2022-02-18 09:46:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *clientAudioProcessor) process(
|
|
|
|
data []byte,
|
2022-04-07 10:50:35 +00:00
|
|
|
pts time.Duration,
|
|
|
|
) {
|
2022-02-18 09:46:52 +00:00
|
|
|
select {
|
|
|
|
case p.queue <- clientAudioProcessorData{data, pts}:
|
|
|
|
case <-p.ctx.Done():
|
|
|
|
}
|
|
|
|
}
|