static bool_t pulse_init (void) { if (! pulse_open (FMT_S16_NE, 44100, 2)) return FALSE; pulse_close (); return TRUE; }
/* OpenAL */ static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name) { const char *pulse_name = NULL; pa_stream_flags_t flags; pa_sample_spec spec; pulse_data *data; pa_operation *o; if(device_name) { ALuint i; if(!allDevNameMap) probe_devices(AL_FALSE); for(i = 0;i < numDevNames;i++) { if(strcmp(device_name, allDevNameMap[i].name) == 0) { pulse_name = allDevNameMap[i].device_name; break; } } if(i == numDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); 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; data->stream = connect_playback_stream(pulse_name, data->loop, data->context, flags, NULL, &spec, NULL); if(!data->stream) { pa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_INVALID_VALUE; } data->device_name = strdup(pa_stream_get_device_name(data->stream)); o = pa_context_get_sink_info_by_name(data->context, data->device_name, sink_name_callback, device); WAIT_FOR_OPERATION(o, data->loop); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; }
void wave_terminate() { ENTER("wave_terminate"); // Pa_Terminate(); int a_status; pthread_mutex_t* a_mutex = NULL; a_mutex = &pulse_mutex; a_status = pthread_mutex_lock(a_mutex); pulse_close(); SHOW_TIME("unlock mutex"); a_status = pthread_mutex_unlock(a_mutex); pthread_mutex_destroy(a_mutex); }
static int pulse_open() { ENTER(__FUNCTION__); pa_sample_spec ss; pa_operation *o = NULL; int success; int ret = PULSE_ERROR; assert(!mainloop); assert(!context); assert(!stream); assert(!connected); pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); ss.format = ESPEAK_FORMAT; ss.rate = wave_samplerate; ss.channels = ESPEAK_CHANNEL; if (!pa_sample_spec_valid(&ss)) return false; SHOW_TIME("pa_threaded_mainloop_new (call)"); if (!(mainloop = pa_threaded_mainloop_new())) { SHOW("Failed to allocate main loop\n",""); goto fail; } pa_threaded_mainloop_lock(mainloop); SHOW_TIME("pa_context_new (call)"); if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak"))) { SHOW("Failed to allocate context\n",""); goto unlock_and_fail; } pa_context_set_state_callback(context, context_state_cb, NULL); pa_context_set_subscribe_callback(context, subscribe_cb, NULL); SHOW_TIME("pa_context_connect (call)"); if (pa_context_connect(context, NULL, (pa_context_flags_t)0, NULL) < 0) { SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); ret = PULSE_NO_CONNECTION; goto unlock_and_fail; } SHOW_TIME("pa_threaded_mainloop_start (call)"); if (pa_threaded_mainloop_start(mainloop) < 0) { SHOW("Failed to start main loop",""); goto unlock_and_fail; } /* Wait until the context is ready */ SHOW_TIME("pa_threaded_mainloop_wait"); pa_threaded_mainloop_wait(mainloop); if (pa_context_get_state(context) != PA_CONTEXT_READY) { SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); ret = PULSE_NO_CONNECTION; if (mainloop) pa_threaded_mainloop_stop(mainloop); goto unlock_and_fail; } SHOW_TIME("pa_stream_new"); if (!(stream = pa_stream_new(context, "unknown", &ss, NULL))) { SHOW("Failed to create stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_stream_set_state_callback(stream, stream_state_cb, NULL); pa_stream_set_write_callback(stream, stream_request_cb, NULL); pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); pa_buffer_attr a_attr; a_attr.maxlength = MAXLENGTH; a_attr.tlength = TLENGTH; a_attr.prebuf = PREBUF; a_attr.minreq = MINREQ; a_attr.fragsize = 0; SHOW_TIME("pa_connect_playback"); if (pa_stream_connect_playback(stream, NULL, &a_attr, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL) < 0) { SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Wait until the stream is ready */ SHOW_TIME("pa_threaded_mainloop_wait"); pa_threaded_mainloop_wait(mainloop); if (pa_stream_get_state(stream) != PA_STREAM_READY) { SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Now subscribe to events */ SHOW_TIME("pa_context_subscribe"); if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) { SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } success = 0; SHOW_TIME("pa_threaded_mainloop_wait"); while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } pa_operation_unref(o); if (!success) { SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } do_trigger = 0; written = 0; time_offset_msec = 0; just_flushed = 0; connected = 1; pa_threaded_mainloop_unlock(mainloop); SHOW_TIME("pulse_open (ret true)"); return PULSE_OK; unlock_and_fail: if (o) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); fail: // pulse_close(); if (ret == PULSE_NO_CONNECTION) { if (context) { SHOW_TIME("pa_context_disconnect (call)"); pa_context_disconnect(context); pa_context_unref(context); context = NULL; } if (mainloop) { SHOW_TIME("pa_threaded_mainloop_free (call)"); pa_threaded_mainloop_free(mainloop); mainloop = NULL; } } else { pulse_close(); } SHOW_TIME("pulse_open (ret false)"); return ret; }
static void pulse_close_playback(ALCdevice *device) //{{{ { pulse_close(device); } //}}}
// OpenAL {{{ static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{ { char *pulse_name = NULL; pa_sample_spec spec; pulse_data *data; if(!allDevNameMap) probe_devices(AL_FALSE); if(!device_name) device_name = pulse_device; else if(strcmp(device_name, pulse_device) != 0) { ALuint i; for(i = 0;i < numDevNames;i++) { if(strcmp(device_name, allDevNameMap[i].name) == 0) { pulse_name = allDevNameMap[i].device_name; break; } } if(i == numDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device, device_name) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; data->device_name = pulse_name; pa_stream *stream = connect_playback_stream(device, 0, NULL, &spec, NULL); if(!stream) { pa_threaded_mainloop_unlock(data->loop); goto fail; } if(pa_stream_is_suspended(stream)) { ERR("Device is suspended\n"); pa_stream_disconnect(stream); pa_stream_unref(stream); pa_threaded_mainloop_unlock(data->loop); goto fail; } data->device_name = strdup(pa_stream_get_device_name(stream)); pa_stream_disconnect(stream); pa_stream_unref(stream); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; fail: pulse_close(device); return ALC_INVALID_VALUE; } //}}}
static void pulse_close_capture(ALCdevice *device) //{{{ { pulse_close(device); } //}}}
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{ { char *pulse_name = NULL; pulse_data *data; pa_stream_flags_t flags = 0; pa_stream_state_t state; pa_channel_map chanmap; if(!allCaptureDevNameMap) probe_devices(AL_TRUE); if(!device_name) device_name = pulse_device; else if(strcmp(device_name, pulse_device) != 0) { ALuint i; for(i = 0;i < numCaptureDevNames;i++) { if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if(i == numCaptureDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device, device_name) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); data->samples = maxu(data->samples, 100 * device->Frequency / 1000); if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples))) { pa_threaded_mainloop_unlock(data->loop); goto fail; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = data->samples * data->frame_size; data->attr.tlength = -1; data->attr.fragsize = minu(data->samples, 50*device->Frequency/1000) * data->frame_size; data->spec.rate = device->Frequency; data->spec.channels = ChannelsFromDevFmt(device->FmtChans); switch(device->FmtType) { case DevFmtUByte: data->spec.format = PA_SAMPLE_U8; break; case DevFmtShort: data->spec.format = PA_SAMPLE_S16NE; break; case DevFmtFloat: data->spec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: ERR("Capture format type %#x capture not supported on PulseAudio\n", device->FmtType); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(pa_sample_spec_valid(&data->spec) == 0) { ERR("Invalid sample format\n"); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) { ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); pa_threaded_mainloop_unlock(data->loop); goto fail; } data->stream = pa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap); if(!data->stream) { ERR("pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(data->context))); pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_stream_set_state_callback(data->stream, stream_state_callback, data->loop); flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; if(pa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0) { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(data->stream); data->stream = NULL; pa_threaded_mainloop_unlock(data->loop); goto fail; } while((state=pa_stream_get_state(data->stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(data->context))); pa_stream_unref(data->stream); data->stream = NULL; pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_threaded_mainloop_wait(data->loop); } pa_stream_set_state_callback(data->stream, stream_state_callback2, device); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; fail: pulse_close(device); return ALC_INVALID_VALUE; } //}}}
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{ { pulse_data *data; pa_stream_state_t state; if(!pa_handle) return ALC_FALSE; if(!device_name) device_name = pulse_capture_device; else if(strcmp(device_name, pulse_capture_device) != 0) return ALC_FALSE; if(pulse_open(device, device_name) == ALC_FALSE) return ALC_FALSE; data = device->ExtraData; ppa_threaded_mainloop_lock(data->loop); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = aluBytesFromFormat(device->Format) * aluChannelsFromFormat(device->Format); if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples))) { ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = -1; data->attr.tlength = -1; data->attr.fragsize = data->frame_size * data->samples / 2; data->stream_name = "Capture Stream"; data->spec.rate = device->Frequency; data->spec.channels = aluChannelsFromFormat(device->Format); switch(aluBytesFromFormat(device->Format)) { case 1: data->spec.format = PA_SAMPLE_U8; break; case 2: data->spec.format = PA_SAMPLE_S16NE; break; case 4: data->spec.format = PA_SAMPLE_FLOAT32NE; break; default: AL_PRINT("Unknown format: 0x%x\n", device->Format); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } if(ppa_sample_spec_valid(&data->spec) == 0) { AL_PRINT("Invalid sample format\n"); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL); if(!data->stream) { AL_PRINT("pa_stream_new() failed: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_threaded_mainloop_unlock(data->loop); pulse_close(device); return ALC_FALSE; } if(ppa_stream_connect_record(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY) < 0) { AL_PRINT("Stream did not connect: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_stream_unref(data->stream); ppa_threaded_mainloop_unlock(data->loop); data->stream = NULL; pulse_close(device); return ALC_FALSE; } while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY) { if(!PA_STREAM_IS_GOOD(state)) { AL_PRINT("Stream did not get ready: %s\n", ppa_strerror(ppa_context_errno(data->context))); ppa_stream_unref(data->stream); ppa_threaded_mainloop_unlock(data->loop); data->stream = NULL; pulse_close(device); return ALC_FALSE; } ppa_threaded_mainloop_unlock(data->loop); Sleep(1); ppa_threaded_mainloop_lock(data->loop); } ppa_threaded_mainloop_unlock(data->loop); return ALC_TRUE; } //}}}
// OpenAL {{{ static ALCboolean pulse_open_playback( ALCdevice* device, const ALCchar* device_name ) //{{{ { char* pulse_name = NULL; pa_sample_spec spec; pulse_data* data; ALuint len; if ( !pulse_load() ) { return ALC_FALSE; } if ( !device_name ) { device_name = pulse_device; } else if ( strcmp( device_name, pulse_device ) != 0 ) { ALuint i; if ( !allDevNameMap ) { probe_devices( AL_FALSE ); } for ( i = 0; i < numDevNames; i++ ) { if ( strcmp( device_name, allDevNameMap[i].name ) == 0 ) { pulse_name = allDevNameMap[i].device_name; break; } } if ( i == numDevNames ) { return ALC_FALSE; } } if ( pulse_open( device, device_name ) == ALC_FALSE ) { return ALC_FALSE; } data = device->ExtraData; ppa_threaded_mainloop_lock( data->loop ); spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; data->device_name = pulse_name; pa_stream* stream = connect_playback_stream( device, 0, NULL, &spec, NULL ); if ( !stream ) { ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( ppa_stream_is_suspended( stream ) ) { ppa_stream_disconnect( stream ); ppa_stream_unref( stream ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->device_name = strdup( ppa_stream_get_device_name( stream ) ); ppa_stream_disconnect( stream ); ppa_stream_unref( stream ); ppa_threaded_mainloop_unlock( data->loop ); len = GetConfigValueInt( "pulse", "buffer-length", 2048 ); if ( len != 0 ) { device->UpdateSize = len; device->NumUpdates = 1; } return ALC_TRUE; fail: pulse_close( device ); return ALC_FALSE; } //}}}
static ALCboolean pulse_open_capture( ALCdevice* device, const ALCchar* device_name ) //{{{ { char* pulse_name = NULL; pulse_data* data; pa_stream_flags_t flags = 0; pa_stream_state_t state; pa_channel_map chanmap; if ( !pulse_load() ) { return ALC_FALSE; } if ( !allCaptureDevNameMap ) { probe_devices( AL_TRUE ); } if ( !device_name ) { device_name = allCaptureDevNameMap[0].name; } else { ALuint i; for ( i = 0; i < numCaptureDevNames; i++ ) { if ( strcmp( device_name, allCaptureDevNameMap[i].name ) == 0 ) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if ( i == numCaptureDevNames ) { return ALC_FALSE; } } if ( pulse_open( device, device_name ) == ALC_FALSE ) { return ALC_FALSE; } data = device->ExtraData; ppa_threaded_mainloop_lock( data->loop ); data->samples = device->UpdateSize * device->NumUpdates; data->frame_size = aluFrameSizeFromFormat( device->Format ); if ( !( data->ring = CreateRingBuffer( data->frame_size, data->samples ) ) ) { ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = data->frame_size * data->samples; data->attr.tlength = -1; data->attr.fragsize = min( data->frame_size * data->samples, 10 * device->Frequency / 1000 ); data->spec.rate = device->Frequency; data->spec.channels = aluChannelsFromFormat( device->Format ); switch ( aluBytesFromFormat( device->Format ) ) { case 1: data->spec.format = PA_SAMPLE_U8; break; case 2: data->spec.format = PA_SAMPLE_S16NE; break; case 4: data->spec.format = PA_SAMPLE_FLOAT32NE; break; default: AL_PRINT( "Unknown format: 0x%x\n", device->Format ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( ppa_sample_spec_valid( &data->spec ) == 0 ) { AL_PRINT( "Invalid sample format\n" ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } if ( !ppa_channel_map_init_auto( &chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX ) ) { AL_PRINT( "Couldn't build map for channel count (%d)!\n", data->spec.channels ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } data->stream = ppa_stream_new( data->context, "Capture Stream", &data->spec, &chanmap ); if ( !data->stream ) { AL_PRINT( "pa_stream_new() failed: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_threaded_mainloop_unlock( data->loop ); goto fail; } ppa_stream_set_state_callback( data->stream, stream_state_callback, data->loop ); flags |= PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY; if ( ppa_stream_connect_record( data->stream, pulse_name, &data->attr, flags ) < 0 ) { AL_PRINT( "Stream did not connect: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_stream_unref( data->stream ); data->stream = NULL; ppa_threaded_mainloop_unlock( data->loop ); goto fail; } while ( ( state = ppa_stream_get_state( data->stream ) ) != PA_STREAM_READY ) { if ( !PA_STREAM_IS_GOOD( state ) ) { AL_PRINT( "Stream did not get ready: %s\n", ppa_strerror( ppa_context_errno( data->context ) ) ); ppa_stream_unref( data->stream ); data->stream = NULL; ppa_threaded_mainloop_unlock( data->loop ); goto fail; } ppa_threaded_mainloop_wait( data->loop ); } ppa_stream_set_state_callback( data->stream, stream_state_callback2, device ); ppa_threaded_mainloop_unlock( data->loop ); return ALC_TRUE; fail: pulse_close( device ); return ALC_FALSE; } //}}}
static int pulse_open(int fmt, int rate, int nch) { pa_sample_spec ss; pa_operation *o = NULL; int success; assert(!mainloop); assert(!context); assert(!stream); assert(!connected); switch(fmt) { case FMT_U8: ss.format = PA_SAMPLE_U8; break; case FMT_S16_LE: ss.format = PA_SAMPLE_S16LE; break; case FMT_S16_BE: ss.format = PA_SAMPLE_S16BE; break; #ifdef PA_SAMPLE_S24_32LE case FMT_S24_LE: ss.format = PA_SAMPLE_S24_32LE; break; case FMT_S24_BE: ss.format = PA_SAMPLE_S24_32BE; break; #endif #ifdef PA_SAMPLE_S32LE case FMT_S32_LE: ss.format = PA_SAMPLE_S32LE; break; case FMT_S32_BE: ss.format = PA_SAMPLE_S32BE; break; #endif case FMT_FLOAT: ss.format = PA_SAMPLE_FLOAT32NE; break; default: return FALSE; } ss.rate = rate; ss.channels = nch; if (!pa_sample_spec_valid(&ss)) return FALSE; if (!(mainloop = pa_threaded_mainloop_new())) { ERROR ("Failed to allocate main loop"); goto fail; } pa_threaded_mainloop_lock(mainloop); if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Audacious"))) { ERROR ("Failed to allocate context"); goto unlock_and_fail; } pa_context_set_state_callback(context, context_state_cb, NULL); pa_context_set_subscribe_callback(context, subscribe_cb, NULL); if (pa_context_connect(context, NULL, 0, NULL) < 0) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (pa_threaded_mainloop_start(mainloop) < 0) { ERROR ("Failed to start main loop"); goto unlock_and_fail; } /* Wait until the context is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_context_get_state(context) != PA_CONTEXT_READY) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (!(stream = pa_stream_new(context, "Audacious", &ss, NULL))) { ERROR ("Failed to create stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_stream_set_state_callback(stream, stream_state_cb, NULL); pa_stream_set_write_callback(stream, stream_request_cb, NULL); pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); /* Connect stream with sink and default volume */ /* Buffer struct */ int aud_buffer = aud_get_int(NULL, "output_buffer_size"); size_t buffer_size = pa_usec_to_bytes(aud_buffer, &ss) * 1000; pa_buffer_attr buffer = {(uint32_t) -1, buffer_size, (uint32_t) -1, (uint32_t) -1, buffer_size}; if (pa_stream_connect_playback(stream, NULL, &buffer, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Wait until the stream is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_stream_get_state(stream) != PA_STREAM_READY) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Now subscribe to events */ if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!success) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); /* Now request the initial stream info */ if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!volume_valid) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); do_trigger = 0; written = 0; flush_time = 0; bytes_per_second = FMT_SIZEOF (fmt) * nch * rate; connected = 1; volume_time_event = NULL; pa_threaded_mainloop_unlock(mainloop); return TRUE; unlock_and_fail: if (o) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); fail: pulse_close(); return FALSE; }
static void pulse_close_playback(ALCdevice *device) { pulse_close(device); }
static void pulse_close_capture(ALCdevice *device) { pulse_close(device); }
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name) { const char *pulse_name = NULL; pa_stream_flags_t flags = 0; pa_channel_map chanmap; pulse_data *data; pa_operation *o; ALuint samples; if(device_name) { ALuint i; if(!allCaptureDevNameMap) probe_devices(AL_TRUE); for(i = 0;i < numCaptureDevNames;i++) { if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if(i == numCaptureDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); data->spec.rate = device->Frequency; data->spec.channels = ChannelsFromDevFmt(device->FmtChans); switch(device->FmtType) { case DevFmtUByte: data->spec.format = PA_SAMPLE_U8; break; case DevFmtShort: data->spec.format = PA_SAMPLE_S16NE; break; case DevFmtInt: data->spec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: data->spec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(pa_sample_spec_valid(&data->spec) == 0) { ERR("Invalid sample format\n"); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) { ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); pa_threaded_mainloop_unlock(data->loop); goto fail; } samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = samples * pa_frame_size(&data->spec); data->attr.tlength = -1; data->attr.fragsize = minu(samples, 50*device->Frequency/1000) * pa_frame_size(&data->spec); flags |= PA_STREAM_DONT_MOVE; flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; data->stream = connect_record_stream(pulse_name, data->loop, data->context, flags, &data->attr, &data->spec, &chanmap); if(!data->stream) { pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_stream_set_state_callback(data->stream, stream_state_callback2, device); data->device_name = strdup(pa_stream_get_device_name(data->stream)); o = pa_context_get_source_info_by_name(data->context, data->device_name, source_name_callback, device); WAIT_FOR_OPERATION(o, data->loop); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; fail: pulse_close(device); return ALC_INVALID_VALUE; }