none
Custom Windows Service Accessing Audio Devices - Not working across users. RRS feed

  • Question

  • Hello, I have two users on my computer, and I want my custom service to run and play audio for each user. It basically listens for MQTT messages and processes them. I've verified that the service is processing messages when the second user signs in (visible in the event logs), however, the actual audio is not playing and there are no errors in the event log. I installed the service using the first account. It is the second account that is not working but when I installed it I installed the service on the local system - not on the local user so that should not be the issue, right?

    Imports System.Net
    Imports System.Text
    Imports uPLibrary.Networking.M2Mqtt
    Imports uPLibrary.Networking.M2Mqtt.Messages
    Imports Newtonsoft.Json
    Imports System.Runtime.InteropServices
    
    Public Enum ServiceState
        SERVICE_STOPPED = 1
        SERVICE_START_PENDING = 2
        SERVICE_STOP_PENDING = 3
        SERVICE_RUNNING = 4
        SERVICE_CONTINUE_PENDING = 5
        SERVICE_PAUSE_PENDING = 6
        SERVICE_PAUSED = 7
    End Enum
    
    <StructLayout(LayoutKind.Sequential)>
    Public Structure ServiceStatus
        Public dwServiceType As Integer
        Public dwCurrentState As ServiceState
        Public dwControlsAccepted As Integer
        Public dwWin32ExitCode As Integer
        Public dwServiceSpecificExitCode As Integer
        Public dwCheckPoint As Integer
        Public dwWaitHint As Integer
    End Structure
    
    Public Class mqttListenService
    
        Private eventLog1 As System.Diagnostics.EventLog
    
        Private _Started As Boolean = False
        Public Property Started As Boolean
            Get
                Return _Started
            End Get
            Set(value As Boolean)
                _Started = value
            End Set
        End Property
    
        Private client As MqttClient
    
        Public Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            Me.eventLog1 = New System.Diagnostics.EventLog()
            Dim sourceName As String = "MQTTListenService"
            Dim logName As String = "MQTTListenServiceLog"
            If Not (System.Diagnostics.EventLog.SourceExists(sourceName)) Then
                System.Diagnostics.EventLog.CreateEventSource(sourceName, logName)
            End If
            eventLog1.Source = sourceName
        End Sub
    
        <DllImport("advapi32.dll", SetLastError:=True)>
        Private Shared Function SetServiceStatus(ByVal handle As IntPtr, ByRef serviceStatus As ServiceStatus) As Boolean
        End Function
    
        Protected Overrides Sub OnStart(ByVal args() As String)
            ' Add code here to start your service. This method should set things
            ' in motion so your service can do its work.
    
            ' Update the service state to Start Pending.  
            Dim serviceStatus As New ServiceStatus()
            serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING
            ServiceStatus.dwWaitHint = 100000
            SetServiceStatus(Me.ServiceHandle, serviceStatus)
    
            Me.eventLog1.WriteEntry("MQTT Listen Service Started", EventLogEntryType.Information)
    
            ' the mqtt broker is the same as the node-red
            ' server.
            Dim mqqt_broker_address As String = "10.0.0.142"
            Dim device_name As String = "COMPUTER-1"
    
            ' create client instance
            Me.client = New MqttClient(IPAddress.Parse(mqqt_broker_address))
    
            ' register to message received
            AddHandler client.MqttMsgPublishReceived, AddressOf client_MqttMsgPublishReceived
    
            Dim clientId As String = Guid.NewGuid().ToString()
            client.Connect(clientId)
    
            Me.eventLog1.WriteEntry("Connected and subcribing to topic <" & device_name & ">", EventLogEntryType.Information)
            ' subscribe to the topic "/home/temperature" with QoS 2
            client.Subscribe(New String() {device_name}, New Byte() {MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE})
    
            Me.eventLog1.WriteEntry("Subscribed. Waiting for messages.", EventLogEntryType.Information)
    
            serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING
            SetServiceStatus(Me.ServiceHandle, serviceStatus)
        End Sub
    
        Protected Overrides Sub OnStop()
            ' Add code here to perform any tear-down necessary to stop your service.
    
            ' disconnect the client
            Me.client.Disconnect()
    
            ' get rid of the client in memory
            Me.client = Nothing
    
            ' log the event
            Me.eventLog1.WriteEntry("MQTT Listen Service Stopped", EventLogEntryType.Information)
        End Sub
    
        Private Sub client_MqttMsgPublishReceived(sender As Object, e As MqttMsgPublishEventArgs)
            ' handle message received
    
            ' this will have two things associated with it,
            ' command
            ' parameter
    
            Dim topic As String = e.Topic
            Dim message As String = Encoding.UTF8.GetString(e.Message)
    
            eventLog1.WriteEntry("message received topic <" & topic & "> message <" & message & ">", EventLogEntryType.Information)
    
            Dim msg_dict As Dictionary(Of String, String)
            Try
                msg_dict = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(message)
                ProcessCommand(msg_dict)
    
            Catch ex As Exception
                eventLog1.WriteEntry("message deserialization error <" & ex.Message & ">", EventLogEntryType.Error)
            End Try
        End Sub
    
        Private Sub ProcessCommand(ByVal theCommandMessage As Dictionary(Of String, String))
    
            Dim commandString As String = theCommandMessage("command")
            Dim commandParameter As String = theCommandMessage("parameter")
            Dim windows_file_path As String = commandParameter.Replace("//", "\")
    
            Select Case commandString
                Case "PLAY"
                    ' in this command the parameter should point to the location for the audio file
                    eventLog1.WriteEntry("processed command, playing audio file " & windows_file_path, EventLogEntryType.Information)
                    Try
                        My.Computer.Audio.Play(windows_file_path)
                    Catch ex As Exception
                        eventLog1.WriteEntry("audio play error " & ex.Message, EventLogEntryType.Error)
                    End Try
            End Select
    
        End Sub
    
    End Class



    neech


    • Edited by neech16 Sunday, January 7, 2018 9:33 PM
    • Moved by Hart Wang Friday, January 19, 2018 1:21 AM
    Sunday, January 7, 2018 9:32 PM

All replies

  • Hi,

    Thank you for posting here.

    Did you get other error message or exception? Did you try to debug your code?

    As far as i know that the MQTT belongs to the third product, you could consult their support website.  i will move the case to off-topic forum. 

    https://www.hivemq.com/blog/mqtt-client-library-encyclopedia-m2mqtt

    Best  Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, January 8, 2018 7:40 AM
  • Hart,

    Thanks for your reply. In digging further on this, I think it may be a result of a third party software application locking down the audio system. Probably KODI, maybe even chrome. Is there any way to do the same in the .NET framework? I want to take control back to my service when the MQTT event fires then release it when the audio is done playing.

    I am not having problems with the MQTT objects, the line of code that is/was not working is the My.Computer.Audio.Play() call.

    Thanks,


    neech

    Monday, January 8, 2018 2:44 PM
  • Hi neech16,

    Thank you for your feedback.

    i am not sure what the MQTT is, if you just use the library to fire and release event. inside .NET framework, you could use the delegate to do this.

    Events and Delegates - MSDN - Microsoft

    Best Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, January 10, 2018 8:27 AM