// PulseAudio I/O Callbacks //{{{ static void stream_write_callback( pa_stream* stream, size_t len, void* pdata ) //{{{ { ALCdevice* Device = pdata; pulse_data* data = Device->ExtraData; while ( len > 0 ) { size_t newlen = len; void* buf; pa_free_cb_t free_func = NULL; #if PA_CHECK_VERSION(0,9,16) if ( !ppa_stream_begin_write || ppa_stream_begin_write( stream, &buf, &newlen ) < 0 ) #endif { buf = ppa_xmalloc( newlen ); free_func = ppa_xfree; } aluMixData( Device, buf, newlen / data->frame_size ); ppa_stream_write( stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE ); len -= newlen; } } //}}}
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; } //}}}
static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{ { pulse_data *data = ppa_xmalloc(sizeof(pulse_data)); pa_context_state_t state; memset(data, 0, sizeof(*data)); if(ppa_get_binary_name(data->path_name, sizeof(data->path_name))) data->context_name = ppa_path_get_filename(data->path_name); else data->context_name = "OpenAL Soft"; 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 = ppa_context_new(ppa_threaded_mainloop_get_api(data->loop), data->context_name); if(!data->context) { AL_PRINT("pa_context_new() failed\n"); ppa_threaded_mainloop_unlock(data->loop); goto out; } ppa_context_set_state_callback(data->context, context_state_callback, device); if(ppa_context_connect(data->context, NULL, pulse_ctx_flags, NULL) < 0) { AL_PRINT("Context did not connect: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_context_unref(data->context); data->context = NULL; ppa_threaded_mainloop_unlock(data->loop); goto out; } while((state=ppa_context_get_state(data->context)) != PA_CONTEXT_READY) { if(!PA_CONTEXT_IS_GOOD(state)) { int err = ppa_context_errno(data->context); if(err != PA_ERR_CONNECTIONREFUSED) AL_PRINT("Context did not get ready: %s\n", ppa_strerror(err)); ppa_context_unref(data->context); data->context = NULL; ppa_threaded_mainloop_unlock(data->loop); goto out; } ppa_threaded_mainloop_wait(data->loop); } 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; } //}}}