pnyx/cmd/client/main.go

236 lines
5.5 KiB
Go

package main
import (
"encoding/binary"
"fmt"
"os"
"git.metznet.ca/MetzNet/pnyx"
"github.com/gen2brain/malgo"
"github.com/hraban/opus"
)
func main() {
decoders := map[pnyx.PeerID]*opus.Decoder{}
encoder, err := opus.NewEncoder(48000, 1, opus.AppVoIP)
if err != nil {
panic(err)
}
ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil)
if err != nil {
panic(err)
}
defer ctx.Free()
defer ctx.Uninit()
infos, err := ctx.Devices(malgo.Playback)
if err != nil {
panic(err)
}
var playback_device *malgo.DeviceInfo = nil
for _, info := range infos {
if info.IsDefault != 0 {
full, err := ctx.DeviceInfo(malgo.Playback, info.ID, malgo.Shared)
if err != nil {
panic(err)
}
playback_device = &full
}
}
if playback_device == nil {
panic("No default playback device")
}
infos, err = ctx.Devices(malgo.Capture)
if err != nil {
panic(err)
}
var capture_device *malgo.DeviceInfo = nil
for _, info := range infos {
if info.IsDefault != 0 {
full, err := ctx.DeviceInfo(malgo.Capture, info.ID, malgo.Shared)
if err != nil {
panic(err)
}
capture_device = &full
}
}
if capture_device == nil {
panic("No default capture device")
}
inDeviceConfig := malgo.DefaultDeviceConfig(malgo.Capture)
inDeviceConfig.Capture.Format = malgo.FormatS16
inDeviceConfig.Capture.Channels = 1
inDeviceConfig.Capture.DeviceID = capture_device.ID.Pointer()
inDeviceConfig.SampleRate = 48000
inDeviceConfig.PeriodSizeInFrames = 960
inDeviceConfig.Alsa.NoMMap = 1
inDeviceConfig.Capture.ShareMode = malgo.Shared
outDeviceConfig := malgo.DefaultDeviceConfig(malgo.Playback)
outDeviceConfig.Playback.Format = malgo.FormatS16
outDeviceConfig.Playback.Channels = 1
outDeviceConfig.Playback.DeviceID = playback_device.ID.Pointer()
outDeviceConfig.SampleRate = 48000
outDeviceConfig.PeriodSizeInFrames = 960
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:
copy(output_samples, data)
default:
}
}
playbackCallbacks := malgo.DeviceCallbacks{
Data: onSendFrames,
}
fmt.Printf("Creating playback device %+v with format %+v\n", playback_device, playback_device.Formats[0])
outDevice, err := malgo.InitDevice(ctx.Context, outDeviceConfig, playbackCallbacks)
if err != nil {
panic(err)
}
fmt.Printf("Starting playback\n")
err = outDevice.Start()
if err != nil {
panic(err)
}
defer outDevice.Uninit()
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)
}
select {
case mic <- data[:written]:
default:
}
}
captureCallbacks := malgo.DeviceCallbacks{
Data: onRecvFrames,
}
fmt.Printf("Creating capture device %+v with format %+v\n", capture_device, capture_device.Formats[0])
inDevice, err := malgo.InitDevice(ctx.Context, inDeviceConfig, captureCallbacks)
if err != nil {
panic(err)
}
fmt.Printf("Starting capture device\n")
err = inDevice.Start()
if err != nil {
panic(err)
}
defer inDevice.Uninit()
defer inDevice.Stop()
fmt.Printf("Starting pnyx client\n")
client, err := pnyx.NewClient(nil, os.Args[1])
if err != nil {
panic(err)
}
go func() {
var buf [1024]byte
for true {
read, _, err := client.Connection.ReadFromUDP(buf[:])
if err != nil {
fmt.Printf("Read Error %s\n", err)
break
}
data, err := pnyx.ParseSessionData(&client.Session, buf[pnyx.COMMAND_LENGTH + pnyx.ID_LENGTH:read])
if err != nil {
fmt.Printf("ParseSessionData Error %s\n", err)
continue
}
packet, err := pnyx.ParsePacket(data)
if err != nil {
fmt.Printf("ParsePacket Error %s - %x\n", err, data)
continue
}
peer := pnyx.PeerID(packet.Data[0:16])
if packet.Channel == pnyx.ChannelID(1) {
decoder, exists := decoders[peer]
if exists == false {
decoder, err = opus.NewDecoder(48000, 1)
if err != nil {
panic(err)
}
}
pcm := make([]int16, 1000)
written, err := decoder.Decode(packet.Data[16:], pcm)
if err != nil {
panic(err)
}
data := make([]byte, written*2)
for i := 0; i < written; i++ {
binary.LittleEndian.PutUint16(data[i*2:], uint16(pcm[i]))
}
speaker <- data
}
}
}()
err = client.Send(pnyx.Packet{
Channel: pnyx.ChannelID(1),
Mode: pnyx.MODE_RAW,
Command: pnyx.MODE_COMMAND_JOIN,
Data: nil,
})
if err != nil {
panic(err)
}
err = client.Send(pnyx.Packet{
Channel: pnyx.ChannelID(2),
Mode: pnyx.MODE_RAW,
Command: pnyx.MODE_COMMAND_JOIN,
Data: nil,
})
if err != nil {
panic(err)
}
for true {
data := <- mic
err = client.Send(pnyx.Packet{
Channel: pnyx.ChannelID(1),
Mode: pnyx.MODE_RAW,
Command: pnyx.MODE_COMMAND_DATA,
Data: data,
})
if err != nil {
panic(err)
}
}
}