1. 任务分解1.1 android 使用了tinyalsa库,看了一下代码,这个库实在功能太弱,google总是放弃稳定的好用的东西不用,自己乱搞,或许是因为licence的问题?于是第一个子任务是将原来android 2.3.3上的alsa库移植上来。1.2 内核要打开配置,至少把UAC打开1.3 找一个usb声卡,淘宝上7块钱就能买到,真他妈便宜,不知道这些人怎么挣钱的!1.4 使用编译出来的alsa库进行测试,验证可正常使用1.5 使用android自带的tinyalsa进行播放测试,因为android的HAL层是调用这个库的,所以这个还非测试不可1.6 修改audio_hw(android声音的HAL层)代码,将UAC声卡接入到android4.0中去1.7 使用android自带的Music.apk,SoundRecorder.apk进行最后测试,我想这两个过了其它软件应该没问题了吧2. 各子任务的具体实施2.1 移植alsa库将原来android2.3.3/external/alsa-lib,android2.3.3/external/alsa-utils这两个库cp到 android4.0/external/中 直接编译生成 相应的alsa_aplay,alsa_amixer,alsa_ctl,并cp到目标板子上,将alsa的配置文件也从android2.3.3 复制到目标板子/system/usr/share/alsa 目录下具体配置文件为 ./pcm/center_lfe.conf./pcm/surround40.conf./pcm/surround50.conf./pcm/dmix.conf./pcm/rear.conf./pcm/front.conf./pcm/surround71.conf./pcm/surround51.conf./pcm/dsnoop.conf./pcm/dpl.conf./pcm/default.conf./pcm/modem.conf./pcm/side.conf./pcm/iec958.conf./pcm/surround41.conf./alsa.conf./cards/aliases.confadb shell进入目标板执行alsa_amixer ,alsa_aplay -l 执行成功,到此alsa工具移植成功,这点看来没有太大难度2.2 打开kernel配置,menuconfig,打开如下配置========================================================Device Drivers ---><*> Sound card support ---> <*> Advanced Linux Sound Architecture ---> USB sound devices ---> <*> USB Audio/MIDI driver========================================================重新编译内核,并烧写到目标板子上2.3 找一个usb声卡,插入usb端口并使用dmesg查看内核日志输出,从dmesg上应该可以看见UAC设备的驱动加载信息ls /dev/snd/*/dev/snd/pcmC0D0c/dev/snd/pcmC0D0p/dev/snd/pcmC1D0c //uac capture/dev/snd/pcmC1D0p //uac play out说明声卡已经加载成功了2.4 使用alsa 工具测试列出设备alsa_aplay -lalsa_aplay 001.wav -D default:CARD=USB Set default:CARD=USB Set是从alsa_aplay -l中列出的设备名可正常听到声音2.5 使用tinyalsa测试# tinyplay -d 1 001.wav //居然提示invalid parameter 只能看代码了external/tinyalsa/tinyplay.c发现主要问题在于tinyplay只打开了设备0多的设备不理,这点真比alsa库差远了,只能山寨一下了,修改如下红色字体部分void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, unsigned int rate, unsigned int bits);int main(int argc, char **argv){ FILE *file; struct wav_header header; unsigned int device = 0; unsigned int card = 0; argv += 2; while (*argv) { if (strcmp(*argv, "-d") == 0) { argv++; device = atoi(*argv); } if (strcmp(*argv, "-c") == 0) { argv++;//命令行多一个 -c 选项,这样可以选择声卡了 card = atoi(*argv); } argv++; } fread(&header, sizeof(struct wav_header), 1, file); if ((header.riff_id != ID_RIFF) || (header.riff_fmt != ID_WAVE) || (header.fmt_id != ID_FMT) || (header.audio_format != FORMAT_PCM) || (header.fmt_sz != 16)) { fprintf(stderr, "Error: '%s' is not a PCM riff/wave file\n", argv[1]); fclose(file); return 1; } play_sample(file,card, device, header.num_channels, header.sample_rate, header.bits_per_sample); fclose(file); return 0;}void play_sample(FILE *file,unsigned int card, unsigned int device, unsigned int channels, unsigned int rate, unsigned int bits){ struct pcm_config config; struct pcm *pcm; char *buffer; int size; int num_read;//config 的配置很重要,tinyalsa直接从wav文件把channels,rate,等读出来并配置进声卡,而像我买的7块钱声卡,功能很弱从windows的设备管理器上看,只支持 16000hz, 16bits,2 channels//所以我只好录一个 16000hz,16bits,2 channel的001.wav文件了//如果config 配置出错,将看到 invalid parameter的错误提示,这点和alsa_aplay的功能 就差远了 config.channels = channels; config.rate = rate; config.period_size = 1024; config.period_count = 4; if (bits == 32) config.format = PCM_FORMAT_S32_LE; else if (bits == 16) config.format = PCM_FORMAT_S16_LE; config.start_threshold = 0; config.stop_threshold = 0; config.silence_threshold = 0; pcm = pcm_open(card, device, PCM_OUT, &config);//原来是pcm = pcm_open(0, device, PCM_OUT, &config); if (!pcm || !pcm_is_ready(pcm)) { fprintf(stderr, "Unable to open PCM device %u (%s)\n", device, pcm_get_error(pcm)); return; } size = pcm_get_buffer_size(pcm);buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %d bytes\n", size); free(buffer); pcm_close(pcm); return; } printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); do { num_read = fread(buffer, 1, size, file); if (num_read > 0) { if (pcm_write(pcm, buffer, num_read)) { fprintf(stderr, "Error playing sample\n"); break; } } } while (num_read > 0); free(buffer); pcm_close(pcm);} 按以上修改完文件后重新编译,并执行# tinyplay -d 1 001.wav 成功从UAC听到声音了,看来集成到android HAL只差一步了,因为android HAL也是用的tinyalsa库的2.6 修改audio_hw(android声音的HAL层)代码,将UAC声卡接入到android4.0中去HAL层代码位置:hardware/targetboard目标板/audio/audio_hw.c找到 pcm_open(card, port, PCM_OUT,&config); 的地方把相应的config配置成和tinyplay.c里正确的配置像我的声卡就是16000hz 16bits,2 channels重新编译 生成 audio.primary.$(TARGET_BOARD_PLATFORM).so 并更新到目标板上重新 启动 mediaserver进程 (kill掉这个进程,就会自动重启,并重新加载audio.primary.xxx.so库)使用android音乐播放,播放mp3,OK可成功听到声音了使用android录音机, 可成功录音了 |