void alsamm_close_audio(void) { int i,err; #ifdef ALSAMM_DEBUG if(sys_verbose) post("closing devices"); #endif alsamm_stop(); for(i=0;i< alsa_noutdev;i++){ #ifdef ALSAMM_DEBUG if(sys_verbose) post("unlink audio out %d, of %lx",i,used_outdevice[i]); #endif if(alsa_outdev[i].a_synced != 0){ if((err = snd_pcm_unlink(alsa_outdev[i].a_handle)) < 0) check_error(err, "snd_pcm_unlink (output)"); alsa_outdev[i].a_synced = 0; } if((err = snd_pcm_close(alsa_outdev[i].a_handle)) <= 0) check_error(err, "snd_pcm_close (output)"); if(alsa_outdev[i].a_addr){ free(alsa_outdev[i].a_addr); alsa_outdev[i].a_addr = NULL; } alsa_outdev[i].a_channels = 0; } for(i=0;i< alsa_nindev;i++){ err = snd_pcm_close(alsa_indev[i].a_handle); if(sys_verbose) check_error(err, "snd_pcm_close (input)"); if(alsa_indev[i].a_addr){ free(alsa_indev[i].a_addr); alsa_indev[i].a_addr = NULL; } alsa_indev[i].a_channels = 0; } alsa_nindev = alsa_noutdev = 0; #ifdef ALSAMM_DEBUG if(sys_verbose) post("close_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns); alsamm_xruns = dac_send = 0; #endif }
/** Fills the input buffer with audio data from the microphone. * * @param data the buffer to fill with audio data * @param len the size of the buffer * @return a pointer to the filled buffer */ uint16_t VoiceStreamer::fillBuffer(char *data, int len) { int latency, bufsize, room_left = len; size_t frames_in, frames_out, in_max; ssize_t r; char *buffer, *data_ptr = data; bool done = false; latency = latency_min - 4; bufsize = (latency_max*snd_pcm_format_width(format)/8)*2; buffer = new char[bufsize]; while (!done) { while (frames_in < loop_limit) { if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0) { break; } else { if (room_left > r<<2) { memcpy(data_ptr, buffer, r<<2); data_ptr += (r<<2); room_left -= (r<<2); } else { memcpy(data_ptr, buffer, room_left); data_ptr += room_left; room_left = 0; done = true; break; } } } if (!done) { snd_pcm_drop(chandle); snd_pcm_unlink(chandle); snd_pcm_hw_free(chandle); frames_in = frames_out = in_max = 0; if (setparams_c(chandle, &latency) < 0) break; } } return uint16_t (len - room_left); }
int main(int argc, char *argv[]) { struct option long_option[] = { {"help", 0, NULL, 'h'}, {"pdevice", 1, NULL, 'P'}, {"cdevice", 1, NULL, 'C'}, {"min", 1, NULL, 'm'}, {"max", 1, NULL, 'M'}, {"frames", 1, NULL, 'F'}, {"format", 1, NULL, 'f'}, {"channels", 1, NULL, 'c'}, {"rate", 1, NULL, 'r'}, {"seconds", 1, NULL, 's'}, {"block", 0, NULL, 'b'}, {"time", 1, NULL, 't'}, {"poll", 0, NULL, 'p'}, {"effect", 0, NULL, 'e'}, {NULL, 0, NULL, 0}, }; snd_pcm_t *phandle, *chandle; char *buffer; int err, latency, morehelp; int ok; snd_timestamp_t p_tstamp, c_tstamp; ssize_t r; size_t frames_in, frames_out, in_max; int effect = 0; morehelp = 0; while (1) { int c; if ((c = getopt_long(argc, argv, "hP:C:m:M:F:f:c:r:s:bt:pe", long_option, NULL)) < 0) break; switch (c) { case 'h': morehelp++; break; case 'P': pdevice = strdup(optarg); break; case 'C': cdevice = strdup(optarg); break; case 'm': err = atoi(optarg) / 2; latency_min = err >= 4 ? err : 4; if (latency_max < latency_min) latency_max = latency_min; break; case 'M': err = atoi(optarg) / 2; latency_max = latency_min > err ? latency_min : err; break; case 'f': format = snd_pcm_format_value(optarg); if (format == SND_PCM_FORMAT_UNKNOWN) { printf("Unknown format, setting to default S16_LE\n"); format = SND_PCM_FORMAT_S16_LE; } break; case 'c': err = atoi(optarg); channels = err >= 1 && err < 1024 ? err : 1; break; case 'r': err = atoi(optarg); rate = err >= 4000 && err < 200000 ? err : 44100; break; case 's': err = atoi(optarg); loop_sec = err >= 1 && err <= 100000 ? err : 30; break; case 'b': block = 1; break; case 't': tick_time = atoi(optarg); tick_time = tick_time < 0 ? 0 : tick_time; break; case 'p': use_poll = 1; break; case 'e': effect = 1; break; } } if (morehelp) { help(); return 0; } err = snd_output_stdio_attach(&output, stdout, 0); if (err < 0) { printf("Output failed: %s\n", snd_strerror(err)); return 0; } loop_limit = loop_sec * rate; latency = latency_min - 4; buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2); setscheduler(); printf("Playback device is %s\n", pdevice); printf("Capture device is %s\n", cdevice); printf("Parameters are %iHz, %s, %i channels, %s mode\n", rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking"); printf("Wanted tick time: %ius, poll mode: %s\n", tick_time, use_poll ? "yes" : "no"); printf("Loop limit is %li frames, minimum latency = %i, maximum latency = %i\n", loop_limit, latency_min * 2, latency_max * 2); if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); return 0; } if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) { printf("Record open error: %s\n", snd_strerror(err)); return 0; } /* initialize the filter sweep variables */ if (effect) { fs = (float) rate; BW = FILTER_BANDWIDTH; lfo = 0; dlfo = 2.*M_PI*FILTERSWEEP_LFO_FREQ/fs; x[0] = (float*) malloc(channels*sizeof(float)); x[1] = (float*) malloc(channels*sizeof(float)); x[2] = (float*) malloc(channels*sizeof(float)); y[0] = (float*) malloc(channels*sizeof(float)); y[1] = (float*) malloc(channels*sizeof(float)); y[2] = (float*) malloc(channels*sizeof(float)); } while (1) { frames_in = frames_out = 0; if (setparams(phandle, chandle, &latency) < 0) break; showlatency(latency); if (tick_time_ok) printf("Using tick time %ius\n", tick_time_ok); if ((err = snd_pcm_link(chandle, phandle)) < 0) { printf("Streams link error: %s\n", snd_strerror(err)); exit(0); } if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) { fprintf(stderr, "silence error\n"); break; } if (writebuf(phandle, buffer, latency, &frames_out) < 0) { fprintf(stderr, "write error\n"); break; } if (writebuf(phandle, buffer, latency, &frames_out) < 0) { fprintf(stderr, "write error\n"); break; } if ((err = snd_pcm_start(chandle)) < 0) { printf("Go error: %s\n", snd_strerror(err)); exit(0); } gettimestamp(phandle, &p_tstamp); gettimestamp(chandle, &c_tstamp); #if 0 printf("Playback:\n"); showstat(phandle, frames_out); printf("Capture:\n"); showstat(chandle, frames_in); #endif ok = 1; in_max = 0; while (ok && frames_in < loop_limit) { if (use_poll) { /* use poll to wait for next event */ snd_pcm_wait(chandle, 1000); } if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0) ok = 0; else { if (effect) applyeffect(buffer,r); if (writebuf(phandle, buffer, r, &frames_out) < 0) ok = 0; } } if (ok) printf("Success\n"); else printf("Failure\n"); printf("Playback:\n"); showstat(phandle, frames_out); printf("Capture:\n"); showstat(chandle, frames_in); showinmax(in_max); if (p_tstamp.tv_sec == p_tstamp.tv_sec && p_tstamp.tv_usec == c_tstamp.tv_usec) printf("Hardware sync\n"); snd_pcm_drop(chandle); snd_pcm_nonblock(phandle, 0); snd_pcm_drain(phandle); snd_pcm_nonblock(phandle, !block ? 1 : 0); if (ok) { #if 1 printf("Playback time = %li.%i, Record time = %li.%i, diff = %li\n", p_tstamp.tv_sec, (int)p_tstamp.tv_usec, c_tstamp.tv_sec, (int)c_tstamp.tv_usec, timediff(p_tstamp, c_tstamp)); #endif break; } snd_pcm_unlink(chandle); snd_pcm_hw_free(phandle); snd_pcm_hw_free(chandle); } snd_pcm_close(phandle); snd_pcm_close(chandle); return 0; }
static int alsa_stream(const char *pdevice, const char *cdevice, int latency) { snd_pcm_t *phandle, *chandle; char *buffer; int err; ssize_t r; struct final_params negotiated; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; char pdevice_new[32]; err = snd_output_stdio_attach(&output, error_fp, 0); if (err < 0) { fprintf(error_fp, "alsa: Output failed: %s\n", snd_strerror(err)); return 0; } /* Open the devices */ if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n", pdevice, snd_strerror(err)); return 0; } if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { fprintf(error_fp, "alsa: Cannot open capture device %s: %s\n", cdevice, snd_strerror(err)); snd_pcm_close(phandle); return 0; } err = setparams(phandle, chandle, format, latency, 0, &negotiated); /* Try to use plughw instead, as it allows emulating speed */ if (err == 2 && strncmp(pdevice, "hw", 2) == 0) { snd_pcm_close(phandle); sprintf(pdevice_new, "plug%s", pdevice); pdevice = pdevice_new; if (verbose) fprintf(error_fp, "alsa: Trying %s for playback\n", pdevice); if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n", pdevice, snd_strerror(err)); snd_pcm_close(chandle); return 0; } err = setparams(phandle, chandle, format, latency, 1, &negotiated); } if (err != 0) { fprintf(error_fp, "alsa: setparams failed\n"); snd_pcm_close(phandle); snd_pcm_close(chandle); return 1; } buffer = malloc((negotiated.bufsize * snd_pcm_format_width(format) / 8) * negotiated.channels); if (buffer == NULL) { fprintf(error_fp, "alsa: Failed allocating buffer for audio\n"); snd_pcm_close(phandle); snd_pcm_close(chandle); return 0; } if (verbose) fprintf(error_fp, "alsa: stream started from %s to %s (%i Hz, buffer delay = %.2f ms)\n", cdevice, pdevice, negotiated.rate, negotiated.latency * 1000.0 / negotiated.rate); while (!stop_alsa) { /* We start with a read and not a wait to auto(re)start the capture */ r = readbuf(chandle, buffer, negotiated.bufsize); if (r == 0) /* Succesfully recovered from an overrun? */ continue; /* Force restart of capture stream */ if (r > 0) writebuf(phandle, buffer, r); /* use poll to wait for next event */ while (!stop_alsa && !snd_pcm_wait(chandle, 50)) ; } snd_pcm_drop(chandle); snd_pcm_drop(phandle); snd_pcm_unlink(chandle); snd_pcm_hw_free(phandle); snd_pcm_hw_free(chandle); snd_pcm_close(phandle); snd_pcm_close(chandle); return 0; }