C:为什么我的库中的全局变量不会更新?(使用 ALSA Lib)



前言:我看过其他答案,我相信这是一个不同类型的问题。它可能与指针有关,但其他答案都没有帮助。我也可能只是错过了一些东西。

我设法制作了一个工作程序,使用 ALSA 库将原始音频数据流式传输到标准输出。我现在正在尝试将此代码推广到库中,并且库的 .c 文件中的全局变量没有更新。据我所知,设置与原始程序没有什么不同,所以我认为它应该可以工作......但事实并非如此。我真的很感激有人确切地解释我是如何搞砸的。先发制人地谢谢你!

编辑 1:

调用wm8782_open_audio()时,wm8782.c顶部的所有全局变量都无法设置。例如,如果在调用wm8782_open_audio()后在wm8782_us_to_loops()中调用snd_pcm_hw_params_get_period_time(params, &val, &dir);,则会失败,因为未初始化params。但是,wm8782_open_audio()完成没有错误!

编辑2:

我在标题中添加了extern声明,没有骰子。有关更新的文件,请参见下文。

编辑3:

我已经在没有标头的单个 C 文件中重现了该问题。简单地将代码分解为函数就足以打破它。我用这个单片C文件替换了2个库文件,以消除链接器错误等。

这是我试图推广到库中的原始程序。这确实按照我想要的方式工作。

#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
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;
int main()
{
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "hw:1",
SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0)
{
fprintf(stderr,
"unable to open pcm device: %sn",
snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* 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 32-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S32_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 64 frames. */
frames = 64;
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: %sn",
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 * 8; /* 4 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);
//fprintf(stderr, "%un", val);
loops = 5000000 / val;
while (loops > 0)
{
loops--;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurredn");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr,
"error from read: %sn",
snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d framesn", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr,
"short write: wrote %d bytesn", rc);
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}

现在这里是模块化版本,最终将成为一个库。此操作失败,并显示ERROR: Failed to get number of loops.

#define ALSA_PCM_NEW_HW_PARAMS_API
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <alsa/asoundlib.h>
char *wm8782_buffer;
int wm8782_buffer_size;
snd_pcm_t *wm8782_handle;
snd_pcm_hw_params_t *wm8782_params;
int wm8782_dir;
snd_pcm_uframes_t wm8782_frames;
unsigned int wm8782_val;
int wm8782_rc;
typedef enum
{
WM8782_READ_OVERRUN,
WM8782_READ_ERROR,
WM8782_READ_SHORT,
WM8782_READ_GOOD,
} wm8782read_t;
typedef enum
{
WM8782_RATE_8K = 8000,
WM8782_RATE_16K = 16000,
WM8782_RATE_32K = 32000,
WM8782_RATE_44_1K = 44100,
WM8782_RATE_48K = 48000,
WM8782_RATE_96K = 96000,
WM8782_RATE_192K = 192000,
} wm8782rate_t;
bool wm8782_open_audio(wm8782rate_t rate_in, snd_pcm_uframes_t wm8782_frames_in)
{
// Open PCM device for recording (capture).
wm8782_rc = snd_pcm_open(&wm8782_handle, "hw:1",
SND_PCM_STREAM_CAPTURE, 0);
if (wm8782_rc < 0)
{
fprintf(stderr,
"ERROR: Unable to open pcm device: %sn",
snd_strerror(wm8782_rc));
return false;
}
// Allocate a hardware parameters object.
snd_pcm_hw_params_alloca(&wm8782_params);
// Fill it in with default values
snd_pcm_hw_params_any(wm8782_handle, wm8782_params);
// Set the desired hardware parameters. */
// Interleaved mode
snd_pcm_hw_params_set_access(wm8782_handle, wm8782_params, SND_PCM_ACCESS_RW_INTERLEAVED);
// Signed 32-bit little-endian format
snd_pcm_hw_params_set_format(wm8782_handle, wm8782_params, SND_PCM_FORMAT_S32_LE);
// Two channels (stereo)
snd_pcm_hw_params_set_channels(wm8782_handle, wm8782_params, 2);
// Set rate
wm8782_val = rate_in;
snd_pcm_hw_params_set_rate_near(wm8782_handle, wm8782_params, &wm8782_val, &wm8782_dir);
// Set period size.
wm8782_frames = wm8782_frames_in;
snd_pcm_hw_params_set_period_size_near(wm8782_handle, wm8782_params, &wm8782_frames, &wm8782_dir);
// Write the parameters to the driver
wm8782_rc = snd_pcm_hw_params(wm8782_handle, wm8782_params);
if (wm8782_rc < 0)
{
fprintf(stderr,
"ERROR: Unable to set hw parameters: %sn",
snd_strerror(wm8782_rc));
return false;
}
// Use a buffer large enough to hold one period
snd_pcm_hw_params_get_period_size(wm8782_params, &wm8782_frames, &wm8782_dir);
wm8782_buffer_size = wm8782_frames * 8; // 4 bytes/sample, 2 channels
wm8782_buffer = (char *) malloc(wm8782_buffer_size);
return true;
}
void wm8782_close_audio()
{
snd_pcm_drain(wm8782_handle);
snd_pcm_close(wm8782_handle);
free(wm8782_buffer);
}
wm8782read_t wm8782_read_audio()
{
wm8782_rc = snd_pcm_readi(wm8782_handle, wm8782_buffer, wm8782_frames);
if (wm8782_rc == -EPIPE)
{
// EPIPE means overrun
fprintf(stderr, "ERROR: Overrun occurredn");
snd_pcm_prepare(wm8782_handle);
return WM8782_READ_OVERRUN;
}
else if (wm8782_rc < 0)
{
fprintf(stderr, "ERROR: From read: %sn", snd_strerror(wm8782_rc));
return WM8782_READ_ERROR;
}
else if (wm8782_rc != (int)wm8782_frames)
{
fprintf(stderr, "ERROR: Short read, read %d wm8782_framesn", wm8782_rc);
return WM8782_READ_SHORT;
}
return WM8782_READ_GOOD;
}
unsigned int wm8782_us_to_loops(unsigned int us_in)
{
if(snd_pcm_hw_params_get_period_time(wm8782_params, &wm8782_val, &wm8782_dir) < 0)
{
fprintf(stderr, "ERROR: Failed to get number of loops.n");
return 0;
}
//fprintf(stderr, "%un", wm8782_val);
return (us_in / wm8782_val);
}
int main()
{
if(!wm8782_open_audio(44100, 64))
{
fprintf(stderr, "unable to open pcm device");
}
unsigned int loops =  wm8782_us_to_loops(5000000);
while (loops > 0)
{
loops--;
wm8782_read_audio();
wm8782_rc = write(1, wm8782_buffer, wm8782_buffer_size);
if (wm8782_rc != wm8782_buffer_size)
fprintf(stderr,
"short write: wrote %d bytesn", wm8782_rc);
}
wm8782_close_audio();
return 0;
}

好的,所以事实证明这根本不是全局变量的问题......对不起大家!这是一些奇怪的无效参数被传递给snd_pcm_hw_params_get_period_size(),特别是。该代码实际上适用于手动定义的循环数,因此我正在关闭这个问题。

最新更新