forked from nstehr/bobcaygeon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
player.go
140 lines (120 loc) · 2.93 KB
/
player.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package player
import (
"bytes"
"encoding/binary"
"log"
"sync"
"github.com/carterpeel/bobcaygeon/rtsp"
"github.com/hajimehoshi/oto"
)
// Player defines a player for outputting the data packets from the session
type Player interface {
Play(session *rtsp.Session)
SetVolume(volume float64)
SetMute(isMuted bool)
GetIsMuted() bool
SetTrack(album string, artist string, title string)
SetAlbumArt(artwork []byte)
GetTrack() Track
}
// LocalPlayer is a player that will just play the audio locally
type LocalPlayer struct {
volLock sync.RWMutex
volume float64
}
// Track represents a track playing by the player
type Track struct {
Artist string
Album string
Title string
Artwork []byte
}
// NewLocalPlayer instantiates a new LocalPlayer
func NewLocalPlayer() *LocalPlayer {
return &LocalPlayer{volume: 1}
}
// Play will play the packets received on the specified session
func (lp *LocalPlayer) Play(session *rtsp.Session) {
go lp.playStream(session)
}
// SetVolume accepts a float between 0 (mute) and 1 (full volume)
func (lp *LocalPlayer) SetVolume(volume float64) {
lp.volLock.Lock()
defer lp.volLock.Unlock()
lp.volume = volume
}
// SetTrack sets the track for the player
func (lp *LocalPlayer) SetTrack(album string, artist string, title string) {
// no op for now
}
// SetAlbumArt sets the album art for the player
func (lp *LocalPlayer) SetAlbumArt(artwork []byte) {
// no op for now
}
// SetMute will mute or unmute the player
func (lp *LocalPlayer) SetMute(isMuted bool) {
// no op for now
}
// GetIsMuted returns muted state
func (lp *LocalPlayer) GetIsMuted() bool {
return false
}
// GetTrack returns the track
func (lp *LocalPlayer) GetTrack() Track {
return Track{}
}
func (lp *LocalPlayer) playStream(session *rtsp.Session) {
pctx, err := oto.NewContext(44100, 2, 2, 10000)
if err != nil {
log.Println("error initializing player", err)
return
}
p := pctx.NewPlayer()
decoder := GetCodec(session)
for d := range session.DataChan {
lp.volLock.RLock()
vol := lp.volume
lp.volLock.RUnlock()
decoded, err := decoder(d)
if err != nil {
log.Println("Problem decoding packet")
}
p.Write(AdjustAudio(decoded, vol))
}
log.Println("Data stream ended closing player")
p.Close()
}
// AdjustAudio takes a raw data frame of audio and a volume value between 0 and 1, 1 being full volume, 0 being mute
func AdjustAudio(raw []byte, vol float64) []byte {
if vol == 1 {
return raw
}
adjusted := new(bytes.Buffer)
for i := 0; i < len(raw); i = i + 2 {
var val int16
b := raw[i : i+2]
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &val)
if err != nil {
log.Println(err)
}
mod := vol * float64(val)
val = int16(mod)
val = min(32767, val)
val = max(-32767, val)
binary.Write(adjusted, binary.LittleEndian, val)
}
return adjusted.Bytes()
}
func min(a, b int16) int16 {
if a < b {
return a
}
return b
}
func max(a, b int16) int16 {
if a > b {
return a
}
return b
}