/* Instru2Light - Illumine un instrument de musique en temps réel Copyright (C) 2012-2013 Ludovic Pouzenc This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "capture.h" #include #include #include // memcpy() #define APP_TITLE "Test 5 lpo" #define BUFSIZE 1024 extern void my_process(float *data, size_t nsamples, size_t nchan); capture_sound_level_cb_t *capture_sound_level_cb=NULL; int capture_init(pa_mainloop **m, pa_context **c); void context_state_callback(pa_context *c, void *userdata); void context_get_server_info_callback(pa_context *c, const pa_server_info*si, void *userdata); void context_get_source_info_callback(pa_context *c, const pa_source_info *si, int is_last, void *userdata); void context_get_source_info_list_callback(pa_context *c, const pa_source_info *si, int is_last, void *userdata); pa_stream * create_stream(pa_context *c, const pa_source_info *si); void stream_state_callback(pa_stream *s, void *userdata); void stream_read_callback(pa_stream *s, size_t nbytes, void *userdata); char *device_name=NULL; // Main procedure of this thread void audio_thread(void *args) { pa_context *c; pa_mainloop *m; int res, retval; capture_sound_level_cb=(capture_sound_level_cb_t *)args; //printf("debug : args==%p capture_sound_level_cb==%p\n", args, capture_sound_level_cb); res=capture_init(&m, &c); g_assert(res==0); res=pa_mainloop_run(m,&retval); g_assert(res==0); g_assert(retval==0); // pa_context_disconnect(pa_ct); pa_mainloop_free(m); } int capture_init(pa_mainloop **m, pa_context **c) { int res=0; *m=pa_mainloop_new(); g_assert(*m); *c = pa_context_new(pa_mainloop_get_api(*m), APP_TITLE); g_assert(*c); pa_context_set_state_callback(*c, context_state_callback, NULL); res=pa_context_connect(*c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); return res; } void context_state_callback(pa_context *c, void *userdata) { switch (pa_context_get_state(c)) { case PA_CONTEXT_UNCONNECTED: printf("PA_CONTEXT_UNCONNECTED\n"); break; case PA_CONTEXT_CONNECTING: printf("PA_CONTEXT_CONNECTING\n"); break; case PA_CONTEXT_AUTHORIZING: printf("PA_CONTEXT_AUTHORIZING\n"); break; case PA_CONTEXT_SETTING_NAME: printf("PA_CONTEXT_SETTING_NAME\n"); break; case PA_CONTEXT_READY: printf("PA_CONTEXT_READY\n"); // if (!device_name) { pa_operation_unref(pa_context_get_server_info(c, context_get_server_info_callback, NULL)); /* } else { pa_operation_unref(pa_context_get_source_info_by_name(c, device_name, context_get_source_info_callback, NULL)); } */ break; case PA_CONTEXT_FAILED: printf("PA_CONTEXT_FAILED\n"); break; case PA_CONTEXT_TERMINATED: printf("PA_CONTEXT_TERMINATED\n"); break; } } void context_get_server_info_callback(pa_context *c, const pa_server_info*si, void *userdata) { if (!si) { printf("Failed to get server information\n"); return; } if (!si->default_source_name) { printf("No default source set\n"); return; } //Temp : pa_operation_unref(pa_context_get_source_info_list(c,context_get_source_info_list_callback,NULL)); pa_operation_unref(pa_context_get_source_info_by_name(c, si->default_source_name, context_get_source_info_callback, NULL)); } //Temp void context_get_source_info_list_callback(pa_context *c, const pa_source_info *si, int is_last, void *userdata) { if (is_last < 0) { printf("Failed to get sink information\n"); return; } if (!si) { return; } printf("%i : '%s' (%s)\n", si->index, si->name, si->description); } void context_get_source_info_callback(pa_context *c, const pa_source_info *si, int is_last, void *userdata) { if (is_last < 0) { printf("Failed to get sink information\n"); return; } if (!si) { return; } create_stream(c,si); } pa_stream *create_stream(pa_context *c, const pa_source_info *si) { static const pa_buffer_attr ba={ //.maxlength=-1, .maxlength=-1, .tlength=1024, .prebuf=-1, .minreq=-1, .fragsize=512 }; pa_sample_spec nss = { .format = PA_SAMPLE_FLOAT32LE, .rate = si->sample_spec.rate, .channels = si->sample_spec.channels }; pa_stream *stream=NULL; //pa_proplist *pl=NULL; char t[256]; /* pa_channel_map cmap; pa_channel_map_init_mono(&cmap); //pa_channel_map_init_stereo(&cmap); */ printf("Source : %s (%s)\n", si->name, si->description); printf("Using sample format: %s\n", pa_sample_spec_snprint(t, sizeof(t), &nss)); printf("Using channel map: %s\n", pa_channel_map_snprint(t, sizeof(t), &(si->channel_map))); /* pl=pa_proplist_new(); pa_proplist_set(pl, "maxlength", &pl_maxlength, sizeof(pl_maxlength)); pa_proplist_set(pl, "tlength", &pl_tlength, sizeof(pl_tlength)); pa_proplist_set(pl, "fragsize", &pl_fragsize, sizeof(pl_fragsize)); */ stream=pa_stream_new(c, APP_TITLE, &nss, &(si->channel_map)); //stream=pa_stream_new_with_proplist(c, APP_TITLE, &(si->sample_spec), &(si->channel_map), pl); pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL); //pa_stream_connect_record(stream, APP_TITLE, NULL, (enum pa_stream_flags) 0); pa_stream_connect_record(stream, si->name, &ba, PA_STREAM_ADJUST_LATENCY); return stream; } void stream_state_callback(pa_stream *s, void *userdata) { switch (pa_stream_get_state(s)) { case PA_STREAM_UNCONNECTED: printf("PA_STREAM_UNCONNECTED\n"); break; case PA_STREAM_CREATING: printf("PA_STREAM_CREATING\n"); break; case PA_STREAM_READY: printf("PA_STREAM_READY\n"); //g_timeout_add(100, latency_func, NULL); //pa_operation_unref(pa_stream_update_timing_info(stream, stream_update_timing_info_callback, NULL)); break; case PA_STREAM_FAILED: printf("PA_STREAM_FAILED\n"); break; case PA_STREAM_TERMINATED: printf("PA_STREAM_TERMINATED\n"); break; } } void stream_read_callback(pa_stream *s, size_t bytes_new, void *userdata) { const void *pa_data=NULL; void *buf=NULL, *process_data=NULL; size_t bytes_readable, bytes_read, process_size, buf_index=0; //printf("stream_read_callback %i\n", nbytes); bytes_readable = pa_stream_readable_size(s); if (bytes_readable/sizeof(float) < 256) { // If buffer is too small for FFT analysis, wait next time printf("s"); fflush(stdout); return; } bytes_read=bytes_readable; if (pa_stream_peek(s, &pa_data, &bytes_read) < 0) { printf("pa_stream_peek() failed\n");//: %s", pa_strerror(pa_context_errno(context))); return; } assert(pa_data); assert(bytes_read>0); if (bytes_read == bytes_readable) { // If all is catched at once, no malloc, no memcpy process_data=(void *)pa_data; // FIXME : loss of const modifier is problematic process_size=bytes_read; //printf("o"); fflush(stdout); } else { // Need to concatenate buffers printf("M"); fflush(stdout); do { printf("."); fflush(stdout); if (!buf) { buf_index=0; buf = pa_xmalloc(bytes_read); } else { buf = pa_xrealloc(buf, buf_index + bytes_read); } memcpy(buf+buf_index, pa_data, bytes_read); buf_index += bytes_read; pa_stream_drop(s); if (pa_stream_peek(s, &pa_data, &bytes_read) < 0) { bytes_read=0; printf("!"); fflush(stdout); } } while (bytes_read>0); process_data=buf; process_size=buf_index; } my_process((float *)process_data, process_size/sizeof(float), pa_stream_get_sample_spec(s)->channels); if (buf) pa_xfree(buf); pa_stream_drop(s); }