labstreaminglayer / App-LabRecorder

An application for streaming one or more LSL streams to disk in XDF file format.
MIT License
124 stars 45 forks source link

Python wrapper for RemoteLabRecorder #5

Open agricolab opened 5 years ago

agricolab commented 5 years ago

I wrote python interfaces to remote control LabRecorder (i.e. the Delmenhorst Version). This is implemented a) via the LabRecorderCLI using win32com.client.Dispatch("WScript.Shell") and b) via the LabRecorderRCS with a TCP/IP client. What would be a preferred place to share them?

cboulay commented 5 years ago

I guess the win32com method is not cross-platform so I would shy away from that. Is the second cross-platform? Do you have that in a repo somewhere that I can look at?

One of the advantages of breaking out the repositories is that we have a little more freedom to add things. I think we could add a subfolder to this repo containing these types of interfaces. Would you like to make a pull request?

tstenner commented 5 years ago

What does win32com offer? If it just starts LabRecorderCLI and inputs data / reads output the subprocess is a much better option. As for b) I'm still not entirely happy because Qt only allows one-way communication so there's no good way to get the results of an action back. Also, I don't know yet what everyone wants to do - setting an output file name, starting and stopping recordings is working right now but with Chad's BIDS support and other ideas that might be coming in I suspect the current design won't hold up for long.

agricolab commented 5 years ago

Thanks for the feedback, and @tstenner's update about the limits of QT.

I fully appreciate that the remote control interfaces to LabRecorder are early beta, and likely to change. For testing purposes, and as i want to reduce point&click for my students as much as possible, i have written the code anyways. I'm fine in attempting to update the clients as development progresses. I guess i might have to get a compilation workflow set up though, or rely on you handing me over the binaries.

a) subprocess.Popen was actually my first approach. But i could not find a way to send keystroke events like {Enter} to close the process gracefully. (see also https://stackoverflow.com/questions/3531953/send-keyboard-event-using-subprocess). Terminating the subprocess lead to not saving the footer. So i used the win32com approach.

b) Regarding the TCP/IP client, it is pretty simple so far, and only implements starting and stopping and waiting for the confirmation from LabRecorder. How is the protocol to change the filename? Couldn't find it in https://github.com/labstreaminglayer/App-LabRecorder/blob/rcs/tcpinterface.cpp

For completeness: Here https://gist.github.com/agricolab/47d3126d9f150b6584d6ec8c7bc791e7 is the gist with both implementations. I tested them both using the python example streams (Fake EEG and Markers) and inspected the resulting xdf with XDFBrowser.

tstenner commented 5 years ago

I guess i might have to get a compilation workflow set up though, or rely on you handing me over the binaries.

The CI should take care of that, building labrecorder takes about a minute.

a) subprocess.Popen was actually my first approach. But i could not find a way to send keystroke events like {Enter} to close the process gracefully.

That answer's highly misleading, see https://stackoverflow.com/a/32570656 for an example. At least on my PC, p = Popen(['./test'],stdout=PIPE, stdin=PIPE, stderr=PIPE); p.communicate(b'\n') lets the process think enter was pressed.

Terminating the subprocess lead to not saving the footer.

Good catch, I've opened that in #8

How is the protocol to change the filename?

You're right, I thought I'd already implemented that but I think there should be better ways to do this (e.g. with templates with settable variables).

agricolab commented 5 years ago

Oh boy, you're right: I did p.stdin.write('b\n') but did not p.stdin.flush(). Stupid. Cool beans, anyways, that means the CLI interface is platform independent now, too. Updated the gist accordingly.

cboulay commented 5 years ago

Sorry for hijacking. I, too, will soon be interested in minimizing things-that-need-to-be-clicked. What is the latest/best version of Remote LabRecorder?

I noticed that tcpinterface.cpp is in master but empty. The one in the rcs branch seems to be missing features that @agricolab is already using, so it exists somewhere, I guess.

tstenner commented 5 years ago

I had started a prototype Qt Signals, but they are one-way only so it's practically impossible to get any feedback to commands and I haven't found a better solution yet. For a command line usage, the CLI recorder with the unintended remote control @agricolab found should be your best bet.

agricolab commented 5 years ago

just for reference, my most recent version currently lives at https://github.com/pyreiz/pyliesl/blob/master/liesl/files/labrecorder/cli_wrapper.py

cboulay commented 5 years ago

@Doug1983 put some work into making the GUI-version of RCS implementation more useful. That's now been merged into master (see #19). It's not perfect but it does the job for us and allows us to control LabRecorder from Unity.

As discussed previously, we currently have no way of knowing if the commands sent over RCS were successful. I think if someone wanted to do a Python wrapper for this then they might check names of running processes and check if the prescribed filename exists.

I suppose we should create some docs demonstrating how to use this from C#, Python, and Matlab. Wiki? README? Something else?