stillbox/cmd/calls/audio.go

121 lines
1.8 KiB
Go
Raw Normal View History

2024-08-04 23:05:23 -04:00
package main
import (
"fmt"
"log"
2024-08-04 23:05:23 -04:00
"time"
2024-08-05 13:18:09 -04:00
"dynatron.me/x/go-minimp3"
2024-08-04 23:32:46 -04:00
"github.com/hajimehoshi/oto"
2024-08-04 23:05:23 -04:00
)
type Player struct {
c chan playReq
2024-08-04 23:50:14 -04:00
ctx *oto.Context
sampleRate int
channels int
2024-08-04 23:05:23 -04:00
}
func NewPlayer() *Player {
p := &Player{
c: make(chan playReq, 256),
}
2024-08-04 23:05:23 -04:00
return p
}
func (p *Player) Queue() int {
return len(p.c)
}
2024-08-04 23:32:46 -04:00
func (p *Player) initOto(samp, channels int) error {
2024-08-04 23:50:14 -04:00
if samp != p.sampleRate || channels != p.channels {
if p.ctx != nil {
err := p.ctx.Close()
if err != nil {
return err
}
}
var err error
if p.ctx, err = oto.NewContext(samp, channels, 2, 1024); err != nil {
return err
}
p.sampleRate = samp
p.channels = channels
2024-08-04 23:32:46 -04:00
}
return nil
2024-08-04 23:05:23 -04:00
}
2024-08-04 23:32:46 -04:00
func (p *Player) playMP3(audio []byte) error {
2024-08-11 13:46:43 -04:00
dec, data, err := minimp3.DecodeFull(audio)
if err != nil {
2024-08-04 23:32:46 -04:00
return err
}
err = p.initOto(dec.SampleRate, dec.Channels)
if err != nil {
return err
}
var player = p.ctx.NewPlayer()
2024-08-11 14:48:17 -04:00
_, err = player.Write(data)
if err != nil {
return err
}
2024-08-04 23:32:46 -04:00
<-time.After(time.Second)
dec.Close()
if err = player.Close(); err != nil {
return err
}
return nil
}
type playReq struct {
audio []byte
mimeType string
}
func (p *Player) Play(audio []byte, mimeType string) {
p.c <- playReq{audio, mimeType}
}
func (p *Player) play(req playReq) error {
switch req.mimeType {
2024-08-04 23:05:23 -04:00
case "audio/mpeg":
return p.playMP3(req.audio)
2024-08-04 23:05:23 -04:00
case "audio/wav":
2024-08-04 23:50:14 -04:00
panic("wav not implemented yet")
2024-08-04 23:05:23 -04:00
default:
return fmt.Errorf("unknown format %s", req.mimeType)
2024-08-04 23:05:23 -04:00
}
}
2024-08-04 23:05:23 -04:00
func (p *Player) Go(done <-chan struct{}) {
for {
select {
case <-done:
close(p.c)
p.ctx.Close()
return
case r, ok := <-p.c:
if !ok {
p.ctx.Close()
return
}
fmt.Printf("> [Q: %d]\r", p.Queue())
err := p.play(r)
fmt.Printf("\033[2K")
if err != nil {
log.Println(err)
}
}
}
2024-08-04 23:05:23 -04:00
}