package main import ( "fmt" "os" "git.metznet.ca/MetzNet/pnyx" "github.com/gen2brain/malgo" ) func main() { ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil) if err != nil { panic(err) } defer ctx.Free() defer ctx.Uninit() // Playback devices. 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.FormatF32 inDeviceConfig.Capture.Channels = 1 inDeviceConfig.Capture.DeviceID = capture_device.ID.Pointer() inDeviceConfig.SampleRate = capture_device.Formats[0].SampleRate inDeviceConfig.PeriodSizeInFrames = 100 inDeviceConfig.Alsa.NoMMap = 1 inDeviceConfig.Capture.ShareMode = malgo.Shared outDeviceConfig := malgo.DefaultDeviceConfig(malgo.Playback) outDeviceConfig.Playback.Format = malgo.FormatF32 outDeviceConfig.Playback.Channels = 1 outDeviceConfig.Playback.DeviceID = playback_device.ID.Pointer() outDeviceConfig.SampleRate = playback_device.Formats[0].SampleRate outDeviceConfig.PeriodSizeInFrames = 100 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) { data := make([]byte, len(input_samples)) copy(data, input_samples) select { case mic <- data: 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 } _ = pnyx.PeerID(packet.Data[0:16]) speaker <- packet.Data[16:] } }() 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) } 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) } } err = client.Send(pnyx.Packet{ Channel: pnyx.ChannelID(1), Mode: pnyx.MODE_RAW, Command: pnyx.MODE_COMMAND_LEAVE, Data: nil, }) if err != nil { panic(err) } err = client.Close() if err != nil { panic(err) } }