Пример #1
0
        public LSLStream(LSLBridgeStreamInfo streamInfo)
        {
            StreamInfo = streamInfo;
            liblsl.channel_format_t channelFormat;

            if (streamInfo.ChannelDataType == LSLBridgeDataType.FLOAT)
            {
                channelFormat = liblsl.channel_format_t.cf_float32;
            }
            else if (streamInfo.ChannelDataType == LSLBridgeDataType.DOUBLE)
            {
                channelFormat = liblsl.channel_format_t.cf_double64;
            }
            else if (streamInfo.ChannelDataType == LSLBridgeDataType.INT)
            {
                channelFormat = liblsl.channel_format_t.cf_int32;
            }
            else if (streamInfo.ChannelDataType == LSLBridgeDataType.STRING)
            {
                channelFormat = liblsl.channel_format_t.cf_string;
            }
            else
            {
                throw new InvalidOperationException("Unsupported channel data type.");
            }

            var lslStreamInfo = new liblsl.StreamInfo(streamInfo.StreamName, streamInfo.StreamType, streamInfo.ChannelCount, streamInfo.NominalSRate, channelFormat, Application.ResourceAssembly.GetName().Name);

            lslStreamInfo.desc().append_child_value("manufacturer", streamInfo.DeviceManufacturer);
            lslStreamInfo.desc().append_child_value("device", streamInfo.DeviceName);
            lslStreamInfo.desc().append_child_value("type", streamInfo.StreamType);
            var channels = lslStreamInfo.desc().append_child("channels");

            foreach (var c in streamInfo.Channels)
            {
                channels.append_child("channel")
                .append_child_value("label", c.Label)
                .append_child_value("unit", c.Unit)
                .append_child_value("type", c.Type);
            }

            OnPropertyChanged(nameof(StreamDisplayInfo));
            lslStream = new liblsl.StreamOutlet(lslStreamInfo, streamInfo.ChunkSize, streamInfo.BufferLength);
            stopWatch = new Stopwatch();
            stopWatch.Restart();
        }
