ds4drv
ds4drv copied to clipboard
Basic audio working. Many kinks.
This is a little nebulous. I pulled the audio processing out to another thread for performance. So there's effectively two event machines going on here over a number of threads. I could probably do with cleaning up some terminology. Suggestions?
I'm having some weird problems with Gtk where xcb is complaining about multiple threads. I'm also having an annoying issue where the write_report function isn't being called from a "main thread" for the audio, even though I'm pretty sure it's being called from a process in a way I've done before, so I can't put a timeout on the write. The write timeout is pretty important on my end for smooth audio.
I might actually start looking at pulling Gtk/gstreamer out now since they aren't playing nicely with threads.
And I do not understand why there needs gtk. Maybe better use GObject.MainLoop. And gst.Bus for catch EOS and other signal from gstreamer
Me neither. It was in the tutorials I was following and it worked. I'll check those bits out.
GObject.MainLoop is working MUCH better.
I've finally got a pure pulseaudio / sbc implementation working in C. Getting the buffering right was a real pain. I'm looking into wrapping the necessary bits and pieces for python.
@poconbhui Have a link to the C example?
@parkerlreed I've just pushed a working pulseaudio/sbc implementation. It's pretty rough and still has some debug print statements littered throughout.
Getting some of this stuff working nicely is a bit painful. Python threading and multiprocessing has a number of painful limitations so it works in Windows and Linux, which I don't really care about here. I started out trying to use the data management bits from those modules, but os.pipe does a muuuch better job than anything I could put together with them.
Another is that writing to the hidraw output on my system sometimes hangs, so I need some way of interrupting a system call. Python only allows signal/setitimer to be set on the main thread. I've managed to add a gross workaround here using the multiprocessing Pool. I've opted not to use a pure Process, since these sometimes die unexpectedly and a Pool reboots its worker thread automatically.
I think the audio timeout needs some tweaking as well. I'm not sure of the best way of getting frame time length, since the result from sbc_get_frame_duration seems to lie on my system.
I think SWIG might be overkill here too. I can probably make the pulseaudio class an opaque type and make new/start/stop/add_fd/remove_fd functions with C linkage and just wrap those with ctypes. I just used it because I've used it a number of times before. I should probably also wrap sbc.h instead of the sbc header parser I wrote from following the docs.
This should now be fully integrated with the controller's eventloop, so each controller is processing their own audio on their own thread.
I'm finding that sending other data to the controller, ie LED colour update on profile switch, causes some skipping in the audio. I think a different model of writing data to the controller might be better. I'm thinking of a constant write loop which will sync the ds4drv controller state to the controller, including LED, audio etc, instead of different events competing for bandwidth.
Ok, I think this is about it on my end as far as basic implementation goes. Could someone give this a go on their machine and tell me if it works well enough? I think the timeout might still not be tight enough.
I'm sure @Ape will have plenty to say about my style and a number of bits and pieces that may need some cleaning up.
Thanks for your effort, we are actually getting audio support!
I tried using this. It runs and creates a pulse audio sink just fine, but the audio I am hearing sounds like this (no matter what I try to play): https://x.ape3000.com/projects/ds4drv/audio.mp3
Sounds like an encoding issue. I've tried fixing it there. Let me know if that worked.
It all works on my machine, so I might have some difficulty guessing what's wrong from my end...
I'll test on my end in just a second.
Ok so I have ds4drv installed from your add-audio branch. Do I just launch ds4drv in --hidraw mode and it should work or is there an argument to pass?
I just ran sudo ds4drv --hidraw (user doesn't have access to the dev entry) and I get two "Test d4drv sink" entries but neither of them plays audio to the controller.
Checked the hidraw permissions and saw they were rw for everybody. Tried without sudo and I get the same two sinks that don't output to controller. Also closing out of ds4drv via ^C doesn't clean up the sinks.
EDIT: Ok exiting cleans up one sink but not the other.
Rebooted to start fresh. Running ds4drv as user created the single sink correctly but still no audio output. I am using the Bluez method of Share + PS to connect and get the hidraw device.
... It works. I didn't realize it was only outputting to the headphone jack. :| I kept wondering why it wasn't going to the speaker, haha. Few pops here and there but overall sounds really good on a set of speakers. (Pops are probably just due to Bluetooth connection)
Sweet. Some options and tweaks still need to be added to handle audio like managing the headphone jack and volume.
Are the sinks cleaning up properly now? Are you sure you only have one instance of ds4drv with audio running?
I still need to add some stuff for reconnecting to pulseaudio if it's killed at some point.
Yeah the double sinks just seemed to be an issue with pulse running as user and ds4drv as root. All running as user works and cleans up correctly.
The current version works really well. There are just some rare pops like parkerlreed said. Clean up seems to be working for me.
Is it possible to add another sink for the controller speaker? Or is just one stream at a time?
Does this work with multiple controllers at once?
I've written it for multiple controllers, each reading from the one pulseaudio sink. I only have one controller, though, so I haven't tested it.
Using the speaker and the headphones at the same time isn't working at the moment. As it is, when we activate the speaker, only one earphone works. I think the earphones and speaker are meant to be mutually exclusive, but it could be we've just not figured out how to do both yet. What we should be doing is checking if the headphones are plugged in and setting the speaker/earphone flags and volumes as appropriate.
Has the popping been actual pops or just skips in the audio?
I think the "popping" is just very short skips that sometimes produce a popping sound.
hey i'm working on steamOS / Debian Jessie and detected that swig and libboost also should added as dependency or not ?
edit: also swig fails on x86_64-linux-gnu-gcc compile because of: 'function' in namespace 'std' does not name a template type in file: pulseaudio_sbc_stream.hh:24:18
@StalCaiRe this isn't quite finished yet, so the dependencies are still up in the air. It also still skips every now and then so it's not quite ready for prime time. It also needs some options added to set the volume etc. I have an idea or two for where to look for the skips, but haven't had the time to investigate them.
It definitely depends on boost because I used a boost::circular_buffer. I'm using swig to wrap the PulseaudioSBCStream class, but I might opt to wrap it with ctypes instead at some point since it has fewer moving parts.
I've just pushed a commit that removes the std::function dependency, since it wasn't being used anyway.
@poconbhui i realized that this is in development atm ;) i wrote my comment to help to develop this feature. Since my python and linux skills in development are not so skilled i choose to inform you and not to write own crappy code. I'll checkout the commit asap and try to figure out why the gcc compiler want to have the 'std=c++11' option which is not set
Also i must say this is an incredebile amazing work from you and i hope i can investigate and help to bring this to SteamOS and other OS
edit.: also sbc.h should be maybe packed with this version because SteamOS failed to find it easily i fixed this by adding it manually tu usr/include/sbc
edit2: if we manage to make this fully working i will try to take the code to the windows version wich is more like my skills
Check out if Jessie has sbc and sbc-dev as separate packages. The -dev might be needed for building. It comes as the one sbc package on my distro. If they are split into package and package-dev, something like pulse-dev and boost-dev might be needed for building as well.
The compiler doesn't have -std=c++11 set because I didn't put it in setup.py. My version of gcc (6.1.1) has -std=gnu++14 by default, so I missed it. Whatever is on Jessie probably has an older standard as default. I've set -std=c++98, the oldest, reasonable one that seemed to work and stripped out the c++11 only headers. Should compile fine on Jessie now... hopefully.
See the discussion with @a1ien (#76) for more information on playing audio and a simpler example if you're looking to get it working on Windows.
are you still working with Python 2.7 ? or do i need to run it in Python3.5.x Environment.
I've been working with python 3 so this branch might have some python 3 only syntax in it. It should be python 2.7 compatible when it's done and cleaned up.
I saw this :) on debian i#m searching for a way to setup python3.5 since 3.4 also have errors in multithreading and TimeoutError is a Python3.5.2 definition.
Ah... oh dear... That one piece of multithreading is vital... but TimeoutError can be changed to anything. I'll have a look at running it with python 2.7 next chance I get.
Seems like really really good work here. What needs to happen for this to get merged in?