|  |  |  | @ -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) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | 
 |