#include #include #include #define M_PI 3.14159265358979323846264338327 #define SAMPLE_RATE 48000 #define CLIP_MSEC 200 #define CLIP_SAMPLES (CLIP_MSEC * SAMPLE_RATE / 1000) #define CLIP_BYTES ((size_t) (sizeof(float) * CLIP_SAMPLES)) #define PREBUF_MSEC 400 #define PREBUF_SAMPLES (PREBUF_MSEC * SAMPLE_RATE / 1000) #define PREBUF_BYTES ((size_t) (sizeof(float) * PREBUF_SAMPLES)) #define FREQ 1000 #define PERIOD_SAMPLES (SAMPLE_RATE / FREQ) typedef struct { pa_mainloop *mainloop; pa_mainloop_api *mainloop_api; pa_stream *stream; pa_defer_event *defer_event; pa_time_event *time_event; float data[CLIP_SAMPLES]; } Thing; static void stream_drain_cb(pa_stream *stream, int success, void *userdata) { Thing *thing; printf("stream_drain_cb(success=%i)\n", success); thing = userdata; pa_mainloop_quit(thing->mainloop, 0); } static void stream_cork_cb(pa_stream *stream, int success, void *userdata) { Thing *thing; printf("stream_cork_cb(success=%i)\n", success); thing = userdata; } static void time_event_cb(pa_mainloop_api *api, pa_time_event *event, const struct timeval *timeval, void *userdata) { Thing *thing; printf("time_event_cb()\n"); thing = userdata; thing->mainloop_api->time_free(thing->time_event); thing->time_event = NULL; pa_operation_unref(pa_stream_cork(thing->stream, 0, stream_cork_cb, thing)); } static void defer_event_cb(pa_mainloop_api *api, pa_defer_event *event, void *userdata) { Thing *thing; struct timeval timeval; printf("defer_event_cb()\n"); thing = userdata; gettimeofday(&timeval, NULL); timeval.tv_sec += 10; thing->mainloop_api->defer_free(thing->defer_event); thing->defer_event = NULL; pa_operation_unref(pa_stream_drain(thing->stream, stream_drain_cb, thing)); thing->time_event = thing->mainloop_api->time_new(thing->mainloop_api, &timeval, time_event_cb, thing); } static void stream_state_cb(pa_stream *stream, void *userdata) { Thing *thing; printf("stream_state_cb()\n"); thing = userdata; if (pa_stream_get_state(stream) == PA_STREAM_READY) { pa_stream_write(stream, thing->data, CLIP_BYTES, NULL, 0, PA_SEEK_RELATIVE); printf("wrote %zu bytes\n", CLIP_BYTES); assert(!thing->defer_event); thing->defer_event = thing->mainloop_api->defer_new(thing->mainloop_api, defer_event_cb, thing); } } static void context_state_cb(pa_context *context, void *userdata) { pa_context_state_t state; Thing *thing; printf("context_state_cb()\n"); state = pa_context_get_state(context); thing = userdata; switch (state) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { pa_sample_spec spec; pa_channel_map map; pa_buffer_attr attr; spec.format = PA_SAMPLE_FLOAT32NE; spec.rate = SAMPLE_RATE; spec.channels = 1; map.channels = 1; map.map[0] = PA_CHANNEL_POSITION_MONO; attr.maxlength = -1; attr.tlength = -1; attr.prebuf = PREBUF_BYTES; attr.minreq = -1; thing->stream = pa_stream_new(context, "super solution", &spec, &map); pa_stream_set_state_callback(thing->stream, stream_state_cb, thing); pa_stream_connect_playback(thing->stream, NULL, &attr, PA_STREAM_START_CORKED, NULL, NULL); break; } case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: { printf("failed/terminated\n"); pa_mainloop_quit(thing->mainloop, 0); break; } } } int main() { Thing *thing; pa_mainloop *mainloop; pa_context *context; printf("main()\n"); thing = pa_xnew0(Thing, 1); for (int i = 0; i < CLIP_SAMPLES; i++) { thing->data[i] = cosf(i * M_PI/PERIOD_SAMPLES); //printf("%i %.2f\n", i, thing->data[i]); } thing->mainloop = pa_mainloop_new(); thing->mainloop_api = pa_mainloop_get_api(thing->mainloop); context = pa_context_new(thing->mainloop_api, NULL); pa_context_set_state_callback(context, context_state_cb, thing); pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); pa_mainloop_run(thing->mainloop, NULL); pa_context_unref(context); pa_mainloop_free(thing->mainloop); if (thing->time_event) thing->mainloop_api->time_free(thing->time_event); if (thing->defer_event) thing->mainloop_api->defer_free(thing->defer_event); if (thing->stream) pa_stream_unref(thing->stream); pa_xfree(thing); return EXIT_SUCCESS; }