Hi,
I'm trying to take a record stream which has been recording for some
time, and empty its buffer. I'm especially interested in causing the
return value from pa_stream_readable_size() to become 0.
I've attached a test program here which uses pa_stream_flush(). The
documentation for pa_stream_flush() says, "This discards any audio in
the buffer," but it doesn't actually seem to work for record streams.
Any hints?
Andrew
/* build with:
* $ gcc -lpulse -pthread -o main main.c
*/
#include <pulse/pulseaudio.h>
#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <poll.h>
#include <string.h>
#include <unistd.h>
#define RATE 44100
#define CH 2
static pa_mainloop *pulse_ml;
static pa_context *pulse_ctx;
static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
static pthread_t pulse_thread;
static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds,
int timeout, void *user)
{
int r;
pthread_mutex_unlock(&pulse_lock);
r = poll(ufds, nfds, timeout);
pthread_mutex_lock(&pulse_lock);
return r;
}
static void *pulse_mainloop_thread(void *user)
{
int ret;
pulse_ml = pa_mainloop_new();
if(!pulse_ml){
printf("pa_mainloop_new() failed\n");
return (void*)1;
}
pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
pthread_mutex_lock(&pulse_lock);
pthread_cond_signal(&pulse_cond);
pa_mainloop_run(pulse_ml, &ret);
pthread_mutex_unlock(&pulse_lock);
pa_mainloop_free(pulse_ml);
return (void*)(size_t)ret;
}
static void context_state_cb(pa_context *ctx, void *user)
{
pthread_cond_signal(&pulse_cond);
}
static int ready_pulse(void)
{
int err;
pa_context_state_t state;
err = pthread_create(&pulse_thread, NULL, &pulse_mainloop_thread, NULL);
if(err < 0){
printf("pthread_create: %u (%s)\n", err, strerror(err));
return 1;
}
pthread_cond_wait(&pulse_cond, &pulse_lock);
pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), "appname");
if(!pulse_ctx){
printf("pa_context_new failed\n");
return 1;
}
pa_context_set_state_callback(pulse_ctx, context_state_cb, NULL);
err = pa_context_connect(pulse_ctx, NULL, 0, NULL);
if(err < 0){
printf("pa_context_connect: %u (%s)\n", err, strerror(err));
return 1;
}
do{
pthread_cond_wait(&pulse_cond, &pulse_lock);
state = pa_context_get_state(pulse_ctx);
if(state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED){
printf("got invalid state: %u\n", state);
return 1;
}
}while(state != PA_CONTEXT_READY);
printf("pulse is ready now!\n");
return 0;
}
static void stream_state_cb(pa_stream *stream, void *user)
{
pthread_cond_signal(&pulse_cond);
}
static int ready_stream(pa_stream **out, const char *name)
{
pa_buffer_attr attr;
pa_stream *stream;
pa_sample_spec spec;
int err;
spec.format = PA_SAMPLE_FLOAT32LE;
spec.rate = RATE;
spec.channels = CH;
stream = pa_stream_new(pulse_ctx, name, &spec, NULL);
if(!stream){
printf("pa_stream_new failed\n");
return 1;
}
pa_stream_set_state_callback(stream, stream_state_cb, NULL);
err = pa_stream_connect_record(stream, NULL, NULL,
PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE);
if(err != 0){
printf("pa_stream_connect_record failed: %d\n", err);
return 1;
}
while(pa_stream_get_state(stream) == PA_STREAM_CREATING)
pthread_cond_wait(&pulse_cond, &pulse_lock);
if(pa_stream_get_state(stream) != PA_STREAM_READY){
printf("Something went wrong with the stream connecting!\n");
return 1;
}
printf("stream is ready now!\n");
*out = stream;
return 0;
}
static void get_server_info_cb(pa_context *ctx, const pa_server_info *info, void *user)
{
pa_server_info *out = user;
*out = *info;
}
static int get_default_fmt(void)
{
pa_operation *o;
pa_server_info info;
o = pa_context_get_server_info(pulse_ctx, get_server_info_cb, &info);
pthread_mutex_unlock(&pulse_lock);
while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
;
pthread_mutex_lock(&pulse_lock);
if(pa_operation_get_state(o) != PA_OPERATION_DONE){
pa_operation_unref(o);
return 1;
}
pa_operation_unref(o);
printf("format: %u\n", info.sample_spec.format);
printf("rate: %u\n", info.sample_spec.rate);
printf("channels: %u\n", info.sample_spec.channels);
return 0;
}
int main(int argc, char **argv)
{
pa_stream *stream;
pa_operation *o;
const pa_buffer_attr *attr;
size_t avail;
pthread_mutex_lock(&pulse_lock);
if(ready_pulse() != 0)
return 1;
if(get_default_fmt() != 0)
return 1;
if(ready_stream(&stream, "stream 1") != 0)
return 1;
avail = pa_stream_readable_size(stream);
printf("pre-sleep avail: %u bytes\n", avail);
pthread_mutex_unlock(&pulse_lock);
sleep(1);
pthread_mutex_lock(&pulse_lock);
o = pa_stream_cork(stream, 1, NULL, NULL);
if(!o)
printf("cork failed\n");
pthread_mutex_unlock(&pulse_lock);
while(pa_operation_get_state(o) == PA_OPERATION_RUNNING);
pthread_mutex_lock(&pulse_lock);
if(pa_operation_get_state(o) != PA_OPERATION_DONE)
printf("cork operation failed!\n");
pa_operation_unref(o);
avail = pa_stream_readable_size(stream);
printf("post-cork avail: %u bytes\n", avail);
o = pa_stream_flush(stream, NULL, NULL);
if(!o)
printf("flush failed\n");
pthread_mutex_unlock(&pulse_lock);
while(pa_operation_get_state(o) == PA_OPERATION_RUNNING);
pthread_mutex_lock(&pulse_lock);
if(pa_operation_get_state(o) != PA_OPERATION_DONE)
printf("flush operation failed!\n");
pa_operation_unref(o);
avail = pa_stream_readable_size(stream);
printf("post-flush avail: %u bytes\n", avail);
pthread_mutex_unlock(&pulse_lock);
return 0;
}
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss