[alsa-devel] Fwd: [Alsa-devel] Read the input of a soundcard with ALSA
Hi,
I have some problems to read the input of my soundcard using Alsa and I don't really understand how to have access to the input of my soundcard. I follow : http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latency_8c-example.htm...
# So, in my program, I have created two handles for capture and playback : char *device = "hw:0,0"; snd_output_t *output; snd_input_t *input; snd_pcm_t *phandle, *chandle;
# then I connect the phandle to the out err = snd_output_stdio_attach(&output, stdout, 0); if (..)
# Do I have to connect the chandle with the input ? # err = snd_input_stdio_attach(&input, stdin, 0);
# I open the access to PCM err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, 0) if (..) err = snd_pcm_open(&chandle, pdevice, SND_PCM_STREAM_CAPTURE, 0) if(..)
# Hardware and software Parameters ## Hardware Parameters snd_pcm_hw_params; int err;
err = snd_pcm_hw_params_any(phandle, params); if(..); err = snd_pcm_hw_params_set_access(phandle, params,SND_PCM_ACCESS_RW_INTERLEAVED); if(..); err = snd_pcm_hw_params_set_format(phandle, params,SND_PCM_FORMAT_S16); if(..); err = snd_pcm_hw_params_set_channels(phandle, params, 1); if(..); err = snd_pcm_hw_params_set_rate_near(phandle, params, 44100, 0); if(..); err = snd_pcm_hw_params_set_buffer_time_near(phandle, params, 500000, &dir); if(..); err = snd_pcm_hw_params_set_time_near(phandle, params, 100000, &dir), if(..); err = snd_pcm_hw_params(phandle, params);
##Software parameters err = snd_pcm_sw_params(phandle, params); if(..); err = snd_pcm_sw_params_set_start_threshold(phandle, swparams, 0x7fffffff); if(..); err = snd_pcm_sw_params_set_avail_min(phandle, swparams, 4);
# same configuration for phandle
# Link output to input and start err = snd_pcm_link(chandle, phandle); if(..); err = snd_pcm_start(chandle); if(..);
#Then I want to read my input frames_in = 0; in_max = 0; latency = 28; buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2); while (1) { r = readbuf(chandle, buffer, latency, &frames_in, &in_max)); if(..);
}
# description of the function long readbuf(snd_pcm_t *handle, char *buf, long len, size_t *frames, size_t *max) { long r; do { r = snd_pcm_readi(handle, buf, len); } while (r == -EAGAIN);
if (r > 0) { *frames += r; if ((long)*max < r) *max = r; } printf ("r = %s, len %li and buf[%d] %f \r", snd_strerror(r), len,i, buf[i]); return r; }
So I compile it and I run it, and I have $ read = Broken Pipe, len = 28 and buf[..] = 0.000
Anyone can help me to read the input of my sound card ?
Thank you
At Mon, 23 Apr 2007 16:18:30 +0200, Nyx wrote:
Hi,
I have some problems to read the input of my soundcard using Alsa and I don't really understand how to have access to the input of my soundcard. I follow : http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latency_8c-example.htm...
# So, in my program, I have created two handles for capture and playback : char *device = "hw:0,0"; snd_output_t *output; snd_input_t *input; snd_pcm_t *phandle, *chandle;
# then I connect the phandle to the out err = snd_output_stdio_attach(&output, stdout, 0); if (..)
# Do I have to connect the chandle with the input ? # err = snd_input_stdio_attach(&input, stdin, 0);
# I open the access to PCM err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, 0) if (..) err = snd_pcm_open(&chandle, pdevice, SND_PCM_STREAM_CAPTURE, 0) if(..)
# Hardware and software Parameters ## Hardware Parameters snd_pcm_hw_params; int err;
err = snd_pcm_hw_params_any(phandle, params); if(..); err = snd_pcm_hw_params_set_access(phandle, params,SND_PCM_ACCESS_RW_INTERLEAVED); if(..); err = snd_pcm_hw_params_set_format(phandle, params,SND_PCM_FORMAT_S16); if(..); err = snd_pcm_hw_params_set_channels(phandle, params, 1); if(..); err = snd_pcm_hw_params_set_rate_near(phandle, params, 44100, 0); if(..); err = snd_pcm_hw_params_set_buffer_time_near(phandle, params, 500000, &dir); if(..); err = snd_pcm_hw_params_set_time_near(phandle, params, 100000, &dir), if(..); err = snd_pcm_hw_params(phandle, params);
##Software parameters err = snd_pcm_sw_params(phandle, params); if(..); err = snd_pcm_sw_params_set_start_threshold(phandle, swparams, 0x7fffffff); if(..); err = snd_pcm_sw_params_set_avail_min(phandle, swparams, 4);
# same configuration for phandle
# Link output to input and start err = snd_pcm_link(chandle, phandle); if(..); err = snd_pcm_start(chandle); if(..);
#Then I want to read my input frames_in = 0; in_max = 0; latency = 28; buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2); while (1) { r = readbuf(chandle, buffer, latency, &frames_in, &in_max)); if(..);
}
# description of the function long readbuf(snd_pcm_t *handle, char *buf, long len, size_t *frames, size_t *max) { long r; do { r = snd_pcm_readi(handle, buf, len); } while (r == -EAGAIN);
if (r > 0) { *frames += r; if ((long)*max < r) *max = r; } printf ("r = %s, len %li and buf[%d] %f \r", snd_strerror(r), len,i, buf[i]); return r; }
So I compile it and I run it, and I have $ read = Broken Pipe, len = 28 and buf[..] = 0.000
Anyone can help me to read the input of my sound card ?
When you link both playback and capture streams and start them at the same time, then it results in buffer underrun for the playback -- unless you fill the data beforehand. snd_pcm_start() triggers _both_ streams linked together. Hence, a common technique for such full-duplex streams is to fill empty data to the playback stream beforehand, then starts.
Takashi
OK. I only want to read on the input of soundcard. So I wrote an other program easier than the first, I write the data in file, but it seems that it doesn't work...
#include <string.h> #include <stdio.h> #include <stdlib.h> #include "alsa/asoundlib.h" #include <errno.h>
unsigned int rate = 44100; unsigned int nb_channels = 2;
int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *hw_params) { int err; int dir=0; if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); }
if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } printf("Initialisation des paramètres\n");
if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); exit (1); } printf("Access card configuration\n");
if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); exit (1); }
if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &rate, &dir)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, nb_chann)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); exit (1); }
if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); exit (1); } printf("Parameters recorded\n");
//snd_pcm_hw_params_free (hw_params);
if ((err = snd_pcm_prepare (handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } return 0; }
int main(int argc, char *argv[]){ int err; int j; printf("Beginning \n"); snd_pcm_hw_params_t *hw_params_capture, *hw_params_playback; short buf[256]; FILE *file;
fichier = fopen( "/root/Desktop/Test/Audio/Capture.001", "w"); if (fichier == NULL) printf("cannot create file : %i\n", errno); else printf("file created\n");
/*Open soundcard as capture*/ snd_pcm_t *capture_handle;
if ((err = snd_pcm_open (&capture_handle, "hw:0,0", SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", argv[1], snd_strerror (err)); exit (1); }
set_hwparams(capture_handle, hw_params_capture);
for (j = 0 ; j < 256 ; j++) { if ((err = snd_pcm_readi (capture_handle, buf, 128)) < 0) printf("cherche pas\n"); putc(buf[j], file); //write in file LEFT Channel putc(buf[j+1], file); //write in file RIGHT Channel putc(0x0A, file); }
printf("Close File\n"); fclose(file); snd_pcm_close (capture_handle); return 0 ; }
What do you think about this program... ? I searched about an How-to or some help for capture on a soundcard with ALSA, but I didn't found
Thank you
OK men and women... I found how I can do this... I am a stupid man ;)
So I found here some help http://www.linuxjournal.com/article/6735
So for capture :
/* This example reads from the default PCM device and writes to standard output for 5 seconds of data. */ /* Use the newer ALSA API */ #define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main() { long loops; int rc; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; char *buffer; /* Open PCM device for recording (capture). */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* 44100 bits/second sampling rate (CD quality) */ val = 44100; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames = 32; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 4; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); loops = 5000000 / val; while (loops > 0) { loops--; rc = snd_pcm_readi(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc); } rc = write(1, buffer, size); if (rc != size) fprintf(stderr, "short write: wrote %d bytes\n", rc); } snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); return 0;
and for playback
/* This example reads standard from input and writes to the default PCM device for 5 seconds of data. */ /* Use the newer ALSA API */ #define ALSA_PCM_NEW_HW_PARAMS_API #include <alsa/asoundlib.h> int main() { long loops; int rc; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val; int dir; snd_pcm_uframes_t frames; char *buffer; /* Open PCM device for playback. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 2); /* 44100 bits/second sampling rate (CD quality) */ val = 44100; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames = 32; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 4; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); /* 5 seconds in microseconds divided by * period time */ loops = 5000000 / val; while (loops > 0) { loops--; rc = read(0, buffer, size); if (rc == 0) { fprintf(stderr, "end of file on input\n"); break; } else if (rc != size) { fprintf(stderr, "short read: read %d bytes\n", rc); } rc = snd_pcm_writei(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short write, write %d frames\n", rc); } } snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); return 0;
Thank you
K. }
}
participants (2)
-
Nyx
-
Takashi Iwai