Forum Programmation.c incompréhensible - utilisation d'ALSA

Posté par .
Tags : aucun
0
27
mar.
2006
Bonjour,

je tente d'écrire un soft devant lire/écrire à partir de la carte son en utilisant ALSA. Je pars du tutoriel http://www.equalarea.com/paul/alsa-audio.html

Mon code qui pose problème est :

#include "string.h";
#include "stdio.h";
#include "stdlib.h";
#include "alsa/asoundlib.h";

int main(int argc, char *argv[]){
printf("debut\n");
snd_pcm_hw_params_t *hw_params;
int i;
int err;
int dir=0;
int rate=44100;

short buf[128];


/*ON LIT*/
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);
}
printf("1\n");

if ((err = snd_pcm_hw_params_malloc (&hw_params)) \< 0) {
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}
printf("2\n");

if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}
printf("3\n");

if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
fprintf (stderr, "cannot set access type (%s)\n",
snd_strerror (err));
exit (1);
}
printf("4\n");

if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
fprintf (stderr, "cannot set sample format (%s)\n",
snd_strerror (err));
exit (1);
}
printf("5\n");

if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, &dir)) < 0) {
fprintf (stderr, "cannot set sample rate (%s)\n",
snd_strerror (err));
exit (1);
}
printf("6\n");

if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
exit (1);
}
printf("7\n");

if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
fprintf (stderr, "cannot set parameters (%s)\n",
snd_strerror (err));
exit (1);
}
printf("8\n");

snd_pcm_hw_params_free (hw_params);

if ((err = snd_pcm_prepare (capture_handle)) < 0) {
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}
printf("9\n");

printf("10\n");

int j;
for (j = 0; j < 10; ++j) {
printf("j=%i\n",j);
printf("j=%i\n",j);
snd_pcm_readi (capture_handle, buf, 128);
printf("j=%i\n",j);
}

snd_pcm_close (capture_handle);



return 0 ;
}




à compiler avec
gcc -lasound test.c

Cela marche chez moi sur ma machine i386, mais sur mon amd64 j'ai le résutat suivant :
berti@neptune:~/tmp/prob$ ./a.out
debut
1
2
3
4
5
6
7
8
9
10
j=0
j=0
j=23003252
Segmentation fault


Ce que je n'arrive pas du tout à comprendre c'est pourquoi la valeur de "j" change dès que je fais un appel à la fonction snd_pcm_readi (capture_handle, buf, 128);

De plus si j'enlève la boucle et je copie la fonction snd_pcm_readi 10 fois, là il n'y plus de problème de segfault...

Quelqu'un a une idée ?
  • # format printf ?

    Posté par . Évalué à 2.

    essaie
    printf("j=%n\n",j);
    au lieu de
    printf("j=%i\n",j);
    • [^] # Re: format printf ?

      Posté par . Évalué à 1.

      C'est la dernière fois que je poste à 6h25.
      Oubliez le message précédent, j'ai certainement confondu un truc avec un autre, mais je ne sais même plus quoi....
  • # valgrind ou electric fence

    Posté par . Évalué à 4.

    en utilisant un de ces deux outils, peut être la solution tu trouveras.
    je ne connais pas les API de ALSA, mais en lisant rapidement:

    short buf[128];
    [...]
    snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2))
    [...]
    snd_pcm_readi (capture_handle, buf, 128);


    peux être qu'en allouant un buffer 2*plus gros ... car si la valeur de j change, c'est que la pile est corrompue (d'où l'aide que peuvent t'apporter valgrind et/ou electric fence).
    • [^] # Re: valgrind ou electric fence

      Posté par . Évalué à 1.

      J'ai pensé de même à un débordement de tampon. En lisant l'API ( http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.(...) ): dans l'exemple http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latenc(...) , snd_pcm-readi() est appelée avec un char* pour deuxième paramêtre. Or un short n'a pas la même taille qu'un char (pourtant on a sizeof(short) >= sizeof(char) (et sizeof(char) == 1), donc remplacer short par char dans ce code ne résoudra pas ce problème. Mais c'est un indice...)
      Mais il faudrait quelqu'un qui connaît mieux l'API pour savoir d'où vient le problème... Dans l'API de snd_pcm-readi(), ils parlent aussi bien de frames que de bytes.

      Si le paramètre size correspond à un nombre de bytes, alors il est préférable de définir le buffer comme un char[LEN] (ou char* avec malloc) et de passer sizeof buf (ou la longueur passée à malloc) comme troisième paramètre.

      Si le paramètre size est un nombre de frames, alors je ne sais pas, il faut voir comment ALSA définit une frame (peut-être la taille d'une frame dépend-elle de la qualité du son, i.e. bitrate ?). Pour info, un short contient au moins 16 bits (une implémentation peut avoir un short plus grand, mais ce n'est pas garanti).

      En tout cas, je suis d'accord avec ton diagnostic, c'est un simple débordement de tampon. Reste à savoir d'où il vient.

      (en passant, j'ai des gros doutes sur les lignes d'include:
      #include "string.h";

      On inclut un en-tête de la bibliothèque standard avec les crochets < > au lieu des guillemets, et on ne place pas de ; à la fin de la ligne:
      #include <string.h>

      Ca me semble étonnant qu'une telle syntaxe soit acceptée par un compilateur C, ça doit être une extension...)
      • [^] # Re: valgrind ou electric fence

        Posté par . Évalué à 0.

        Je vais regarder de coté là, je reviendrai dire quoi plus tard.

        Pour le #include "string.h"; ca doit être des erreurs lors du copier/coller vu que dans mon code local c'est correct. bizarre...
        • [^] # Re: valgrind ou electric fence

          Posté par . Évalué à 3.

          Ok, c'est ça.

          Si je double la taille du buffer, y'a plus de problème.

          La notion de frame est définie comme :
          frame
          A sample is a single value that describes the amplitude of the audio signal at a single point in time, on a single channel. When we talk about working with digital audio, we often want to talk about the data that represents all channels at a single point in time. This is a collection of samples, one per channel, and is generally called a "frame". When we talk about the passage of time in terms of frames, its roughly equivalent to what people when they measure in terms of samples, but is more accurate; more importantly, when we're talking about the amount of data needed to represent all the channels at a point in time, its the only unit that makes sense. Almost every ALSA Audio API function uses frames as its unit of measurement for data quantities.

          Donc dans mon cas, une frame contiendrait 2 samples de 16 bits chacun. Il me faudrait donc 32 bits par frame. Et la taille de "short" est de 16 bits avec mon petit gcc.

          Merci pour votre aide.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.