#include <pulse/error.h>
#include <pulse/simple.h>
+#include <pulse/pulseaudio.h>
#include <cstdio>
static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
return 1;
}
+void RtApiPulse::sinkInfoCallback(pa_context*, const pa_sink_info* info, int, void* arg)
+{
+ RtApiPulse* api = (RtApiPulse *) arg;
+ if (info) {
+ api->channels_ = info->sample_spec.channels;
+ }
+ pa_threaded_mainloop_signal(api->mainloop_, 0);
+}
+
+void RtApiPulse::contextStateCallback(pa_context* c, void* arg)
+{
+ pa_threaded_mainloop* mainloop = (pa_threaded_mainloop*) arg;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(mainloop, 0);
+ break;
+ default:
+ break;
+ }
+}
+
RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
{
+ /* Set up some defaults in case we crash and burn */
RtAudio::DeviceInfo info;
info.probed = true;
info.name = "PulseAudio";
info.preferredSampleRate = 48000;
info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
+ /* Get the number of output channels from pulseaudio. A simple task, you say?
+ "What is your mainloop?" */
+ mainloop_ = pa_threaded_mainloop_new();
+ if (!mainloop_) {
+ return info;
+ }
+
+ pa_threaded_mainloop_start(mainloop_);
+ pa_threaded_mainloop_lock(mainloop_);
+
+ /* "And what is your context?" */
+ pa_context* context = pa_context_new(pa_threaded_mainloop_get_api(mainloop_), "RtAudio");
+ if (!context) {
+ pa_threaded_mainloop_unlock(mainloop_);
+ pa_threaded_mainloop_stop(mainloop_);
+ pa_threaded_mainloop_free(mainloop_);
+ mainloop_ = 0;
+ return info;
+ }
+
+ pa_context_set_state_callback(context, contextStateCallback, mainloop_);
+
+ pa_context_connect(context, 0, (pa_context_flags_t) 0, 0);
+
+ /* "And what is your favourite colour?" */
+ int connected = 0;
+ pa_context_state_t state = pa_context_get_state(context);
+ for (; !connected; state = pa_context_get_state(context)) {
+ switch (state) {
+ case PA_CONTEXT_READY:
+ connected = 1;
+ continue;
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ /* Blue! No, I mean red! */
+ pa_threaded_mainloop_unlock(mainloop_);
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+ pa_threaded_mainloop_stop(mainloop_);
+ pa_threaded_mainloop_free(mainloop_);
+ mainloop_ = 0;
+ return info;
+ default:
+ pa_threaded_mainloop_wait(mainloop_);
+ break;
+ }
+ }
+
+ pa_operation* op = pa_context_get_sink_info_by_index(context, 0, sinkInfoCallback, this);
+
+ if (op) {
+ pa_operation_unref(op);
+ }
+
+ pa_threaded_mainloop_wait(mainloop_);
+ pa_threaded_mainloop_unlock(mainloop_);
+
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+
+ pa_threaded_mainloop_stop(mainloop_);
+ pa_threaded_mainloop_free(mainloop_);
+ mainloop_ = 0;
+
+ info.outputChannels = channels_;
+
return info;
}
if ( device != 0 ) return false;
if ( mode != INPUT && mode != OUTPUT ) return false;
- if ( channels != 1 && channels != 2 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";
- return false;
- }
ss.channels = channels;
if ( firstChannel != 0 ) return false;
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
+
+ static void sinkInfoCallback(pa_context* c, const pa_sink_info* info, int eol, void* arg);
+ static void contextStateCallback(pa_context* c, void* arg);
+ pa_threaded_mainloop* mainloop_;
+ int channels_;
};
#endif
#if defined(__LINUX_PULSE__)
+struct pa_context;
+struct pa_sink_info;
+struct pa_threaded_mainloop;
+
class RtApiPulse: public RtApi
{
public:
+ RtApiPulse() : mainloop_(0), channels_(2) {}
~RtApiPulse();
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
unsigned int getDeviceCount( void );