static void probe_devices( ALboolean capture ) { pa_threaded_mainloop* loop; if ( capture == AL_FALSE ) { allDevNameMap = malloc( sizeof( DevMap ) * 1 ); allDevNameMap[0].name = strdup( "PulseAudio Default" ); allDevNameMap[0].device_name = NULL; numDevNames = 1; } else { allCaptureDevNameMap = malloc( sizeof( DevMap ) * 1 ); allCaptureDevNameMap[0].name = strdup( "PulseAudio Default" ); allCaptureDevNameMap[0].device_name = NULL; numCaptureDevNames = 1; } if ( ( loop = ppa_threaded_mainloop_new() ) && ppa_threaded_mainloop_start( loop ) >= 0 ) { pa_context* context; ppa_threaded_mainloop_lock( loop ); context = connect_context( loop ); if ( context ) { pa_operation* o; if ( capture == AL_FALSE ) { o = ppa_context_get_sink_info_list( context, sink_device_callback, loop ); } else { o = ppa_context_get_source_info_list( context, source_device_callback, loop ); } while ( ppa_operation_get_state( o ) == PA_OPERATION_RUNNING ) { ppa_threaded_mainloop_wait( loop ); } ppa_operation_unref( o ); ppa_context_disconnect( context ); ppa_context_unref( context ); } ppa_threaded_mainloop_unlock( loop ); ppa_threaded_mainloop_stop( loop ); } if ( loop ) { ppa_threaded_mainloop_free( loop ); } }
static ALCboolean pulse_open( ALCdevice* device, const ALCchar* device_name ) //{{{ { pulse_data* data = ppa_xmalloc( sizeof( pulse_data ) ); memset( data, 0, sizeof( *data ) ); if ( !( data->loop = ppa_threaded_mainloop_new() ) ) { AL_PRINT( "pa_threaded_mainloop_new() failed!\n" ); goto out; } if ( ppa_threaded_mainloop_start( data->loop ) < 0 ) { AL_PRINT( "pa_threaded_mainloop_start() failed\n" ); goto out; } ppa_threaded_mainloop_lock( data->loop ); device->ExtraData = data; data->context = connect_context( data->loop ); if ( !data->context ) { ppa_threaded_mainloop_unlock( data->loop ); goto out; } ppa_context_set_state_callback( data->context, context_state_callback2, device ); device->szDeviceName = strdup( device_name ); ppa_threaded_mainloop_unlock( data->loop ); return ALC_TRUE; out: if ( data->loop ) { ppa_threaded_mainloop_stop( data->loop ); ppa_threaded_mainloop_free( data->loop ); } device->ExtraData = NULL; ppa_xfree( data ); return ALC_FALSE; } //}}}
ALCboolean alc_pulse_init(BackendFuncs *func_list) { ALCboolean ret = ALC_FALSE; if(pulse_load()) { pa_threaded_mainloop *loop; pulse_ctx_flags = 0; if(!GetConfigValueBool("pulse", "spawn-server", 0)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_TRUE); if(context) { *func_list = pulse_funcs; ret = ALC_TRUE; /* Some libraries (Phonon, Qt) set some pulseaudio properties * through environment variables, which causes all streams in * the process to inherit them. This attempts to filter those * properties out by setting them to 0-length data. */ prop_filter = pa_proplist_new(); pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, NULL, 0); pa_proplist_set(prop_filter, "phonon.streamid", NULL, 0); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); } return ret; }
static ALCboolean pulse_open(ALCdevice *device) { pulse_data *data = pa_xmalloc(sizeof(pulse_data)); memset(data, 0, sizeof(*data)); if(!(data->loop = pa_threaded_mainloop_new())) { ERR("pa_threaded_mainloop_new() failed!\n"); goto out; } if(pa_threaded_mainloop_start(data->loop) < 0) { ERR("pa_threaded_mainloop_start() failed\n"); goto out; } pa_threaded_mainloop_lock(data->loop); device->ExtraData = data; data->context = connect_context(data->loop, AL_FALSE); if(!data->context) { pa_threaded_mainloop_unlock(data->loop); goto out; } pa_context_set_state_callback(data->context, context_state_callback2, device); pa_threaded_mainloop_unlock(data->loop); return ALC_TRUE; out: if(data->loop) { pa_threaded_mainloop_stop(data->loop); pa_threaded_mainloop_free(data->loop); } device->ExtraData = NULL; pa_xfree(data); return ALC_FALSE; }
static void probe_devices(ALboolean capture) { pa_threaded_mainloop *loop; if(capture == AL_FALSE) allDevNameMap = malloc(sizeof(DevMap) * 1); else allCaptureDevNameMap = malloc(sizeof(DevMap) * 1); if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_FALSE); if(context) { pa_operation *o; if(capture == AL_FALSE) o = pa_context_get_sink_info_list(context, sink_device_callback, loop); else o = pa_context_get_source_info_list(context, source_device_callback, loop); while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(loop); pa_operation_unref(o); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); }
static ALCboolean pulse_load(void) //{{{ { ALCboolean ret = ALC_FALSE; if(!pa_handle) { pa_threaded_mainloop *loop; #ifdef HAVE_DYNLOAD #ifdef _WIN32 #define PALIB "libpulse-0.dll" #elif defined(__APPLE__) && defined(__MACH__) #define PALIB "libpulse.0.dylib" #else #define PALIB "libpulse.so.0" #endif pa_handle = LoadLib(PALIB); if(!pa_handle) return ALC_FALSE; #define LOAD_FUNC(x) do { \ p##x = GetSymbol(pa_handle, #x); \ if(!(p##x)) { \ CloseLib(pa_handle); \ pa_handle = NULL; \ return ALC_FALSE; \ } \ } while(0) LOAD_FUNC(pa_context_unref); LOAD_FUNC(pa_sample_spec_valid); LOAD_FUNC(pa_stream_drop); LOAD_FUNC(pa_strerror); LOAD_FUNC(pa_context_get_state); LOAD_FUNC(pa_stream_get_state); LOAD_FUNC(pa_threaded_mainloop_signal); LOAD_FUNC(pa_stream_peek); LOAD_FUNC(pa_threaded_mainloop_wait); LOAD_FUNC(pa_threaded_mainloop_unlock); LOAD_FUNC(pa_threaded_mainloop_in_thread); LOAD_FUNC(pa_context_new); LOAD_FUNC(pa_threaded_mainloop_stop); LOAD_FUNC(pa_context_disconnect); LOAD_FUNC(pa_threaded_mainloop_start); LOAD_FUNC(pa_threaded_mainloop_get_api); LOAD_FUNC(pa_context_set_state_callback); LOAD_FUNC(pa_stream_write); LOAD_FUNC(pa_xfree); LOAD_FUNC(pa_stream_connect_record); LOAD_FUNC(pa_stream_connect_playback); LOAD_FUNC(pa_stream_readable_size); LOAD_FUNC(pa_stream_writable_size); LOAD_FUNC(pa_stream_cork); LOAD_FUNC(pa_stream_is_suspended); LOAD_FUNC(pa_stream_get_device_name); LOAD_FUNC(pa_path_get_filename); LOAD_FUNC(pa_get_binary_name); LOAD_FUNC(pa_threaded_mainloop_free); LOAD_FUNC(pa_context_errno); LOAD_FUNC(pa_xmalloc); LOAD_FUNC(pa_stream_unref); LOAD_FUNC(pa_threaded_mainloop_accept); LOAD_FUNC(pa_stream_set_write_callback); LOAD_FUNC(pa_threaded_mainloop_new); LOAD_FUNC(pa_context_connect); LOAD_FUNC(pa_stream_set_buffer_attr); LOAD_FUNC(pa_stream_get_buffer_attr); LOAD_FUNC(pa_stream_get_sample_spec); LOAD_FUNC(pa_stream_get_time); LOAD_FUNC(pa_stream_set_read_callback); LOAD_FUNC(pa_stream_set_state_callback); LOAD_FUNC(pa_stream_set_moved_callback); LOAD_FUNC(pa_stream_set_underflow_callback); LOAD_FUNC(pa_stream_new); LOAD_FUNC(pa_stream_disconnect); LOAD_FUNC(pa_threaded_mainloop_lock); LOAD_FUNC(pa_channel_map_init_auto); LOAD_FUNC(pa_channel_map_parse); LOAD_FUNC(pa_channel_map_snprint); LOAD_FUNC(pa_channel_map_equal); LOAD_FUNC(pa_context_get_server_info); LOAD_FUNC(pa_context_get_sink_info_by_name); LOAD_FUNC(pa_context_get_sink_info_list); LOAD_FUNC(pa_context_get_source_info_list); LOAD_FUNC(pa_operation_get_state); LOAD_FUNC(pa_operation_unref); #undef LOAD_FUNC #define LOAD_OPTIONAL_FUNC(x) do { \ p##x = GetSymbol(pa_handle, #x); \ } while(0) #if PA_CHECK_VERSION(0,9,15) LOAD_OPTIONAL_FUNC(pa_channel_map_superset); LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback); #endif #if PA_CHECK_VERSION(0,9,16) LOAD_OPTIONAL_FUNC(pa_stream_begin_write); #endif #undef LOAD_OPTIONAL_FUNC #else /* HAVE_DYNLOAD */ pa_handle = (void*)0xDEADBEEF; #endif if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_TRUE); if(context) { ret = ALC_TRUE; pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); if(!ret) { #ifdef HAVE_DYNLOAD CloseLib(pa_handle); #endif pa_handle = NULL; } } return ret; } //}}}
void alc_pulse_probe(enum DevProbe type) //{{{ { pa_threaded_mainloop *loop; ALuint i; switch(type) { case DEVICE_PROBE: if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_FALSE); if(context) { AppendDeviceList(pulse_device); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); break; case ALL_DEVICE_PROBE: for(i = 0;i < numDevNames;++i) { free(allDevNameMap[i].name); free(allDevNameMap[i].device_name); } free(allDevNameMap); allDevNameMap = NULL; numDevNames = 0; probe_devices(AL_FALSE); for(i = 0;i < numDevNames;i++) AppendAllDeviceList(allDevNameMap[i].name); break; case CAPTURE_DEVICE_PROBE: for(i = 0;i < numCaptureDevNames;++i) { free(allCaptureDevNameMap[i].name); free(allCaptureDevNameMap[i].device_name); } free(allCaptureDevNameMap); allCaptureDevNameMap = NULL; numCaptureDevNames = 0; probe_devices(AL_TRUE); for(i = 0;i < numCaptureDevNames;i++) AppendCaptureDeviceList(allCaptureDevNameMap[i].name); break; } } //}}}
static void probe_devices(ALboolean capture) { pa_threaded_mainloop *loop; if(capture == AL_FALSE) allDevNameMap = malloc(sizeof(DevMap) * 1); else allCaptureDevNameMap = malloc(sizeof(DevMap) * 1); if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_FALSE); if(context) { pa_operation *o; if(capture == AL_FALSE) { pa_stream_flags_t flags; pa_sample_spec spec; pa_stream *stream; flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; stream = connect_playback_stream(NULL, loop, context, flags, NULL, &spec, NULL); if(stream) { o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop); WAIT_FOR_OPERATION(o, loop); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; } o = pa_context_get_sink_info_list(context, sink_device_callback, loop); } else { pa_stream_flags_t flags; pa_sample_spec spec; pa_stream *stream; flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 1; stream = connect_record_stream(NULL, loop, context, flags, NULL, &spec, NULL); if(stream) { o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop); WAIT_FOR_OPERATION(o, loop); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; } o = pa_context_get_source_info_list(context, source_device_callback, loop); } WAIT_FOR_OPERATION(o, loop); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); }