Пример #2
0
        private void LSLService_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            lastMessageTime = DateTime.UtcNow;
            ValueSet message = args.Request.Message;

            if (message.TryGetValue(Constants.LSL_MESSAGE_TYPE, out object value))
            {
                string commandType = (string)value;
                switch (commandType)
                {
                case Constants.LSL_MESSAGE_TYPE_KEEP_ACTIVE:
                    return;

                case Constants.LSL_MESSAGE_TYPE_OPEN_STREAM:
                {
                    LSLBridgeStreamInfo streamInfo = JsonConvert.DeserializeObject <LSLBridgeStreamInfo>((string)message[Constants.LSL_MESSAGE_STREAM_INFO]);
                    if (streamInfo.SendSecondaryTimestamp)
                    {
                        if (streamInfo.ChannelDataType == LSLBridgeDataType.FLOAT)
                        {
                            streamInfo.Channels.Add(new LSLBridgeChannelInfo {
                                    Label = "Secondary Timestamp (Base)", Type = "timestamp", Unit = "seconds"
                                });
                            streamInfo.Channels.Add(new LSLBridgeChannelInfo {
                                    Label = "Secondary Timestamp (Remainder)", Type = "timestamp", Unit = "seconds"
                                });
                            streamInfo.ChannelCount += 2;
                        }
                        else if (streamInfo.ChannelDataType == LSLBridgeDataType.DOUBLE)
                        {
                            streamInfo.Channels.Add(new LSLBridgeChannelInfo {
                                    Label = "Secondary Timestamp", Type = "timestamp", Unit = "seconds"
                                });
                            streamInfo.ChannelCount += 1;
                        }
                    }
                    if (!streams.Any(x => x.StreamInfo.StreamName == streamInfo.StreamName))
                    {
                        streams.Add(new LSLStream(streamInfo));
                        streamCountSetter(streams.Count);
                    }
                }
                break;

                case Constants.LSL_MESSAGE_TYPE_CLOSE_STREAM:
                {
                    string streamName = (string)message[Constants.LSL_MESSAGE_STREAM_NAME];
                    var    stream     = streams.FirstOrDefault(x => x.StreamInfo.StreamName == streamName);
                    if (stream != null)
                    {
                        streams.Remove(stream);
                        stream.Dispose();
                        streamCountSetter(streams.Count);
                    }
                }
                break;

                case Constants.LSL_MESSAGE_TYPE_SEND_CHUNK:
                {
                    string streamName = (string)message[Constants.LSL_MESSAGE_STREAM_NAME];
                    var    stream     = streams.FirstOrDefault(x => x.StreamInfo.StreamName == streamName);
                    if (stream != null)
                    {
                        var streamInfo = stream.StreamInfo;

                        // Get our stream timestamps.
                        double[] nativeTimestamps = null;
                        double[] timestamps       = ((double[])message[Constants.LSL_MESSAGE_CHUNK_TIMESTAMPS]);
                        if (double.IsNegativeInfinity(timestamps[0]))         // Hack since main app can't call native lsl_local_clock().
                        {
                            nativeTimestamps = StreamHelper.GenerateLSLNativeTimestamps(streamInfo);
                            timestamps       = nativeTimestamps;
                        }

                        // Potentially add in secondary timestamps to be pushed with data chunk if we are using float/double format.
                        double[] timestamps2 = null;
                        if (streamInfo.SendSecondaryTimestamp)
                        {
                            timestamps2 = ((double[])message[Constants.LSL_MESSAGE_CHUNK_TIMESTAMPS2]);
                            if (double.IsNegativeInfinity(timestamps2[0]))         // Hack since main app can't call native lsl_local_clock().
                            {
                                timestamps2 = nativeTimestamps ?? StreamHelper.GenerateLSLNativeTimestamps(streamInfo);
                            }
                        }

                        // Get our stream data, figure out data type, get secondary timestamps if needed, and push chunk.
                        if (streamInfo.ChannelDataType == LSLBridgeDataType.FLOAT)
                        {
                            float[] data1D = (float[])message[Constants.LSL_MESSAGE_CHUNK_DATA];
                            float[,] data2D = data1D.To2DArray(streamInfo.ChunkSize, streamInfo.ChannelCount - (streamInfo.SendSecondaryTimestamp ? 2 : 0));         // Two extra channels for float timestamp, so subtract 2 from length to get actual data part.
                            stream.PushChunkLSL(data2D, timestamps, timestamps2);
                        }
                        else if (streamInfo.ChannelDataType == LSLBridgeDataType.DOUBLE)
                        {
                            double[] data1D = (double[])message[Constants.LSL_MESSAGE_CHUNK_DATA];
                            double[,] data2D = data1D.To2DArray(streamInfo.ChunkSize, streamInfo.ChannelCount - (streamInfo.SendSecondaryTimestamp ? 1 : 0));
                            stream.PushChunkLSL(data2D, timestamps, timestamps2);
                        }
                        else if (streamInfo.ChannelDataType == LSLBridgeDataType.INT)
                        {
                            int[] data1D = (int[])message[Constants.LSL_MESSAGE_CHUNK_DATA];
                            int[,] data2D = data1D.To2DArray(streamInfo.ChunkSize, streamInfo.ChannelCount);
                            stream.PushChunkLSL(data2D, timestamps);
                        }
                        else if (streamInfo.ChannelDataType == LSLBridgeDataType.STRING)
                        {
                            string[] data1D = (string[])message[Constants.LSL_MESSAGE_CHUNK_DATA];
                            string[,] data2D = data1D.To2DArray(streamInfo.ChunkSize, streamInfo.ChannelCount);
                            stream.PushChunkLSL(data2D, timestamps);
                        }

                        stream.UpdateSampleRate(timestamps.Length);
                    }
                }
                break;

                // Should not be called until application is closing.
                case Constants.LSL_MESSAGE_TYPE_CLOSE_BRIDGE:
                {
                    Log.Information("Closing LSL bridge (requested by BlueMuse).");
                    CloseBridge();
                }
                break;
                }
            }
        }