[ create a new paste ] login | about

Link: http://codepad.org/BjWZOgx1    [ raw code | fork ]

C, pasted on Jul 16:
/* Test program to compare latency of different flushing methods
 * By Magnus Hjorth
 *
 * To compile: 
 *   gcc pa_flush_test.c -o pa_flush_test -Wall -O2 -lm    \
 *     `pkg-config --cflags --libs libpulse`
 *
 * History:
 *   2013-07-16, MH, First version
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <math.h>
#include <pulse/pulseaudio.h>

static void check1(void *p)
{
     if (p == NULL) { fputs("Unexpected NULL pointer\n",stderr); exit(1); }
}

static void check2(int i)
{
     if (i < 0) { fprintf(stderr,"Error: %s\n",pa_strerror(i)); exit(1); }
}

static struct termios origattr;
static void setup_term(void)
{
     int i;
     struct termios attr;
     if (isatty(0)) {
	  i = tcgetattr(0,&attr);
	  if (i < 0) { perror("tcgetattr"); exit(1); }
	  memcpy(&origattr,&attr,sizeof(origattr));
	  attr.c_lflag &= ~(ICANON|ECHO);
	  i = tcsetattr(0,TCSANOW,&attr);
	  if (i < 0) { perror("tcsetattr"); exit(1); }
     }
}

static void restore_term(void)
{
     if (isatty(0))
	  tcsetattr(0,TCSANOW,&origattr);
}

static void cx_state_cb(pa_context *c, void *userdata)
{     
     pa_context_state_t *csp = (pa_context_state_t *)userdata;
     pa_context_state_t cs;
     cs = pa_context_get_state(c);
     if (!PA_CONTEXT_IS_GOOD(cs)) {
	  fprintf(stderr,"Bad context state: %d\n",cs);
	  exit(1);
     }
     *csp = cs;
}

static void sm_state_cb(pa_stream *p, void *userdata)
{
     pa_stream_state_t smst;
     smst = pa_stream_get_state(p);
     if (!PA_STREAM_IS_GOOD(smst)) {
	  fprintf(stderr,"Bad stream state: %d\n",smst);
	  exit(1);
     }
}

static long soundpos=0;
static float ang = 0.0;

static void write_sound(pa_stream *p, size_t nbytes, int relread)
{
     void *buf;
     float *fbuf;
     size_t s,nf;
     int i;
     while (nbytes > 0) {
	  s = nbytes;
	  i = pa_stream_begin_write(p,&buf,&s);
	  check2(i);
	  fbuf = buf;
	  nf = s / 4;
	  for (i=0; i<nf; i++,soundpos++) {
	       ang += (220.0/44100.0) * 2.0 * M_PI;
	       fbuf[i] = sinf( ang );
	       if (soundpos > 2205) fbuf[i] *= 0.005;
	  }
	  i = pa_stream_write(p,fbuf,s,NULL,0,
			      relread ? PA_SEEK_RELATIVE_ON_READ : 
			      PA_SEEK_RELATIVE);
	  check2(i);
	  nbytes -= s;
     }
}

static void sm_write_cb(pa_stream *p, size_t nbytes, void *userdata)
{
     write_sound(p,nbytes,0);
}

static pa_stream *create_stream(pa_context *cx)
{
     pa_sample_spec ss={PA_SAMPLE_FLOAT32NE,44100,1};
     pa_stream *sm;
     sm = pa_stream_new(cx, "test", &ss, NULL);
     check1(sm);
     pa_stream_set_state_callback(sm,sm_state_cb,NULL);
     pa_stream_set_write_callback(sm,sm_write_cb,NULL);
     pa_stream_connect_playback(sm,NULL,NULL,0,NULL,NULL);
     return sm;
}

static void keyboard_cb(pa_mainloop_api *ea, pa_io_event *e, int fd, 
			pa_io_event_flags_t events, void *userdata)
{
     char c;
     pa_operation *op;
     pa_stream **sm = (pa_stream **)userdata;
     pa_context *ctx;
     int i;
     read(0,&c,1);
     /* printf("keyboard_cb: %c\n",c); */
     switch (c) {
     case '0':
	  soundpos = 0;
	  break;
     case '1':
	  op = pa_stream_flush(*sm, NULL, NULL);
	  pa_operation_unref(op);
	  soundpos = 0;
	  break;
     case '2':
	  soundpos = 0;
	  write_sound(*sm, 256, 1);
	  break;
     case '3':
	  ctx = pa_stream_get_context(*sm);
	  pa_stream_set_state_callback(*sm, NULL, NULL);
	  i = pa_stream_disconnect(*sm);
	  check2(i);
	  pa_stream_unref(*sm);
	  *sm = create_stream(ctx);
	  soundpos = 0;
	  break;
     };
}

int main(int argc, char **argv)
{
     pa_mainloop *ml;
     pa_mainloop_api *mlapi;
     pa_context *cx;
     int i;
     pa_context_state_t cs=PA_CONTEXT_UNCONNECTED;
     pa_stream *sm;

     setup_term();
     atexit(restore_term);

     ml = pa_mainloop_new();
     check1(ml);
     mlapi = pa_mainloop_get_api(ml);
     cx = pa_context_new(mlapi,"flushtest");
     check1(cx);
     pa_context_set_state_callback(cx, cx_state_cb, &cs);
     i = pa_context_connect(cx, NULL, 0, NULL);
     check2(i);
     while (cs != PA_CONTEXT_READY)
	  pa_mainloop_iterate(ml,1,NULL);

     sm = create_stream(cx);

     puts(" PulseAudio flush latency test");
     puts(" Keys:");
     puts("  0 = No flushing (full latency)");
     puts("  1 = pa_stream_flush");
     puts("  2 = pa_stream_write with PA_SEEK_RELATIVE_ON_READ");
     puts("  3 = disconnect/reconnect stream");
     puts("  Ctrl-C = exit");
     
     mlapi->io_new(mlapi,0,PA_IO_EVENT_INPUT,keyboard_cb,&sm);
     pa_mainloop_run(ml,NULL);

     return 0;
}


Create a new paste based on this one


Comments: