X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=RtAudio.cpp;h=64b15774c8642423fffb6492eac264469b930d60;hb=9e8043f492c5c2b9456f771b8e5b2b4fdf29ed41;hp=264d5f694c2b0fd0187f6957107554280b63cfab;hpb=0668f1fc1b65ffbe752e194663b833e27a29e7c6;p=rtaudio.git diff --git a/RtAudio.cpp b/RtAudio.cpp index 264d5f6..64b1577 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -47,6 +47,7 @@ #include #include #include +#include // Static variable definitions. const unsigned int RtApi::MAX_SAMPLE_RATES = 14; @@ -3778,7 +3779,7 @@ static const char* getAsioErrorString( ASIOError result ) #include #include #include -#include +#include #ifndef MF_E_TRANSFORM_NEED_MORE_INPUT #define MF_E_TRANSFORM_NEED_MORE_INPUT _HRESULT_TYPEDEF_(0xc00d6d72) @@ -8435,6 +8436,7 @@ static void *alsaCallbackHandler( void *ptr ) #include #include +#include #include static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000, @@ -8471,8 +8473,33 @@ unsigned int RtApiPulse::getDeviceCount( void ) 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"; @@ -8488,6 +8515,72 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ ) 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; } @@ -8762,10 +8855,6 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, 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; @@ -8885,7 +8974,38 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, } break; case OUTPUT: - pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error ); + /* XXX: hard-coded for DCP-o-matic */ + pa_channel_map map; + pa_channel_map_init(&map); + /* XXX: need to check 7.1 */ + map.channels = channels; + + if (channels > 0) { + map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + } + if (channels > 1) { + map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + } + if (channels > 2) { + map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + } + if (channels > 3) { + map.map[3] = PA_CHANNEL_POSITION_LFE; + } + if (channels > 4) { + map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + } + if (channels > 5) { + map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + } + if (channels > 6) { + map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + } + if (channels > 7) { + map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + } + + pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, &map, NULL, &error ); if ( !pah->s_play ) { errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server."; goto error;