private void DataSource_DataAcquired(object sender, DataMessageEventArgs e)
        {
            try
            {
                // lock to prevent multiple simultaneous calls to the data channel from different threads
                lock (_locker)
                {
                    _logger.Trace("Received data from the data source: {0}", e.DataMessage.DataType);

                    if (_dataChannel != null && _dataChannel.IsConnected)
                    {
                        // for some messages, we need to do some clean-up here.
                        // explanation: we use two separate sockets to transfer data: TCP and UDP.
                        // some data messages require a logical sequence, e.g. PinchComplete must always occur after the last Pinch.
                        // the problem is that for performance reasons, data messages like Pinch are sent using UDP, whereas
                        // all "Complete" messages are sent using TCP (because their delivery must be guaranteed). This can lead
                        // to the situation that Pinch messages arrive _after_ PinchComplete messages on the server side.
                        // we avoid this here by purging all queued messages of a certain kind if we are about to send a corresponding
                        // "Complete" message.
                        switch (e.DataMessage.DataType)
                        {
                            case DataType.CustomDragComplete:
                                _dataChannel.PurgeFromQueue(DataType.CustomDrag);
                                break;
                            case DataType.DragComplete:
                                _dataChannel.PurgeFromQueue(DataType.FreeDrag);
                                _dataChannel.PurgeFromQueue(DataType.HorizontalDrag);
                                _dataChannel.PurgeFromQueue(DataType.VerticalDrag);
                                break;
                            case DataType.PinchComplete:
                                _dataChannel.PurgeFromQueue(DataType.Pinch);
                                break;
                        }

                        // now actually send the message
                        _dataChannel.Send(e.DataMessage);
                    }
                }
            }
            catch (Exception ex)
            {
                State = PhoneControllerState.Error;
                RaiseErrorEvent("Error while processing and sending acquired data: " + ex.Message, ex);
            }
        }
        private void DataChannel_DataMessageReceived(object sender, DataMessageEventArgs e)
        {
            // do not report data if we are not ready
            // (e.g. data may still drop in if the client version does not match the
            // expected version and we've transitioned to Error state already,
            // and until the consumer of the library does something like shutting down).
            if (State != PhoneControllerState.Ready)
            {
                return;
            }

            _logger.Trace("Received DataMessageReceived event from data channel");

            // check if we have a controller info data message
            if (e.DataMessage.DataType == DataType.ControllerInfo)
            {
                // make sure that the version information fits what we expect
                var controllerInfoData = e.DataMessage as ControllerInfoData;
                if (controllerInfoData.ClientVersion != Constants.ControllerVersion)
                {
                    _logger.Trace("Client controller version {0} does not match expected version {1}.", controllerInfoData.ClientVersion, Constants.ControllerVersion);

                    State = PhoneControllerState.Error;
                    var error = new ControllerVersionMismatchException(Constants.ControllerVersion, controllerInfoData.ClientVersion);
                    RaiseErrorEvent(error);
                    return;
                }
            }

            // simply pass through
            RaiseDataMessageReceivedEvent(e.DataMessage);
        }