gpt4 book ai didi

c - 为什么使用 dlopen 加载时 libao 没有声音?

转载 作者:行者123 更新时间:2023-11-30 14:37:04 30 4
gpt4 key购买 nike

我正在使用 libao 编写应用程序用于音频输出。该部分我的程序中调用 libao 的部分位于共享对象中:

// playao.c
// compile with: gcc -shared -o libplayao.so playao.c -lao -lm
#include <ao/ao.h>
#include <stdio.h>
#include <math.h>

void playao(void) {
int i;
unsigned char samps[8000];
ao_initialize();
ao_sample_format sf;
sf.bits = 8;
sf.rate = 8000;
sf.channels = 1;
sf.byte_format = AO_FMT_NATIVE;
sf.matrix = "M";
ao_device *device = ao_open_live(ao_default_driver_id(), &sf, NULL);
if(!device) {
puts("ao_open_live error");
ao_shutdown();
return;
}
for(i = 0; i < 8000; ++i) {
float time = (float)i / 8000;
float freq = 440;
float angle = time * freq * M_PI * 2;
float value = sinf(angle);
samps[i] = (unsigned char)(value * 127 + 127);
}
if(!ao_play(device, (char *)samps, 8000)) {
puts("ao_play error");
}
ao_close(device);
ao_shutdown();
}

如果我在程序中链接到此共享对象,它可以正常工作:

// directlink.c
// compile with: gcc -o directlink directlink.c libplayao.so -Wl,-rpath,'$ORIGIN'
void playao(void);

int main(int argc, char **argv) {
playao();
return 0;
}

但是,如果我使用 dlopen/dlsym 调用它,则不会出现错误,但程序不会发出任何声音:

// usedl.c
// compile with: gcc -o usedl usedl.c -ldl
#include <dlfcn.h>
#include <stdio.h>

int main(int argc, char **argv) {
void *handle = dlopen("./libplayao.so", RTLD_LAZY);
if(!handle) {
puts("dlopen failed");
return 1;
}
void *playao = dlsym(handle, "playao");
if(!playao) {
puts("dlsym failed");
dlclose(handle);
return 1;
}
((void (*)(void))playao)();
dlclose(handle);
return 0;
}

但是,使用 LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libao.so.4 运行 usedl确实有效。所以有一些关于libao的东西想要在程序启动,并且不喜欢稍后加载。

这是为什么呢?有什么办法可以解决这个问题,以便 libao 正常工作即使稍后在程序执行中加载也正确吗?

如果重要的话,我正在运行 Debian 10 “buster”。

最佳答案

我在 Freenode 上的 #xiph channel 上询问了这个问题,xiphmont 建议转向 turning on verbose mode 。一旦我这样做了,失败的案例就开始收到消息:

ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so => dlopen() failed

所以 libao 本身正在尝试dlopen某事,但它失败了。它没有向我显示更多详细信息,因此我在 GDB 下运行该程序并在 dlopen 上设置断点。 。点击dlopenlibalsa 的断点并运行finish ,我尝试使用 print (const char *)dlerror() 查找错误所在。这样,我得到了更详细的错误:

/usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so: undefined symbol: ao_is_big_endian

所以 ao 的 libalsa 插件试图引用 libao 中的符号,但没有找到它们。为什么会这样呢?引用 dlopen文档,我看到:

Zero or more of the following values may also be ORed in flags:

RTLD_GLOBAL: The symbols defined by this shared object will be made available for symbol resolution of subsequently loaded shared objects.

RTLD_LOCAL: This is the converse of RTLD_GLOBAL, and the default if neither flag is specified. Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects.

因为我的dlopen仅用于调用RTLD_LAZY并且不包括RTLD_GLOBALRTLD_LOCAL ,默认为RTLD_LOCAL ,它不会将共享对象中的符号(如 ao_is_big_endian )公开给随后加载的共享对象(如 libalsa.so )。

所以,我尝试更改代码:

void *handle = dlopen("./libplayao.so", RTLD_LAZY);

致:

void *handle = dlopen("./libplayao.so", RTLD_LAZY | RTLD_GLOBAL);

你瞧,它确实有效!

关于c - 为什么使用 dlopen 加载时 libao 没有声音?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57644228/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com