I am trying to use Alsa library to reproduce the audio I get from my CAN FD communication, into my headphones. I don't quite understand how to properly configure Alsa's parameters, in order to be able to listen to the sound I get from the CAN FD.
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 16000; /* stream rate */
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 40000; /* ring buffer length in us */
static unsigned int period_time = 120000; /* period time in us */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
int size;
while (1) {
do {
nbytes = read(s, &frame, sizeof(struct canfd_frame));
} while (nbytes == 0);
for (x = 0; x < 64; x = x + 2) {
buffer[a] = ((uint32_t) frame.data[x] << 8)
| ((uint32_t) (frame.data[x + 1]));
a++;
}
//err=snd_pcm_writei(handle,buffer,32);
//printf("Datos = %d\n", err);
memcpy(total1 + i * 32, buffer, 32 * sizeof(uint32_t));
i++;
a = 0;
if (i == 500) {
buffer_length=16000;
ptr = total1;
while(buffer_length > 0){
err = snd_pcm_writei(handle, ptr, 16000);
printf("Datos = %d\n", err);
snd_pcm_avail_delay(handle, &availp, &delayp);
//printf("available frames =%ld delay = %ld z = %d\n", availp, delayp, z);
if (err == -EAGAIN)
continue;
if(err < 0){
err=snd_pcm_recover(handle, err, 1);
}
else{
ptr += err * channels;
buffer_length -= err;
z++;
}
if(err<0){
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
}
i = 0;
}
This is a part of my code, I don't thinks posting the whole code is worth. I don't understand which values should I give to buffer_time, period_time and how to be able to listen to what a I get through the CAN FD in real time. I am using snd_pcm_writei, inserting a buffer I fill with some samples I get from the CAN FD. I don't know which size should I give to the buffer and to the "frames" variable, another one that I don't quite understand, eventhough I have read some about it.
Any idea how should I configure my system? (buffer_time, period_time, buffer_size, frame,...) I have tried using different buffer and frame sizes, but I don't think I understand how it works properly. How can I calculate the size of the frame and buffer of the snd_pcm_writei(), in order to listen in Real Time to the audio?
Should I use two differente threads? One to create the buffer with the CAN FD information and the other one to handle the buffer and the audio output?
Thanks in advance, Ander.
I have finally managed to hear my self through the headphones. I have changed my configuration posted on my previous in order to sincronize it with the data I get from the CAN FD. I will post part of my code down here in case somebody needs an example. The most important part having to handle buffers like these is to handle the time to fill and the time to communicate it. Handling the time and configuring the Alsa parameters accordingly makes easier to handle the buffers.
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 22000; /* stream rate */
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 1000; /* ring buffer length in us */
static unsigned int period_time = 10000; /* period time in us */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
int size;
static snd_pcm_sframes_t buffer_size;
static snd_pcm_sframes_t period_size;
static snd_output_t *output = NULL;
snd_pcm_sframes_t delayp;
snd_pcm_sframes_t availp;
snd_pcm_uframes_t frames;
static void write_loop(snd_pcm_t *handle) {
uint32_t *buffer = malloc(16000 * sizeof(uint32_t));
uint32_t *total1 = malloc(16000 * sizeof(uint32_t)); // array to hold the result
while (1) {
do {
nbytes = read(s, &frame, sizeof(struct canfd_frame));
} while (nbytes == 0);
for (x = 0; x < 64;x = x + 2) {
buffer[a] = ((uint32_t) frame.data[x] << 8)
| ((uint32_t) (frame.data[x + 1]));
//buffer[a]=frame.data[x];
a++;
}
i++;
if (i == 250) {
memcpy(total1, buffer, 16000 * sizeof(uint32_t));
//printf("Address = %lu \n",(unsigned long)total1);
flag = 1;
buffer_length = 16000;
i = 0;
a = 0;
}
if (flag == 1) {
while(buffer_length > 0) {
snd_pcm_prepare(handle);
err = snd_pcm_writei(handle, total1, buffer_length);
//printf("Datos = %d\n", err);
snd_pcm_avail_delay(handle, &availp, &delayp);
//printf("available frames =%ld delay = %ld\n",availp,delayp);
if (err == -EAGAIN)
continue;
if (err < 0) {
err = snd_pcm_recover(handle, err, 1);
} else {
ptr += err * channels;
buffer_length -= err;
z++;
}
if (err < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
}
flag = 0;
}
}
}