using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; using WebSocketSharp; namespace Example1 { internal class AudioStreamer : IDisposable { private Dictionary _audioBox; private Timer _heartbeatTimer; private uint? _id; private string _name; private Notifier _notifier; private WebSocket _websocket; public AudioStreamer (string url) { _websocket = new WebSocket (url); _audioBox = new Dictionary (); _heartbeatTimer = new Timer (sendHeartbeat, null, -1, -1); _id = null; _notifier = new Notifier (); configure (); } private AudioMessage acceptBinaryMessage (byte [] data) { var id = data.SubArray (0, 4).To (ByteOrder.Big); var chNum = data.SubArray (4, 1) [0]; var bufferLength = data.SubArray (5, 4).To (ByteOrder.Big); var bufferArray = new float [chNum, bufferLength]; var offset = 9; ((int) chNum).Times ( i => bufferLength.Times ( j => { bufferArray [i, j] = data.SubArray (offset, 4).To (ByteOrder.Big); offset += 4; })); return new AudioMessage { user_id = id, ch_num = chNum, buffer_length = bufferLength, buffer_array = bufferArray }; } private NotificationMessage acceptTextMessage (string data) { var json = JObject.Parse (data); var id = (uint) json ["user_id"]; var name = (string) json ["name"]; var type = (string) json ["type"]; string message; if (type == "message") message = String.Format ("{0}: {1}", name, (string) json ["message"]); else if (type == "start_music") message = String.Format ("{0}: Started playing music!", name); else if (type == "connection") { var users = (JArray) json ["message"]; var msg = new StringBuilder ("Now keeping connections:"); foreach (JToken user in users) msg.AppendFormat ( "\n- user_id: {0} name: {1}", (uint) user ["user_id"], (string) user ["name"]); message = msg.ToString (); } else if (type == "connected") { _id = id; _heartbeatTimer.Change (30000, 30000); message = String.Format ("user_id: {0} name: {1}", id, name); } else message = "Received unknown type message."; return new NotificationMessage { Summary = String.Format ("AudioStreamer ({0})", type), Body = message, Icon = "notification-message-im" }; } private void configure () { #if DEBUG _websocket.Log.Level = LogLevel.Trace; #endif _websocket.OnOpen += (sender, e) => _websocket.Send (createTextMessage ("connection", String.Empty)); _websocket.OnMessage += (sender, e) => { if (e.Type == Opcode.Text) _notifier.Notify (acceptTextMessage (e.Data)); else { var msg = acceptBinaryMessage (e.RawData); if (msg.user_id == _id) return; if (_audioBox.ContainsKey (msg.user_id)) { _audioBox [msg.user_id].Enqueue (msg.buffer_array); return; } var queue = Queue.Synchronized (new Queue ()); queue.Enqueue (msg.buffer_array); _audioBox.Add (msg.user_id, queue); } }; _websocket.OnError += (sender, e) => _notifier.Notify ( new NotificationMessage { Summary = "AudioStreamer (error)", Body = e.Message, Icon = "notification-message-im" }); _websocket.OnClose += (sender, e) => _notifier.Notify ( new NotificationMessage { Summary = "AudioStreamer (disconnect)", Body = String.Format ("code: {0} reason: {1}", e.Code, e.Reason), Icon = "notification-message-im" }); } private byte [] createAudioMessage (float [,] bufferArray) { var msg = new List (); var id = (uint) _id; var chNum = bufferArray.GetLength (0); var bufferLength = bufferArray.GetLength (1); msg.AddRange (id.ToByteArray (ByteOrder.Big)); msg.Add ((byte) chNum); msg.AddRange (((uint) bufferLength).ToByteArray (ByteOrder.Big)); chNum.Times ( i => bufferLength.Times ( j => msg.AddRange (bufferArray [i, j].ToByteArray (ByteOrder.Big)))); return msg.ToArray (); } private string createTextMessage (string type, string message) { return JsonConvert.SerializeObject ( new TextMessage { user_id = _id, name = _name, type = type, message = message }); } private void sendHeartbeat (object state) { _websocket.Send (createTextMessage ("heartbeat", String.Empty)); } public void Connect (string username) { _name = username; _websocket.Connect (); } public void Disconnect () { _heartbeatTimer.Change (-1, -1); _websocket.Close (CloseStatusCode.Away); _audioBox.Clear (); _id = null; _name = null; } public void Write (string message) { _websocket.Send (createTextMessage ("message", message)); } void IDisposable.Dispose () { Disconnect (); _heartbeatTimer.Dispose (); _notifier.Close (); } } }