/// <summary> /// Handles wrapping the session into a higher level object, registering /// it in the service and notifying of the event. /// </summary> /// <param name="session_"></param> private void OnSessionCreated(AudioSessionControl session_) { var session = new AudioSession(session_); AppLogging.DebugLog(nameof(OnSessionCreated), session.SessionIdentifier, session.DisplayName, session.Id.ToString()); RegisterSession(session); }
// Using a template, with a constraint of IMessage allows us to pass the message without boxing reducing garbage generation private unsafe void ReadMessage <T>(DateTime now, Command command) where T : unmanaged, IMessage { int length = 0; try { while (length < sizeof(T)) { length += m_SerialPort.Read(m_ReadBuffer, length, sizeof(T) - length); } if (length != sizeof(T)) { throw new ArgumentException($"Message Length: {length}. Expected Length: {sizeof(T)}."); } } catch (Exception e) { AppLogging.DebugLogException(nameof(ReadMessage), e); Interlocked.Increment(ref m_ErrorCount); return; } T message = new T(); message.SetBytes(m_ReadBuffer); AppLogging.DebugLog(nameof(ReadMessage), command.ToString(), message.ToString()); Interlocked.Add(ref m_ReadBytes, length); m_LastMessageRead = now; m_MessageContext.Post(x => OnMessageRecieved?.Invoke(command, message), null); }
/// <summary> /// Registers the device with the service so it's aware /// of events and they're handled properly. /// </summary> /// <param name="device"></param> private void RegisterDevice(IAudioDevice device) { AppLogging.DebugLog(nameof(RegisterDevice), device.DeviceId, device.DisplayName, device.Device.DataFlow.ToString()); if (_devices.ContainsKey(device.Id)) { device.Dispose(); return; } _devices.Add(device.Id, device); device.DeviceDefaultChanged += OnDefaultDeviceChanged; device.DeviceVolumeChanged += OnDeviceVolumeChanged; device.DeviceRemoved += OnDeviceRemoved; RaiseDeviceCreated(device.Id, device.DisplayName, device.Volume, device.IsMuted, device.Flow); if (device.Flow == DeviceFlow.Output) { var sessionManager = AudioSessionManager2.FromMMDevice(device.Device); sessionManager.SessionCreated += OnSessionCreated; _sessionManagers.Add(device.Id, sessionManager); foreach (var session in sessionManager.GetSessionEnumerator()) { OnSessionCreated(session); } } }
private void Connect(DateTime now) { string[] portNames = null; try { portNames = SerialPort.GetPortNames(); } catch { } if (portNames == null || portNames.Length == 0) { return; } foreach (string portName in portNames) { string firmware = ""; try { AppLogging.DebugLog(nameof(Connect), portName); m_SerialPort = new SerialPort(portName, 115200); m_SerialPort.ReadTimeout = k_ReadTimeout; m_SerialPort.WriteTimeout = k_WriteTimeout; m_SerialPort.Open(); m_SerialPort.DiscardInBuffer(); m_SerialPort.DiscardOutBuffer(); WriteMessage(now, Command.TEST); Thread.Sleep(20); Command command = (Command)m_SerialPort.ReadByte(); if (command != Command.TEST) { throw new InvalidOperationException($"Firmware Test reply failed. Reply: '{command}' Bytes: '{m_SerialPort.BytesToRead}'"); } firmware = m_SerialPort.ReadLine().Replace("\r", ""); if (!FirmwareVersions.IsCompatible(firmware)) { throw new ArgumentException($"Incompatible Firmware: '{firmware}'."); } m_SerialPort.DataReceived += Read; m_DeviceConnected = true; m_DeviceReady = true; m_MessageContext.Post(x => OnDeviceConnected?.Invoke(), null); m_LastMessageRead = now; return; } catch (Exception e) { AppLogging.DebugLogException(nameof(Connect), e); m_SerialPort.Close(); m_SerialPort.Dispose(); m_SerialPort = null; if (e is ArgumentException) // Incompatible Firmware { m_MessageContext.Post(x => OnFirmwareIncompatible?.Invoke(firmware), null); } } } }
private void OnDefaultDeviceChanged(object sender, DefaultDeviceChangedEventArgs e) { if (e.DataFlow != Flow.ToDataFlow()) { return; } bool newDefault = e.DeviceId == DeviceId; if (IsDefault != newDefault) { AppLogging.DebugLog(nameof(OnDefaultDeviceChanged), DeviceId, newDefault.ToString()); IsDefault = newDefault; DeviceDefaultChanged?.Invoke(this); } }
private void WriteMessage(DateTime now, Command command, IMessage message = null) { m_WriteBuffer.SetLength(0); m_WriteBuffer.WriteByte((byte)command); message?.GetBytes(m_WriteBuffer); Interlocked.Add(ref m_WriteBytes, m_WriteBuffer.Length); // GetBuffer returns a reference to the underlying array, we can still use that after we reset the position if we store the length byte[] buffer = m_WriteBuffer.GetBuffer(); int length = (int)m_WriteBuffer.Length; AppLogging.DebugLog(nameof(WriteMessage), command.ToString(), message != null ? message.ToString() : ""); try { m_SerialPort.Write(buffer, 0, length); } catch (Exception e) { AppLogging.DebugLogException(nameof(WriteMessage), e); return; } m_LastMessageWrite = now; }
/// <summary> /// Unregisters the session from the service so events /// are not responded to anymore. /// <param name="device">The device to unregister</param> private void UnregisterDevice(IAudioDevice device) { AppLogging.DebugLog(nameof(UnregisterDevice), device.DeviceId, device.DisplayName); if (_sessionManagers.ContainsKey(device.Id)) { _sessionManagers[device.Id].SessionCreated -= OnSessionCreated; _sessionManagers.Remove(device.Id); } device.DeviceDefaultChanged -= OnDefaultDeviceChanged; device.DeviceVolumeChanged -= OnDeviceVolumeChanged; device.DeviceRemoved -= OnDeviceRemoved; if (_devices.ContainsKey(device.Id)) { _devices.Remove(device.Id); RaiseDeviceRemoved(device.Id, device.Flow); } device.Dispose(); }
private void Read(DateTime now) { #if POLLING_SERIAL try { if (m_SerialPort == null || !m_SerialPort.IsOpen || m_SerialPort.BytesToRead <= 0) { return; } } catch { return; } #endif Command command; try { command = (Command)m_SerialPort.ReadByte(); } catch (Exception ex) { AppLogging.DebugLogException(nameof(Read), ex); Interlocked.Increment(ref m_ErrorCount); return; } Interlocked.Increment(ref m_ReadCount); Interlocked.Increment(ref m_ReadBytes); switch (command) { case Command.TEST: { try { var firmware = m_SerialPort.ReadLine().Replace("\r", ""); AppLogging.DebugLog(nameof(Read), command.ToString(), firmware); m_LastMessageRead = now; m_LastMessageWrite = now; } catch (Exception e) { AppLogging.DebugLogException(nameof(ReadMessage), e); Interlocked.Increment(ref m_ErrorCount); return; } } break; case Command.OK: { AppLogging.DebugLog(nameof(Read), command.ToString()); m_DeviceReady = true; m_LastMessageRead = now; m_LastMessageWrite = now; Write(m_LastMessageRead); } break; case Command.SETTINGS: ReadMessage <DeviceSettings>(now, command); break; case Command.SESSION_INFO: ReadMessage <SessionInfo>(now, command); break; case Command.CURRENT_SESSION: case Command.ALTERNATE_SESSION: case Command.PREVIOUS_SESSION: case Command.NEXT_SESSION: ReadMessage <SessionData>(now, command); break; case Command.VOLUME_CURR_CHANGE: case Command.VOLUME_ALT_CHANGE: case Command.VOLUME_PREV_CHANGE: case Command.VOLUME_NEXT_CHANGE: ReadMessage <VolumeData>(now, command); break; case Command.MODE_STATES: ReadMessage <ModeStates>(now, command); break; case Command.ERROR: case Command.NONE: case Command.DEBUG: Interlocked.Increment(ref m_ErrorCount); break; } }
private void Read(object sender, SerialDataReceivedEventArgs e) { if (e.EventType == SerialData.Eof) { return; } Command command = (Command)m_SerialPort.ReadByte(); Interlocked.Increment(ref m_ReadCount); Interlocked.Increment(ref m_ReadBytes); switch (command) { case Command.TEST: { var firmware = m_SerialPort.ReadLine().Replace("\r", ""); AppLogging.DebugLog(nameof(Read), command.ToString(), firmware); m_LastMessageRead = DateTime.Now; } break; case Command.OK: { AppLogging.DebugLog(nameof(Read), command.ToString()); m_DeviceReady = true; DateTime now = DateTime.Now; m_LastMessageRead = now; m_LastMessageWrite = now; Write(m_LastMessageRead); } break; case Command.SETTINGS: ReadMessage <DeviceSettings>(command); break; case Command.SESSION_INFO: ReadMessage <SessionInfo>(command); break; case Command.CURRENT_SESSION: case Command.ALTERNATE_SESSION: case Command.PREVIOUS_SESSION: case Command.NEXT_SESSION: ReadMessage <SessionData>(command); break; case Command.VOLUME_CURR_CHANGE: case Command.VOLUME_ALT_CHANGE: case Command.VOLUME_PREV_CHANGE: case Command.VOLUME_NEXT_CHANGE: ReadMessage <VolumeData>(command); break; case Command.ERROR: case Command.NONE: case Command.DEBUG: Interlocked.Increment(ref m_ErrorCount); break; } }