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

Reply via email to