01-15 14:31:50.960: E/faplayer(1622): [0x67389ef8]audiotrack_android audio output: Could not initialize libmedia.so!
01-15 14:31:50.960: D/faplayer(1622): [0x67389ef8]main audio output: using audio output module "dummy"
上面这条日志是报了个错说无法初始化libmedia.so这个库,下面的日志说的是使用虚拟的音频输出模块,是不是使用了虚拟的音频模块,才导致了没有声音呢?
在faplayer的jni代码中查找这条日志的输出位置:在faplayer/jni/vlc/modules/audio_output/android_AudioTrack.c中:
1 p_library = InitLibrary(p_this);
2 if (!p_library) {
3 msg_Err(VLC_OBJECT(p_this), "Could not initialize libmedia.so!");
4 return VLC_EGENERIC;
5 }
看来是InitLibrary函数出了问题,我们来看看这个函数的内容:
1 void *InitLibrary() {
2 void *p_library;
3
4 p_library = dlopen("libmedia.so", RTLD_NOW);
5 if (!p_library)
6 return NULL;
7 as_getOutputFrameCount = (AudioSystem_getOutputFrameCount)(dlsym(p_library, "_ZN7android11AudioSystem19getOutputFrameCountEPii"));
8 as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
9 as_getOutputSamplingRate = (AudioSystem_getOutputSamplingRate)(dlsym(p_library, "_ZN7android11AudioSystem21getOutputSamplingRateEPii"));
10 at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPiij"));
11 at_ctor = (AudioTrack_ctor)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii"));
12 at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i"));
13 at_dtor = (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev"));
14 at_initCheck = (AudioTrack_initCheck)(dlsym(p_library, "_ZNK7android10AudioTrack9initCheckEv"));
15 at_start = (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv"));
16 at_stop = (AudioTrack_stop)(dlsym(p_library, "_ZN7android10AudioTrack4stopEv"));
17 at_write = (AudioTrack_write)(dlsym(p_library, "_ZN7android10AudioTrack5writeEPKvj"));
18 at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
19 // need the first 3 or the last 1
20 if (!((as_getOutputFrameCount && as_getOutputLatency && as_getOutputSamplingRate) || at_getMinFrameCount)) {
21 dlclose(p_library);
22 return NULL;
23 }
24 // need all in the list
25 if (!((at_ctor || at_ctor_legacy) && at_dtor && at_initCheck && at_start && at_stop && at_write && at_flush)) {
26 dlclose(p_library);
27 return NULL;
28 }
29 return p_library;
30 }
嗯,看来这个函数的内容是从so库中查找相应的函数地址,然后把地址赋值给对应的函数指针,那么类似“_ZN7android11AudioSystem19getOutputFrameCountEPii”这样的字符串就是函数在so库中的签名了。我们看看这个字符串所代表的函数的签名:
1 // _ZN7android11AudioSystem19getOutputFrameCountEPii
2 typedef int (*AudioSystem_getOutputFrameCount)(int *, int);
为什么这样的函数在so中会有这样奇怪的代号呢?这方面的知识有一篇文章讲的很好:C++的函数重载
了解了这个后我就在猜想:应该是某个或是某几个函数的签名在4.1中发生了改变,导致找不到才出的错,于是我这样修改程序:
1 void *InitLibrary() {
2 void *p_library;
3
4 p_library = dlopen("libmedia.so", RTLD_NOW);
5 if (!p_library)
6 return NULL;
7 as_getOutputFrameCount = (AudioSystem_getOutputFrameCount)(dlsym(p_library, "_ZN7android11AudioSystem19getOutputFrameCountEPii"));
8 as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
9 as_getOutputSamplingRate = (AudioSystem_getOutputSamplingRate)(dlsym(p_library, "_ZN7android11AudioSystem21getOutputSamplingRateEPii"));
10 at_getMinFrameCount = (AudioTrack_getMinFrameCount)(dlsym(p_library, "_ZN7android10AudioTrack16getMinFrameCountEPiij"));
11 at_ctor = (AudioTrack_ctor)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii"));
12 at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library, "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i"));
13 at_dtor = (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev"));
14 at_initCheck = (AudioTrack_initCheck)(dlsym(p_library, "_ZNK7android10AudioTrack9initCheckEv"));
15 at_start = (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv"));
16 at_stop = (AudioTrack_stop)(dlsym(p_library, "_ZN7android10AudioTrack4stopEv"));
17 at_write = (AudioTrack_write)(dlsym(p_library, "_ZN7android10AudioTrack5writeEPKvj"));
18 at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
19 // need the first 3 or the last 1
20 if (!((as_getOutputFrameCount && as_getOutputLatency && as_getOutputSamplingRate) || at_getMinFrameCount)) {
21 msg_Err(VLC_OBJECT(p_this), "interface error 1");
22 if (!as_getOutputFrameCount) {
23 msg_Err(VLC_OBJECT(p_this), "error1");
24 }
25 if (!as_getOutputLatency) {
26 msg_Err(VLC_OBJECT(p_this), "error2");
27 }
28 if (!as_getOutputSamplingRate) {
29 msg_Err(VLC_OBJECT(p_this), "error3");
30 }
31 if (!at_getMinFrameCount)
32 {
33 msg_Err(VLC_OBJECT(p_this), "error4");
34 }
35 dlclose(p_library);
36 return NULL;
37 }
38 // need all in the list
39 if (!((at_ctor || at_ctor_legacy) && at_dtor && at_initCheck && at_start && at_stop && at_write && at_flush)) {
40 msg_Err(VLC_OBJECT(p_this), "interface error 2");
41 dlclose(p_library);
42 return NULL;
43 }
44 return p_library;
45 }
查看日志后,发现是“error2” 也就是as_getOutputLatency为空,那说明“_ZN7android11AudioSystem16getOutputLatencyEPji”这个签名现在在libmedia.so中找不到了,那么现在这个函数的签名是什么呢?要想弄清楚这个,我们需要弄清楚怎么查看libmedia.so中函数的签名。
在网上查询方法后,在终端上使用readelf -s libmedia.so,结果是一长串符号列表,类似下面的内容:
1 root@ubuntu:/mnt/hgfs/share/4.1.2# readelf -s libmedia.so
2
3 Symbol table '.dynsym' contains 1918 entries:
4 Num: Value Size Type Bind Vis Ndx Name
5 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
6 1: 00037069 4 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack16
7 2: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
8 3: 0003706d 2 FUNC GLOBAL DEFAULT 7 _ZTv0_n16_N7android10Audi
9 4: 0003706d 2 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack16
10 5: 0003706f 12 FUNC GLOBAL DEFAULT 7 _ZTv0_n12_N7android10Audi
11 6: 0003707d 68 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack16
12 7: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_cond_destroy
13 8: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_destroy
14 9: 00000000 0 FUNC GLOBAL DEFAULT UND _ZN7android6ThreadD2Ev
15 10: 00000000 0 FUNC GLOBAL DEFAULT UND _ZN7android7RefBaseD2Ev
16 11: 000370c1 12 FUNC GLOBAL DEFAULT 7 _ZTv0_n12_N7android10Audi
17 12: 000370cd 18 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack16
18 13: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv
19 14: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_lock
20 15: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr1
21 16: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_unlock
22 17: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_idiv
23 18: 00000000 0 FUNC GLOBAL DEFAULT UND __aeabi_uidiv
24 19: 000370ed 98 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack16
25 20: 0003f015 52 FUNC GLOBAL DEFAULT 7 _ZN7android11AudioSystem2
26 21: 0003efdd 52 FUNC GLOBAL DEFAULT 7 _ZN7android11AudioSystem1
27 22: 0003efa9 52 FUNC GLOBAL DEFAULT 7 _ZN7android11AudioSystem1
28 23: 0003714f 62 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrackC2
29 24: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_init
30 25: 0003718d 80 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrackC1
31 26: 00000000 0 FUNC GLOBAL DEFAULT UND _ZN7android7RefBaseC2Ev
32 27: 000371dd 4 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack9
33 28: 000371e1 4 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack7
34 29: 000371e5 4 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack1
35 30: 000371e9 4 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack6
36 31: 000371ed 6 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack1
37 32: 000371f3 6 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack1
38 33: 000371f9 44 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack9
39 34: 00037225 4 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack12
40 35: 00037229 32 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack7
41 36: 00037249 48 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack7f
42 37: 00000000 0 FUNC GLOBAL DEFAULT UND pthread_cond_signal
43 38: 00037279 30 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack5f
44 39: 00037297 52 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack5p
45 40: 000372cb 22 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack4m
46 41: 000372e1 12 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack5
47 42: 000372ed 144 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack9s
48 43: 0003737d 14 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack9
49 44: 0003738d 96 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack21
50 45: 000373ed 8 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack2
51 46: 000373f5 74 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack13
52 47: 0003743f 40 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack1
53 48: 00037469 188 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack9s
54 49: 00000000 0 FUNC GLOBAL DEFAULT UND __android_log_print
55 50: 00037525 48 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack7s
56 51: 00037555 22 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack17
57 52: 0003756b 16 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack1
58 53: 0003757b 16 FUNC GLOBAL DEFAULT 7 _ZNK7android10AudioTrack2
59 54: 0003758b 94 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack11
60 55: 00000000 0 FUNC GLOBAL DEFAULT UND android_atomic_or
61 56: 000375e9 50 FUNC GLOBAL DEFAULT 7 _ZN7android10AudioTrack11
62 ...
看上去挺像那么回事的是吧?其实在仔细查找其中的内容后,没有发现任何跟“_ZN7android11AudioSystem16getOutputLatencyEPji”相关的代码,别说这个空函数了,连已经证明加载成功的函数的签名也没有找到,这是为什么呢?
这时候我就想到,android系统中的库文件都是在arm-linux环境下编译的,属于交叉编译,而我们使用的命令都是在x86架构下的指令,他解析的符号类型会不会也是x86的指令呢?为了弄清楚这个问题,我需要安装arm-linux的开发工具,在参考了这几篇文章后,我成功的安装了arm-linux工具链。
在 Linux 下安装 GNU ARM 工具链
Android 开发环境建立-ARM编译器安装
编译mini2440工具链
使用arm-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu交叉编译成功在板子上运行
然后使用命令:arm-none-linux-gnueabi-objdump -d libmedia.so:
1 root@ubuntu:/mnt/hgfs/share/4.1.2# arm-none-linux-gnueabi-objdump -d libmedia.so
2
3 libmedia.so: file format elf32-littlearm
4
5 Disassembly of section .plt:
6
7 00036358 <.plt>:
8 36358: e52de004 push {lr} ; (str lr, [sp, #-4]!)
9 3635c: e59fe004 ldr lr, [pc, #4] ; 36368 <_ZN7android10AudioTrack16AudioTrackThread10readyToRunEv-0xd00>
10 36360: e08fe00e add lr, pc, lr
11 36364: e5bef008 ldr pc, [lr, #8]!
12 ... ...
13 37058: e5bcffa0 ldr pc, [ip, #4000]!
14 3705c: e28fc600 add ip, pc, #0 ; 0x0
15 37060: e28cca38 add ip, ip, #229376 ; 0x38000
16 37064: e5bcff98 ldr pc, [ip, #3992]!
17 Disassembly of section .text:
18
19 00037068 <_ZN7android10AudioTrack16AudioTrackThread10readyToRunEv>:
20 37068: 2000 movs r0, #0
21 3706a: 4770 bx lr
22
23 0003706c <_ZN7android10AudioTrack16AudioTrackThread10onFirstRefEv>:
24 3706c: 4770 bx lr
25
26 0003706e <_ZTv0_n12_N7android10AudioTrack16AudioTrackThreadD1Ev>:
27 3706e: 6801 ldr r1, [r0, #0]
28 37070: f851 3c0c ldr.w r3, [r1, #-12]
29 37074: 18c0 adds r0, r0, r3
30 37076: f000 b801 b.w 3707c <_ZN7android10AudioTrack16AudioTrackThreadD1Ev>
31 ...
结果是上面这样的代码。把结果输出到文件中,进行查找:
1 root@ubuntu:/mnt/hgfs/share/4.1.2# arm-none-linux-gnueabi-objdump -d libmedia.so > libmedia.txt
2 root@ubuntu:/mnt/hgfs/share/4.1.2# ls
3 4.0.4 4.0.4.txt 4.1.2.txt a.txt lib libmedia_jni.so libmedia_native.so libmediaplayerservice.so libmedia.so libmedia.txt
4 root@ubuntu:/mnt/hgfs/share/4.1.2# gedit libmedia.txt
5 root@ubuntu:/mnt/hgfs/share/4.1.2# grep getOutputLatency libmedia.txt
6 3710c: f007 ff4c bl 3efa8 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t>
7 0003efa8 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t>:
8 3efc4: b130 cbz r0, 3efd4 <_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t+0x2c>
可知getOutputLatency函数的符号由“_ZN7android11AudioSystem16getOutputLatencyEPji”变为“_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t”,于是我们这样修改代码:
1 as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPji"));
2
3 // edit by yueang
4 if (!as_getOutputLatency) {
5 as_getOutputLatency = (AudioSystem_getOutputLatency)(dlsym(p_library, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t"));
6 }
7 // edit by yueang end
然后编译运行,问题解决!