void StopNotificationSubscribeThread()
 {
     lock (this)
     {
         if (_loopingThread != IntPtr.Zero)
         {
             USBMuxInterop.CFRunLoopStop(_loopingThread);
         }
     }
 }
        void AMDeviceNotificationSubscribeLoop()
        {
            IntPtr context = IntPtr.Zero;

            try
            {
                lock (this)
                {
                    if (_loopingThread != IntPtr.Zero)
                    {
                        _logger?.LogError($"AMDeviceNotificationSubscribeLoop already running.");
                        throw new Exception("AMDeviceNotificationSubscribeLoop already running.");
                    }

                    _loopingThread = USBMuxInterop.CFRunLoopGetCurrent();
                }

                _logger?.LogTrace($"Calling AMDeviceNotificationSubscribe.");

                if (USBMuxInterop.AMDeviceNotificationSubscribe(AMDeviceNotificationCallback, 0, 0, 0, out context) != 0)
                {
                    _logger?.LogError($"Failed AMDeviceNotificationSubscribe call.");
                    throw new Exception("Failed AMDeviceNotificationSubscribe call.");
                }

                _logger?.LogTrace($"Start dispatching notifications.");
                USBMuxInterop.CFRunLoopRun();
                _logger?.LogTrace($"Stop dispatching notifications.");
            }
            catch (Exception ex)
            {
                _logger?.LogError($"Failed running subscribe loop: {ex.Message}. Disabling detection of devices connected over USB.");
            }
            finally
            {
                lock (this)
                {
                    if (_loopingThread != IntPtr.Zero)
                    {
                        _loopingThread = IntPtr.Zero;
                    }

                    DisconnectDevice();
                }

                if (context != IntPtr.Zero)
                {
                    _logger?.LogTrace($"Calling AMDeviceNotificationUnsubscribe.");
                    USBMuxInterop.AMDeviceNotificationUnsubscribe(context);
                }
            }
        }
        bool DisconnectDevice()
        {
            if (_device != IntPtr.Zero)
            {
                if (_deviceConnectionID != 0)
                {
                    USBMuxInterop.AMDeviceDisconnect(_device);
                    _logger?.LogInformation($"Successfully disconnected device, id={_deviceConnectionID}.");
                    _deviceConnectionID = 0;
                }

                _device = IntPtr.Zero;
            }

            return(true);
        }
        bool ConnectDevice(IntPtr newDevice)
        {
            if (_device != IntPtr.Zero)
            {
                return(false);
            }

            _device = newDevice;
            if (USBMuxInterop.AMDeviceConnect(_device) == 0)
            {
                _deviceConnectionID = USBMuxInterop.AMDeviceGetConnectionID(_device);
                _logger?.LogInformation($"Successfully connected new device, id={_deviceConnectionID}.");
                return(true);
            }
            else
            {
                _logger?.LogError($"Failed connecting new device.");
                return(false);
            }
        }
        void AMDeviceNotificationCallback(ref USBMuxInterop.AMDeviceNotificationCallbackInfo info)
        {
            _logger?.LogTrace($"AMDeviceNotificationInternal callback, device={info.am_device}, action={info.message}");

            try
            {
                lock (this)
                {
                    int interfaceType = USBMuxInterop.AMDeviceGetInterfaceType(info.am_device);
                    switch (info.message)
                    {
                    case USBMuxInterop.AMDeviceNotificationMessage.Connected:
                        if (interfaceType == 1 && _device == IntPtr.Zero)
                        {
                            ConnectDevice(info.am_device);
                        }
                        else if (interfaceType == 1 && _device != IntPtr.Zero)
                        {
                            _logger?.LogInformation($"Discovered new device, but one is already connected, ignoring new device.");
                        }
                        else if (interfaceType == 0)
                        {
                            _logger?.LogInformation($"Discovered new device not connected over USB, ignoring new device.");
                        }
                        break;

                    case USBMuxInterop.AMDeviceNotificationMessage.Disconnected:
                    case USBMuxInterop.AMDeviceNotificationMessage.Unsubscribed:
                        if (_device == info.am_device)
                        {
                            DisconnectDevice();
                        }
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError($"Failed AMDeviceNotificationCallback: {ex.Message}. Failed handling device={info.am_device} using action={info.message}");
            }
        }
        int ConnectTcpClientOverUSBMux()
        {
            uint   result      = 0;
            int    handle      = -1;
            ushort networkPort = (ushort)IPAddress.HostToNetworkOrder(unchecked ((short)_port));

            lock (this)
            {
                if (_deviceConnectionID == 0)
                {
                    throw new Exception($"Failed to connect device over USB, no device currently connected.");
                }

                result = USBMuxInterop.USBMuxConnectByPort(_deviceConnectionID, networkPort, out handle);
            }

            if (result != 0)
            {
                throw new Exception($"Failed to connect device over USB using connection {_deviceConnectionID} and port {_port}.");
            }

            return(handle);
        }