|
|
|
@ -8,16 +8,83 @@ import (
|
|
|
|
|
|
|
|
|
|
"git.metznet.ca/MetzNet/pnyx"
|
|
|
|
|
"github.com/gen2brain/malgo"
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"github.com/hraban/opus"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
decoders := map[pnyx.PeerID]chan[]byte{}
|
|
|
|
|
encoder, err := opus.NewEncoder(48000, 1, opus.AppVoIP)
|
|
|
|
|
var decoders = map[pnyx.PeerID]chan[]byte{}
|
|
|
|
|
var encoder *opus.Encoder
|
|
|
|
|
var sample_rate int = 0
|
|
|
|
|
var mic = make(chan []byte, 0)
|
|
|
|
|
var speaker = make(chan []byte, 0)
|
|
|
|
|
|
|
|
|
|
func set_sample_rate(new_sample_rate int) error {
|
|
|
|
|
sample_rate = new_sample_rate
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
fmt.Printf("Creating encoder with sample_rate %d\n", new_sample_rate)
|
|
|
|
|
encoder, err = opus.NewEncoder(new_sample_rate, 1, opus.AppVoIP)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for peer_id, decoder_chan := range(decoders) {
|
|
|
|
|
if decoder_chan != nil {
|
|
|
|
|
decoder_chan <- nil
|
|
|
|
|
}
|
|
|
|
|
new_chan := make(chan[]byte, 1000)
|
|
|
|
|
decoders[peer_id] = new_chan
|
|
|
|
|
go handle_peer_decode(peer_id, decoders[peer_id], sample_rate)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handle_peer_decode(peer_id pnyx.PeerID, decode_chan chan[]byte, sample_rate int){
|
|
|
|
|
fmt.Printf("Starting decoder routine for %x with sample_rate %d\n", peer_id, sample_rate)
|
|
|
|
|
decoder, err := opus.NewDecoder(sample_rate, 1)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
running := true
|
|
|
|
|
for running {
|
|
|
|
|
select {
|
|
|
|
|
case <-time.After(20*time.Millisecond):
|
|
|
|
|
pcm := make([]int16, sample_rate/50)
|
|
|
|
|
err := decoder.DecodePLC(pcm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pcm_bytes := make([]byte, sample_rate/50*2)
|
|
|
|
|
for i := 0; i < sample_rate/50; i++ {
|
|
|
|
|
binary.LittleEndian.PutUint16(pcm_bytes[i*2:], uint16(pcm[i]))
|
|
|
|
|
}
|
|
|
|
|
speaker <- pcm_bytes
|
|
|
|
|
|
|
|
|
|
case data := <-decode_chan:
|
|
|
|
|
if data == nil {
|
|
|
|
|
running = false
|
|
|
|
|
} else {
|
|
|
|
|
pcm := make([]int16, sample_rate/50*2)
|
|
|
|
|
written, err := decoder.Decode(data, pcm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pcm_bytes := make([]byte, written*2)
|
|
|
|
|
for i := 0; i < written; i++ {
|
|
|
|
|
binary.LittleEndian.PutUint16(pcm_bytes[i*2:], uint16(pcm[i]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
speaker <- pcm_bytes
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("Stopping decoder routine for %x with sample_rate %d\n", peer_id, sample_rate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
@ -84,9 +151,6 @@ func main() {
|
|
|
|
|
outDeviceConfig.Alsa.NoMMap = 1
|
|
|
|
|
outDeviceConfig.Playback.ShareMode = malgo.Shared
|
|
|
|
|
|
|
|
|
|
mic := make(chan []byte, 0)
|
|
|
|
|
speaker := make(chan []byte, 0)
|
|
|
|
|
|
|
|
|
|
onSendFrames := func(output_samples []byte, input_samples []byte, framecount uint32) {
|
|
|
|
|
select {
|
|
|
|
|
case data := <- speaker:
|
|
|
|
@ -115,20 +179,21 @@ func main() {
|
|
|
|
|
defer outDevice.Stop()
|
|
|
|
|
|
|
|
|
|
onRecvFrames := func(output_samples []byte, input_samples []byte, framecount uint32) {
|
|
|
|
|
pcm := make([]int16, len(input_samples)/2)
|
|
|
|
|
for i := 0; i < len(input_samples)/2; i++ {
|
|
|
|
|
pcm[i] = int16(binary.LittleEndian.Uint16(input_samples[2*i:]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data := make([]byte, len(input_samples))
|
|
|
|
|
written, err := encoder.Encode(pcm, data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
if encoder != nil {
|
|
|
|
|
pcm := make([]int16, len(input_samples)/2)
|
|
|
|
|
for i := 0; i < len(input_samples)/2; i++ {
|
|
|
|
|
pcm[i] = int16(binary.LittleEndian.Uint16(input_samples[2*i:]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case mic <- data[:written]:
|
|
|
|
|
default:
|
|
|
|
|
data := make([]byte, len(input_samples))
|
|
|
|
|
written, err := encoder.Encode(pcm, data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
select {
|
|
|
|
|
case mic <- data[:written]:
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -182,51 +247,42 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch packet := packet.(type) {
|
|
|
|
|
case pnyx.ChannelPeerPacket:
|
|
|
|
|
case pnyx.ChannelCommandPacket:
|
|
|
|
|
if packet.Channel == pnyx.ChannelID(0) {
|
|
|
|
|
decode_chan, exists := decoders[packet.Peer]
|
|
|
|
|
if exists == false {
|
|
|
|
|
decode_chan = make(chan[]byte, 1000)
|
|
|
|
|
decoders[packet.Peer] = decode_chan
|
|
|
|
|
|
|
|
|
|
go func(decode_chan chan[]byte){
|
|
|
|
|
decoder, err := opus.NewDecoder(48000, 1)
|
|
|
|
|
if packet.Mode == pnyx.MODE_AUDIO {
|
|
|
|
|
if packet.Command == pnyx.AUDIO_SET_SAMPLE_RATE {
|
|
|
|
|
fmt.Printf("GOT NEW SAMPLE RATE 0x%02x\n", packet.Data)
|
|
|
|
|
var new_sample_rate int
|
|
|
|
|
switch packet.Data[0] {
|
|
|
|
|
case byte(pnyx.SAMPLE_RATE_24KHZ):
|
|
|
|
|
new_sample_rate = 24000
|
|
|
|
|
case byte(pnyx.SAMPLE_RATE_48KHZ):
|
|
|
|
|
new_sample_rate = 48000
|
|
|
|
|
default:
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
err := set_sample_rate(new_sample_rate)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for true {
|
|
|
|
|
select {
|
|
|
|
|
case <-time.After(20*time.Millisecond):
|
|
|
|
|
pcm := make([]int16, 960)
|
|
|
|
|
err := decoder.DecodePLC(pcm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pcm_bytes := make([]byte, 960*2)
|
|
|
|
|
for i := 0; i < 960; i++ {
|
|
|
|
|
binary.LittleEndian.PutUint16(pcm_bytes[i*2:], uint16(pcm[i]))
|
|
|
|
|
}
|
|
|
|
|
speaker <- pcm_bytes
|
|
|
|
|
case data := <-decode_chan:
|
|
|
|
|
pcm := make([]int16, 960)
|
|
|
|
|
written, err := decoder.Decode(data, pcm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pcm_bytes := make([]byte, written*2)
|
|
|
|
|
for i := 0; i < written; i++ {
|
|
|
|
|
binary.LittleEndian.PutUint16(pcm_bytes[i*2:], uint16(pcm[i]))
|
|
|
|
|
}
|
|
|
|
|
speaker <- pcm_bytes
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}(decoders[packet.Peer])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case pnyx.ChannelPeerPacket:
|
|
|
|
|
if packet.Channel == pnyx.ChannelID(0) {
|
|
|
|
|
decode_chan, exists := decoders[packet.Peer]
|
|
|
|
|
if exists == false {
|
|
|
|
|
if sample_rate != 0 {
|
|
|
|
|
decode_chan = make(chan[]byte, 1000)
|
|
|
|
|
decoders[packet.Peer] = decode_chan
|
|
|
|
|
go handle_peer_decode(packet.Peer, decoders[packet.Peer], sample_rate)
|
|
|
|
|
decode_chan <- packet.Data
|
|
|
|
|
} else {
|
|
|
|
|
decoders[packet.Peer] = nil
|
|
|
|
|
}
|
|
|
|
|
} else if decode_chan != nil {
|
|
|
|
|
decode_chan <- packet.Data
|
|
|
|
|
}
|
|
|
|
|
decode_chan <- packet.Data
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
fmt.Printf("Unhandled packet type: %s\n", packet)
|
|
|
|
@ -234,15 +290,27 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
join_packet, _ := pnyx.NewChannelCommandPacket(pnyx.ChannelID(0), pnyx.MODE_CHANNEL, pnyx.CHANNEL_JOIN, nil)
|
|
|
|
|
add_packet, _ := pnyx.NewServerCommandPacket(pnyx.SERVER_COMMAND_ADD_CHANNEL, []byte{0xFF})
|
|
|
|
|
err = client.Send(add_packet)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
join_packet := pnyx.NewChannelCommandPacket(uuid.New(), pnyx.ChannelID(0), pnyx.MODE_CHANNEL, pnyx.CHANNEL_JOIN, nil)
|
|
|
|
|
err = client.Send(join_packet)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get_sample_rate_packet := pnyx.NewChannelCommandPacket(uuid.New(), pnyx.ChannelID(0), pnyx.MODE_AUDIO, pnyx.AUDIO_SET_SAMPLE_RATE, []byte{byte(pnyx.SAMPLE_RATE_48KHZ)})
|
|
|
|
|
err = client.Send(get_sample_rate_packet)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for true {
|
|
|
|
|
data := <- mic
|
|
|
|
|
err = client.Send(pnyx.NewChannelDataPacket(pnyx.ChannelID(0), pnyx.MODE_RAW, data))
|
|
|
|
|
err = client.Send(pnyx.NewChannelDataPacket(pnyx.ChannelID(0), pnyx.MODE_AUDIO, data))
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|