C 프로그램을 사용하여 오디오를 캡처하고 재생하려고 합니다. 이를 위해 나는이 튜토리얼을 얻었습니다.. 내가 실행중인 프로그램은 다음과 같습니다.
/**
* Jan Newmarch
*/
#define PERIOD_SIZE 1024
#define BUF_SIZE (PERIOD_SIZE * 2)
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
void print_pcm_state(snd_pcm_t *handle, char *name) {
switch (snd_pcm_state(handle)) {
case SND_PCM_STATE_OPEN:
printf("state open %s\n", name);
break;
case SND_PCM_STATE_SETUP:
printf("state setup %s\n", name);
break;
case SND_PCM_STATE_PREPARED:
printf("state prepare %s\n", name);
break;
case SND_PCM_STATE_RUNNING:
printf("state running %s\n", name);
break;
case SND_PCM_STATE_XRUN:
printf("state xrun %s\n", name);
break;
default:
printf("state other %s\n", name);
break;
}
}
int setparams(snd_pcm_t *handle, char *name) {
snd_pcm_hw_params_t *hw_params;
int err;
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);
}
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);
}
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);
}
unsigned int rate = 48000;
if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &rate, 0)) < 0) {
fprintf (stderr, "cannot set sample rate (%s)\n",
snd_strerror (err));
exit (1);
}
printf("Rate for %s is %d\n", name, rate);
if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, 2)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
exit (1);
}
snd_pcm_uframes_t buffersize = BUF_SIZE;
if ((err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffersize)) < 0) {
printf("Unable to set buffer size %li: %s\n", BUF_SIZE, snd_strerror(err));
exit (1);;
}
snd_pcm_uframes_t periodsize = PERIOD_SIZE;
fprintf(stderr, "period size now %d\n", periodsize);
if ((err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &periodsize, 0)) < 0) {
printf("Unable to set period size %li: %s\n", periodsize, 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);
}
snd_pcm_uframes_t p_psize;
snd_pcm_hw_params_get_period_size(hw_params, &p_psize, NULL);
fprintf(stderr, "period size %d\n", p_psize);
snd_pcm_hw_params_get_buffer_size(hw_params, &p_psize);
fprintf(stderr, "buffer size %d\n", p_psize);
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 set_sw_params(snd_pcm_t *handle, char *name) {
snd_pcm_sw_params_t *swparams;
int err;
snd_pcm_sw_params_alloca(&swparams);
err = snd_pcm_sw_params_current(handle, swparams);
if (err < 0) {
fprintf(stderr, "Broken configuration for this PCM: no configurations available\n");
exit(1);
}
err = snd_pcm_sw_params_set_start_threshold(handle, swparams, PERIOD_SIZE);
if (err < 0) {
printf("Unable to set start threshold: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_sw_params_set_avail_min(handle, swparams, PERIOD_SIZE);
if (err < 0) {
printf("Unable to set avail min: %s\n", snd_strerror(err));
return err;
}
if (snd_pcm_sw_params(handle, swparams) < 0) {
fprintf(stderr, "unable to install sw params:\n");
exit(1);
}
return 0;
}
/************** some code from latency.c *****************/
main (int argc, char *argv[])
{
int i;
int err;
int buf[BUF_SIZE];
snd_pcm_t *playback_handle;
snd_pcm_t *capture_handle;
snd_pcm_hw_params_t *hw_params;
FILE *fin;
size_t nread;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
if (argc != 3) {
fprintf(stderr, "Usage: %s in-card out-card\n", argv[0]);
exit(1);
}
/**** Out card *******/
if ((err = snd_pcm_open (&playback_handle, argv[2], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
argv[2],
snd_strerror (err));
exit (1);
}
setparams(playback_handle, "playback");
set_sw_params(playback_handle, "playback");
/*********** In card **********/
if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
argv[1],
snd_strerror (err));
exit (1);
}
setparams(capture_handle, "capture");
set_sw_params(capture_handle, "capture");
if ((err = snd_pcm_link(capture_handle, playback_handle)) < 0) {
printf("Streams link error: %s\n", snd_strerror(err));
exit(0);
}
if ((err = snd_pcm_prepare (playback_handle)) < 0) {
fprintf (stderr, "cannot prepare playback audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}
/**************** stuff something into the playback buffer ****************/
if (snd_pcm_format_set_silence(format, buf, 2*BUF_SIZE) < 0) {
fprintf(stderr, "silence error\n");
exit(1);
}
int n = 0;
while (n++ < 2) {
if (snd_pcm_writei (playback_handle, buf, BUF_SIZE) < 0) {
fprintf(stderr, "write error\n");
exit(1);
}
}
/************* COPY ************/
while (1) {
int nread;
if ((nread = snd_pcm_readi (capture_handle, buf, BUF_SIZE)) != BUF_SIZE) {
if (nread < 0) {
fprintf (stderr, "read from audio interface failed (%s)\n",
snd_strerror (nread));
} else {
fprintf (stderr, "read from audio interface failed after %d frames\n", nread);
}
snd_pcm_prepare(capture_handle);
continue;
}
if ((err = snd_pcm_writei (playback_handle, buf, nread)) != nread) {
if (err < 0) {
fprintf (stderr, "write to audio interface failed (%s)\n",
snd_strerror (err));
} else {
fprintf (stderr, "write to audio interface failed after %d frames\n", err);
}
snd_pcm_prepare(playback_handle);
}
}
snd_pcm_drain(playback_handle);
snd_pcm_close (playback_handle);
exit (0);
}
나는 그것을 컴파일하고 다음 매개변수를 사용하여 실행했습니다.
./playback-capture hw:0 hw:0
내 코드는 지금까지 잘 작동하고 있지만 이제 USB 사운드 카드를 사용하여 프로그램을 실행하기로 결정했습니다. 이를 위해 편집합니다.
/etc/modprobe.d/alsa-base.conf
변경 사항은 다음과 같습니다.
내가 대신해
options snd_usb_audio index=-2
options snd_hda_intel index=-1
그리고
options snd_usb_audio index=-1
options snd_hda_intel index=-2
내가 대신해
# Keep snd-usb-audio from beeing loaded as first soundcard
options snd-usb-audio index=-1
그리고
# Keep snd-usb-audio from beeing loaded as first soundcard
options snd-usb-audio index=-1
이제 코드를 실행하면 다음과 같은 출력이 표시됩니다.
Rate for playback is 48000
period size now 1024
period size 1024
buffer size 2048
Rate for capture is 48000
cannot set channel count (Invalid argument)
그렇다면 사운드 카드를 사용하여 코드를 실행하려면 어떻게 해야 하는지 말해 줄 수 있는 사람이 있습니까?
참고:-명령을 실행합니다.
aplay -l
그리고 다음과 같은 결과가 나왔습니다:-
card 0: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: ALC221 Analog [ALC221 Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
답변1
프로젝트의 일환으로 전이중 ALSA를 원합니다.고급 Linux 사운드 아키텍처예를 들어:
- 마이크 잭(분홍색)을 통해 사운드 카드에서 사운드를 캡처합니다.
- 다른 USB 사운드 카드 출력(라인 출력 녹색 잭)에서 재생합니다.
코드를 약간만 변경하면 다음은 양방향 ALSA 캡처 재생의 예입니다.
암호
/**
* Jan Newmarch
*/
/*
* File name: rec-play-inline.c
*
* compile: gcc rec-play-inline.c -o rec-play-inline -lasound
*
* run: ./rec-play-inline "plughw:2,0" "plughw:0,0"
*
*
* */
#define PERIOD_SIZE 1024
#define BUF_SIZE (PERIOD_SIZE * 2)
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
void print_pcm_state(snd_pcm_t *handle, char *name) {
switch (snd_pcm_state(handle)) {
case SND_PCM_STATE_OPEN:
printf("state open %s\n", name);
break;
case SND_PCM_STATE_SETUP:
printf("state setup %s\n", name);
break;
case SND_PCM_STATE_PREPARED:
printf("state prepare %s\n", name);
break;
case SND_PCM_STATE_RUNNING:
printf("state running %s\n", name);
break;
case SND_PCM_STATE_XRUN:
printf("state xrun %s\n", name);
break;
default:
printf("state other %s\n", name);
break;
}
}
int setparams(snd_pcm_t *handle, char *name) {
snd_pcm_hw_params_t *hw_params;
int err;
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);
}
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);
}
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);
}
unsigned int rate = 48000;
if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &rate, 0)) < 0) {
fprintf (stderr, "cannot set sample rate (%s)\n",
snd_strerror (err));
exit (1);
}
printf("Rate for %s is %d\n", name, rate);
if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, 2)) < 0) {
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
exit (1);
}
snd_pcm_uframes_t buffersize = BUF_SIZE;
if ((err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffersize)) < 0) {
printf("Unable to set buffer size %li: %s\n", (long int)BUF_SIZE, snd_strerror(err));
exit (1);;
}
snd_pcm_uframes_t periodsize = PERIOD_SIZE;
fprintf(stderr, "period size now %d\n", (int) periodsize);
if ((err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &periodsize, 0)) < 0) {
printf("Unable to set period size %li: %s\n", periodsize, 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);
}
snd_pcm_uframes_t p_psize;
snd_pcm_hw_params_get_period_size(hw_params, &p_psize, NULL);
fprintf(stderr, "period size %d\n", (int)p_psize);
snd_pcm_hw_params_get_buffer_size(hw_params, &p_psize);
fprintf(stderr, "buffer size %d\n", (int)p_psize);
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 set_sw_params(snd_pcm_t *handle, char *name) {
snd_pcm_sw_params_t *swparams;
int err;
snd_pcm_sw_params_alloca(&swparams);
err = snd_pcm_sw_params_current(handle, swparams);
if (err < 0) {
fprintf(stderr, "Broken configuration for this PCM: no configurations available\n");
exit(1);
}
err = snd_pcm_sw_params_set_start_threshold(handle, swparams, PERIOD_SIZE);
if (err < 0) {
printf("Unable to set start threshold: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_sw_params_set_avail_min(handle, swparams, PERIOD_SIZE);
if (err < 0) {
printf("Unable to set avail min: %s\n", snd_strerror(err));
return err;
}
if (snd_pcm_sw_params(handle, swparams) < 0) {
fprintf(stderr, "unable to install sw params:\n");
exit(1);
}
return 0;
}
/************** some code from latency.c *****************/
int main (int argc, char *argv[])
{
int i;
int err;
int buf[BUF_SIZE];
snd_pcm_t *playback_handle;
snd_pcm_t *capture_handle;
snd_pcm_hw_params_t *hw_params;
FILE *fin;
size_t nread;
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
///Check for command line arguments
if (argc != 3) {
fprintf(stderr, "Usage: %s input-soundCard output-soundCard\n", argv[0]);
exit(1);
}
/**** Out card *******/
if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
argv[2],
snd_strerror (err));
exit (1);
}
setparams(playback_handle, "playback");
set_sw_params(playback_handle, "playback");
/*********** In card **********/
if ((err = snd_pcm_open (&capture_handle, argv[2], SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
argv[1],
snd_strerror (err));
exit (1);
}
setparams(capture_handle, "capture");
set_sw_params(capture_handle, "capture");
///Comment by EE
/*
if ((err = snd_pcm_link(capture_handle, playback_handle)) < 0) {
printf("Streams link error: %s\n", snd_strerror(err));
exit(0);
}
*/
if ((err = snd_pcm_prepare (playback_handle)) < 0) {
fprintf (stderr, "cannot prepare playback audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}
/**************** stuff something into the playback buffer ****************/
if (snd_pcm_format_set_silence(format, buf, 2*BUF_SIZE) < 0) {
fprintf(stderr, "silence error\n");
exit(1);
}
///Comment by EE
/*
int n = 0;
while (n++ < 2) {
if (snd_pcm_writei (playback_handle, buf, BUF_SIZE) < 0) {
fprintf(stderr, "write error\n");
exit(1);
}
}
*/
///
/************* Capture and Play Voice ***************/
while (1) {
int nread;
if ((nread = snd_pcm_readi (capture_handle, buf, BUF_SIZE)) != BUF_SIZE) {
if (nread < 0) {
fprintf (stderr, "read from audio interface failed (%s)\n",
snd_strerror (nread));
} else {
fprintf (stderr, "read from audio interface failed after %d frames\n", nread);
}
snd_pcm_prepare(capture_handle);
continue;
}
///added by EE
snd_pcm_prepare(playback_handle);
///
if ((err = snd_pcm_writei (playback_handle, buf, nread)) != nread) {
if (err < 0) {
fprintf (stderr, "write to audio interface failed (%s)\n",
snd_strerror (err));
} else {
fprintf (stderr, "write to audio interface failed after %d frames\n", err);
}
snd_pcm_prepare(playback_handle);
}
}
snd_pcm_drain(playback_handle);
snd_pcm_close (playback_handle);
exit (0);
return 0;
}
설명하다
내 온보드 사운드 카드는 다음과 같습니다. plughw:0,0
USB로 연결된 외부 사운드 카드는 다음과 같습니다.plughw:2,0
다음 명령을 실행하여 이러한 이름을 찾았습니다.
- 재생 장치 목록을 얻으려면:
aplay --list--devices
- 캡처 장치 목록을 얻으려면:
arecord --list-devices
원천
snd_pcm_prepare(playback_handle);
전화하기 전에 추가하여 문제 writei()
를 해결하세요.
ALSA: snd_pcm_writei를 호출할 때 버퍼가 부족합니다.