-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
593 additions
and
246 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package media | ||
|
||
type Writer[T any] interface { | ||
WriteSample(sample T) error | ||
} | ||
|
||
type WriterFunc[T any] func(in T) error | ||
|
||
func (fnc WriterFunc[T]) WriteSample(in T) error { | ||
return fnc(in) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package opus | ||
|
||
import ( | ||
"gopkg.in/hraban/opus.v2" | ||
|
||
"github.com/livekit/sip/pkg/media" | ||
) | ||
|
||
type Sample []byte | ||
|
||
func Decode(w media.Writer[media.PCM16Sample], sampleRate int, channels int) (media.Writer[Sample], error) { | ||
dec, err := opus.NewDecoder(sampleRate, channels) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buf := make([]int16, 1000) | ||
return media.WriterFunc[Sample](func(in Sample) error { | ||
n, err := dec.Decode(in, buf) | ||
if err != nil { | ||
return err | ||
} | ||
return w.WriteSample(buf[:n]) | ||
}), nil | ||
} | ||
|
||
func Encode(w media.Writer[Sample], sampleRate int, channels int) (media.Writer[media.PCM16Sample], error) { | ||
enc, err := opus.NewEncoder(sampleRate, channels, opus.AppVoIP) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buf := make([]byte, 1024) | ||
return media.WriterFunc[media.PCM16Sample](func(in media.PCM16Sample) error { | ||
n, err := enc.Encode(in, buf) | ||
if err != nil { | ||
return err | ||
} | ||
return w.WriteSample(buf[:n]) | ||
}), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package media | ||
|
||
import ( | ||
"encoding/binary" | ||
"time" | ||
|
||
"github.com/pion/webrtc/v3/pkg/media" | ||
) | ||
|
||
func PlayAudio[T any](w Writer[T], sampleDur time.Duration, frames []T) error { | ||
tick := time.NewTicker(sampleDur) | ||
defer tick.Stop() | ||
for range tick.C { | ||
if len(frames) == 0 { | ||
break | ||
} | ||
samples := frames[0] | ||
frames = frames[1:] | ||
if err := w.WriteSample(samples); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
type LPCM16Sample []byte | ||
|
||
func (s LPCM16Sample) Decode() PCM16Sample { | ||
out := make(PCM16Sample, len(s)/2) | ||
for i := 0; i < len(s); i += 2 { | ||
out[i/2] = int16(binary.LittleEndian.Uint16(s[i:])) | ||
} | ||
return out | ||
} | ||
|
||
type PCM16Sample []int16 | ||
|
||
func (s PCM16Sample) Encode() LPCM16Sample { | ||
out := make(LPCM16Sample, len(s)*2) | ||
for i, v := range s { | ||
binary.LittleEndian.PutUint16(out[2*i:], uint16(v)) | ||
} | ||
return out | ||
} | ||
|
||
func DecodePCM(w Writer[PCM16Sample]) Writer[LPCM16Sample] { | ||
return WriterFunc[LPCM16Sample](func(in LPCM16Sample) error { | ||
return w.WriteSample(in.Decode()) | ||
}) | ||
} | ||
|
||
func EncodePCM(w Writer[LPCM16Sample]) Writer[PCM16Sample] { | ||
return WriterFunc[PCM16Sample](func(in PCM16Sample) error { | ||
return w.WriteSample(in.Encode()) | ||
}) | ||
} | ||
|
||
type MediaSampleWriter interface { | ||
WriteSample(sample media.Sample) error | ||
} | ||
|
||
func FromSampleWriter[T ~[]byte](w MediaSampleWriter, sampleDur time.Duration) Writer[T] { | ||
return WriterFunc[T](func(in T) error { | ||
data := make([]byte, len(in)) | ||
copy(data, in) | ||
return w.WriteSample(media.Sample{Data: data, Duration: sampleDur}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package rtp | ||
|
||
import ( | ||
"github.com/pion/interceptor" | ||
"github.com/pion/rtp" | ||
|
||
"github.com/livekit/sip/pkg/media" | ||
) | ||
|
||
type Writer interface { | ||
WriteRTP(p *rtp.Packet) error | ||
} | ||
|
||
type Reader interface { | ||
ReadRTP() (*rtp.Packet, interceptor.Attributes, error) | ||
} | ||
|
||
type Handler interface { | ||
HandleRTP(p *rtp.Packet) error | ||
} | ||
|
||
type HandlerFunc func(p *rtp.Packet) error | ||
|
||
func (fnc HandlerFunc) HandleRTP(p *rtp.Packet) error { | ||
return fnc(p) | ||
} | ||
|
||
func HandleLoop(r Reader, h Handler) error { | ||
for { | ||
p, _, err := r.ReadRTP() | ||
if err != nil { | ||
return err | ||
} | ||
err = h.HandleRTP(p) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
func NewStream(w Writer, packetDur uint32) *Stream { | ||
s := &Stream{w: w, packetDur: packetDur} | ||
s.p = rtp.Packet{ | ||
Header: rtp.Header{ | ||
Version: 2, | ||
SSRC: 5000, // TODO: why this magic number? | ||
Timestamp: 0, | ||
SequenceNumber: 0, | ||
}, | ||
} | ||
return s | ||
} | ||
|
||
type Packet = rtp.Packet | ||
|
||
type Stream struct { | ||
w Writer | ||
p Packet | ||
packetDur uint32 | ||
} | ||
|
||
func (s *Stream) WritePayload(data []byte) error { | ||
s.p.Payload = data | ||
if err := s.w.WriteRTP(&s.p); err != nil { | ||
return err | ||
} | ||
s.p.Header.Timestamp += s.packetDur | ||
s.p.Header.SequenceNumber++ | ||
return nil | ||
} | ||
|
||
func NewMediaStreamOut[T ~[]byte](w Writer, packetDur uint32) *MediaStreamOut[T] { | ||
return &MediaStreamOut[T]{s: NewStream(w, packetDur)} | ||
} | ||
|
||
type MediaStreamOut[T ~[]byte] struct { | ||
s *Stream | ||
} | ||
|
||
func (s *MediaStreamOut[T]) WriteSample(sample T) error { | ||
return s.s.WritePayload([]byte(sample)) | ||
} | ||
|
||
func NewMediaStreamIn[T ~[]byte](w media.Writer[T]) *MediaStreamIn[T] { | ||
return &MediaStreamIn[T]{w: w} | ||
} | ||
|
||
type MediaStreamIn[T ~[]byte] struct { | ||
w media.Writer[T] | ||
} | ||
|
||
func (s *MediaStreamIn[T]) HandleRTP(p *rtp.Packet) error { | ||
return s.w.WriteSample(T(p.Payload)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package ulaw | ||
|
||
import ( | ||
"github.com/zaf/g711" | ||
|
||
"github.com/livekit/sip/pkg/media" | ||
) | ||
|
||
type Sample []byte | ||
|
||
func (s Sample) Decode() media.LPCM16Sample { | ||
return g711.DecodeUlaw(s) | ||
} | ||
|
||
func (s *Sample) Encode(data media.LPCM16Sample) { | ||
*s = g711.EncodeUlaw(data) | ||
} | ||
|
||
func Encode(w media.Writer[media.LPCM16Sample]) media.Writer[Sample] { | ||
return media.WriterFunc[Sample](func(in Sample) error { | ||
out := in.Decode() | ||
return w.WriteSample(out) | ||
}) | ||
} | ||
|
||
func Decode(w media.Writer[Sample]) media.Writer[media.LPCM16Sample] { | ||
return media.WriterFunc[media.LPCM16Sample](func(in media.LPCM16Sample) error { | ||
var s Sample | ||
s.Encode(in) | ||
return w.WriteSample(s) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.