-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add libsoundio audio backend #2339
Conversation
😄 |
@tresf do you know where the source is to tobydox's mingw ppa? |
No, I've never witnessed it. Here's a convo I had with him in November 2014
He's quite nonchalant, but AFAIK, he does some specific things to get it all working including providing PPAs for both Ubuntu 12.04 and 14.04. The good part is that he promises to keep maintaining them, so tagging him should be enough. |
@tobydox want to add libsoundio to your mingw PPA? It should be very easy since the official Windows binaries of libsoundio are compiled with mingw, and it has no dependencies. |
Linux travis checks are passing now. To pass the remaining checks we need:
|
Alright, I went ahead and disabled libsoundio in the travis build for macos and windows. Once libsoundio becomes available in those target environments we can re-enable travis testing for it. In the mean time, the build is green, anyone want to take a look and merge? |
@andrewrk the travis builds should not be failing on any platform. If here's a log of when I attempt to compile your branch without installing libsoundio. You'll notice I don't have portaudio installed either, but previously LMMS would still compile without it. |
Ah, I see the travis tests are passing, so ignore the first part of my previous comment. The rest of it still stands though, in that default compilation of LMMS (i.e. |
f76e35c
to
12a60b7
Compare
@Wallacoloo good point. I made it build successfully without libsoundio and I reverted the changes to travis and the checks still pass. I think we're good to go now. |
@Wallacoloo are you OK with me merging this? Travis checks out and this time it's not explicitly disabling libsoundio in the travis scripts. |
@andrewrk give me some time to test it out & review the code first. I'll
try to do that today.
|
Working on building this. I'm getting linker errors when compiling libsoundio from source, related to jack:
Info:
This is on 64-bit Arch. I guess the libjack.so versioning differs from the library versioning. Do you think there's a chance you're using any deprecated APIs or something? By the way, this is a known Arch issue - the arch package for libsoundio includes a patch to explicitly disable jack support: https://aur.archlinux.org/packages/libsoundio-git/ I'm going to proceed by building without JACK support. |
FWIW Debian unstable's jackd2 package includes the jack2 commit in question. |
Oh, oops, you're trying to build with jack1. See this issue instead: andrewrk/libsoundio#11 |
@Wallacoloo re: your comment on the AUR. Is it perhaps because libsoundio uses GNUInstallDirs in CMakeLists.txt? |
@andrewrk I have no idea, unfortunately. The conventions across linux OS's are all subtly different. Anyway, lmms is working with libsoundio. Audio output works flawlessly. However, I am consistently getting a hang upon exit when using libsoundio as output, under any backend (ALSA, Pulse, Dummy). The gui closes, but lmms never actually exits. Here's a backtrace when using the Dummy libsoundio interface: https://gist.github.com/Wallacoloo/b540d0d37a94512019a7 I would guess it has to do with a thread interfacing with libsoundio not being notified to exit, or something along those lines. |
I put print statements in AudioSoundIo::~AudioSoundIo() {} and none of them got called. I think LMMS is not properly cleaning up AudioDevice objects. |
Mixer::~Mixer()
{
// ...
while( m_fifo->available() )
{
delete[] m_fifo->read(); // <--------- hangs forever
}
// this code never gets run
delete m_audioDev;
// ...
} |
Alright I think I know the problem. |
This adds libsoundio (http://libsound.io/) as an available audio backend. libsoundio supports JACK, PulseAudio, ALSA, CoreAudio, WASAPI, and a dummy backend.
12a60b7
to
f7ff96f
Compare
I made void Mixer::stopProcessing()
{
if( m_fifoWriter != NULL )
{
m_fifoWriter->finish();
m_audioDev->stopProcessing();
m_fifoWriter->wait( 1000 );
m_fifoWriter->terminate();
delete m_fifoWriter;
m_fifoWriter = NULL;
}
else
{
m_audioDev->stopProcessing();
}
} m_fifoWriter->wait( 1000 );
m_fifoWriter->terminate(); Yikes. This should be: m_fifoWriter->wait(); When I do this I discover that the fifo writer thread is not exiting for some reason. |
@Wallacoloo alright. I found and fixed the bug. It was a race condition in Mixer.cpp: --- a/src/core/Mixer.cpp
+++ b/src/core/Mixer.cpp
@@ -221,11 +221,10 @@ void Mixer::stopProcessing()
if( m_fifoWriter != NULL )
{
m_fifoWriter->finish();
- m_audioDev->stopProcessing();
- m_fifoWriter->wait( 1000 );
- m_fifoWriter->terminate();
+ m_fifoWriter->wait();
delete m_fifoWriter;
m_fifoWriter = NULL;
+ m_audioDev->stopProcessing();
}
else
{ Before, the fifo writer thread was waiting on So, to fix it, instead we first wait until the fifo writer is done, then tell the audio backend to stop processing. Have another go at the code, if you will :-) |
IF(SOUNDIO_FOUND) | ||
SET(LMMS_HAVE_SOUNDIO TRUE) | ||
SET(STATUS_SOUNDIO "OK") | ||
INCLUDE_DIRECTORIES("${SOUNDIO_INCLUDE_DIR}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how big of a deal this is, but all the other audio/midi backends configure their includes in /src/CMakeLists.txt
instead of /CMakeLists.txt
so as not to affect the building of plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first thing I tried was using PortAudio's CMake lines as a template but that lead to inability to build if the library is not installed. Instead of trying to figure out why that wasn't working, I opted to just do it how I do it in my own projects, since I know that will work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Probably not a big deal - I wouldn't sink any time into changing that then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first thing I tried was using PortAudio's CMake lines as a template but that lead to inability to build if the library is not installed. Instead of trying to figure out why that wasn't working, I opted to just do it how I do it in my own projects, since I know that will work.
In regards to the CMakeLists lines, I'll be the odd man out and say I'd prefer we keep this consistent -- speaking less about where it should be but rather on behalf of the recent cleanup efforts.
From my experience, variable scope and order of operations is what seems to cause most CMakeLists.txt
problems. At a glance, LMMS_REQUIRED_LIBS
adds ${PORTAUDIO_LIBRARIES}
to parent scope. In my experience, the PARENT_SCOPE
related issues are usually the cause of ADD_SUBDIRECTORY
headaches and this is because a local variable in cmake isn't exposed to its parent.
Anyway, happy to help. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand what you're suggesting. I basically grepped for portaudio, copied all the cmake configuration, then replaced portudio with soundio. The only difference is the cmake/modules/Find*.cmake file, which I suspect is the culprit. But I'm sure that the FindSoundIo.cmake is OK and the PortAudio one looks complicated and not how I would do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grepped for portaudio, copied all the cmake configuration, then replaced portudio with soundio
That's what I get for only reading the comments. 😄
I see now that it's a single line... INCLUDE_DIRECTORIES
. Did you clone the IF(NOT ("${PULSEAUDIO_INCLUDE_DIR}" STREQUAL ""))
logic? Because if you don't define SOUNDIO_INCLUDE_DIR
, you're better off doing an IF(WANT_SOUNDIO AND SOUNDIO_FOUND)
, right (in src/CMakeLists.txt that is)?
Edit: Hmm... I see you do define SOUNDIO_INCLUDE_DIR
in FindSoundIo.cmake
. I'm confused now too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you clone the IF(NOT ("${PULSEAUDIO_INCLUDE_DIR}" STREQUAL "")) logic?
Yes I cloned that logic too.
ConfigManager::inst()->value( "audiosoundio", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), | ||
_mixer ) | ||
{ | ||
out_successful = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to use tabs for indentation, not spaces (lmms convention).
Alright.
|
Hey, thanks for fixing those up so quickly @andrewrk. I've recompiled with libsoundio support. The original hang has been fixed, but while testing the other backends, some of them now have hangs in a similar location that weren't there before. Specifically, SDL. Set the backend to SDL (with device="", a.k.a. default), restart so changes take place, and then close lmms. For me, it hangs upon exit 2/3rds of the time. Backtrace: https://gist.github.com/Wallacoloo/0ad08ea27ee6abc9df81 Currently testing the other backends - so far, SDL seems to be an exception & the rest seem to work fine. |
Yeah, all other backends are working fine for me, though I couldn't test JACK or OSS. |
I tested JACK; it exited cleanly 3/3 times. |
I think SDL is broken in master branch, I put a print statement in sdlAudioCallback and it is never run. Either way, if the SDL backend is messed up, it's a bug in the SDL backend, not the libsoundio backend. The core fix is necessary to clean up without a race condition. |
@andrewrk SDL is working on master for me:
(/usr/local/bin/lmms is the location of my build of lmms master - I just pulled master & rebuilt about an hour ago) |
OK I think I might have spotted the bug by eyeballing it (I can't test since SDL isn't working for me). I bet that this is happening: // frames depend on the sample rate
const fpp_t frames = getNextBuffer( m_outBuf );
if( !frames )
{
m_stopped = true;
m_stopSemaphore.release();
memset( _buf, 0, _len );
return;
} Then next time the audio callback is run: if( m_stopped )
{
memset( _buf, 0, _len );
return;
} So that happens, then we call m_stopSemaphore.acquire(); Oops. too late. And checking diff --git a/include/AudioSdl.h b/include/AudioSdl.h
index ba2f09f..a5ce279 100644
--- a/include/AudioSdl.h
+++ b/include/AudioSdl.h
@@ -82,8 +82,7 @@ private:
bool m_convertEndian;
- volatile bool m_stopped;
- QSemaphore m_stopSemaphore;
+ bool m_stopped;
} ;
diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp
index 4587a61..9d16b5e 100644
--- a/src/core/audio/AudioSdl.cpp
+++ b/src/core/audio/AudioSdl.cpp
@@ -42,8 +42,7 @@ AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) :
AudioDevice( DEFAULT_CHANNELS, _mixer ),
m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ),
m_convertedBufPos( 0 ),
- m_convertEndian( false ),
- m_stopSemaphore( 1 )
+ m_convertEndian( false )
{
_success_ful = false;
@@ -78,8 +77,6 @@ AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) :
}
m_convertEndian = ( m_audioHandle.format != actual.format );
- m_stopSemaphore.acquire();
-
_success_ful = true;
}
@@ -89,7 +86,6 @@ AudioSdl::AudioSdl( bool & _success_ful, Mixer* _mixer ) :
AudioSdl::~AudioSdl()
{
stopProcessing();
- m_stopSemaphore.release();
SDL_CloseAudio();
SDL_Quit();
@@ -114,9 +110,8 @@ void AudioSdl::stopProcessing()
{
if( SDL_GetAudioStatus() == SDL_AUDIO_PLAYING )
{
- m_stopSemaphore.acquire();
-
SDL_LockAudio();
+ m_stopped = true;
SDL_PauseAudio( 1 );
SDL_UnlockAudio();
}
@@ -176,8 +171,6 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len )
const fpp_t frames = getNextBuffer( m_outBuf );
if( !frames )
{
- m_stopped = true;
- m_stopSemaphore.release();
memset( _buf, 0, _len );
return;
} Can you test it? |
I'll go ahead and test that. |
Well that patch fixes it. No deadlock & SDL output is still working reliably. Nicely done! Technically, we still need some sort of synchronization for Luckily, I think the callback is called from the SDL library, and so the compiler doesn't have enough information to avoid the read, and in the first case it doesn't make sense to reorder the But the previous code wasn't fully protected against both cases anyway. A lot of people misuse volatile. Accesses to a volatile variable cannot be optimized away and cannot be reordered with respect to eachother, but they can be reordered with respect to other memory accesses. So the callback is protected against optimization by declaring Technically, I believe we require a memory fence after each write to edit: Actually, I think locking a semaphore probably implies a memory barrier, which would mean the previous code was well-defined. |
I checked a little bit of SDL source code and on linux they use pthread mutexes, which have memory barrier semantics. So the memory barrier is when locking and unlocking and |
I hadn't realized it was a one-liner. I thought your comment on the audio-backend cmake logic was more than a single line. Don't hold up progress on my behalf, although at a glance it should work either using the original syntax, or using the |
Yes I think the CMake stuff is reasonably neat. Perhaps even more neat, if you take into account how simple FindSoundIo.cmake is. Anyway, looks like we have the go-ahead from all parties! 👍 |
For the record, we still need @tobydox to add libsoundio to his mingw ppa so Windows users can take advantage. Also I don't know how the builds are created for macos, does it use homebrew? In that case it would be nice for a volunteer to add libsoundio to homebrew (they discourage upstream maintainers from packaging their own software). |
Agreed.
Yes, but very recently via #2271. We still support MacPorts as well. @ryandesign has been our contact there, but we've no active Brew contributor AFAIK. |
FYI: libsoundio packaged and available at both https://launchpad.net/~tobydox/+archive/ubuntu/mingw-x-trusty and https://launchpad.net/~tobydox/+archive/ubuntu/mingw-x-precise as "mingw32-x-libsoundio" and "mingw64-x-libsoundio". |
@tobydox much obliged.
Updated tutorials:
mingw32-x-libgig mingw32-x-libsamplerate mingw32-x-pkgconfig \
- mingw32-x-binutils mingw32-x-gcc mingw32-x-runtime mingw32-x-libsoundio
+ mingw32-x-binutils mingw32-x-gcc mingw32-x-runtime
@@ -- @@
mingw64-x-libgig mingw64-x-libsamplerate mingw64-x-pkgconfig \
- mingw64-x-binutils mingw64-x-gcc mingw64-x-runtime
+ mingw64-x-binutils mingw64-x-gcc mingw64-x-runtime mingw64-x-libsoundio
Optional, but strongly recommended (with devel-files each):
@@ -- @@
* [libportaudio](http://www.portaudio.com/)
+ * [libsoundio](http://libsound.io/) I couldn't find a Installing all dependencies on Ubuntu 12.04 (or later) at once, run:
@@ -- @@
sudo apt-get install [...]
libxinerama-dev libxft-dev libgig-dev git
- FIXME: libsoundio-dev |
This adds libsoundio (http://libsound.io/) as an available audio
backend. libsoundio supports JACK, PulseAudio, ALSA, CoreAudio,
WASAPI, and a dummy backend.