Android 语音遥控器的整体分析-HAL层的AudioFlinger
2015-07-14 22:16
701 查看
上篇说到语音部分最后会通过AudioFlinger来操作HAL层。
一、首先我们看下硬件接口层的接口(奇怪为什么只有Audio的hardwareinterface):
(1)hardware\libhardware_legacy\include\hardware_legacy\AudioHardwareInterface.h
其中定义了AudioStreamOut和AudioStreamIn,二者被AudioHardwareInterface类中的openOutputStream和openInputStream操作以对硬件音频的输入和输出进行管理。
类中定义的都是抽象函数,具体要实现Audio系统时去实现。
(2)hardware\libhardware_legacy\include\hardware_legacy\AudioPolicyInterface.h
这里定义了Android的策略类。
二、然后看下HAL层的实现
Android的HAL中提供三种示例:AudioHardwareStub AudioDumpInterface AudioHardwareGeneric这三种各自代表一种Audio硬件抽象层的实现
(1)AudioHardwareStub是一个空实现,不表述,可以自己去看代码
(2)AudioDumpInterface是一个用文件来模拟输入输出的示例
这个要先介绍AudioDumpInterface:
分析代码是上面的类关系,可以知道,在AudioDumpInterface中是new了AudioStreamInDump和AudioStreamOutDump两个对象来进行输入输出操作。
其中的AudioStreamInDump.write会生成一个PCM文件,而read函数能够将一个一个指定的Audio文件读入,比如Android5.0中是打开一个/sdcard/music/目录下的.wav文件
怎么命名参见程序实现:
3.1先在构造函数中指定了一个音频设备节点:kAudioDeviceName = "/dev/eac"
好了,现在整个Android主机端的实现方式就分析完了。
实际使用的时候,可以由Android层的系统工程师和驱动工程师配合工作,驱动工程师完成音频驱动后,给出音频数据的节点,Android系统层去对这个设备节点进行读写。或者与其他网络模块比如蓝牙模块工作的时候,可以不通过内核。遥控器端将数据加密,编码压缩后,通过蓝牙部分接受裸数据,然后蓝牙模块通过socket传给语音模块进行解码,然后给上层使用。
后面会进行音频编解码以及蓝牙无线传输音频这两个部分的总结。
一、首先我们看下硬件接口层的接口(奇怪为什么只有Audio的hardwareinterface):
(1)hardware\libhardware_legacy\include\hardware_legacy\AudioHardwareInterface.h
其中定义了AudioStreamOut和AudioStreamIn,二者被AudioHardwareInterface类中的openOutputStream和openInputStream操作以对硬件音频的输入和输出进行管理。
类中定义的都是抽象函数,具体要实现Audio系统时去实现。
(2)hardware\libhardware_legacy\include\hardware_legacy\AudioPolicyInterface.h
这里定义了Android的策略类。
二、然后看下HAL层的实现
Android的HAL中提供三种示例:AudioHardwareStub AudioDumpInterface AudioHardwareGeneric这三种各自代表一种Audio硬件抽象层的实现
(1)AudioHardwareStub是一个空实现,不表述,可以自己去看代码
(2)AudioDumpInterface是一个用文件来模拟输入输出的示例
这个要先介绍AudioDumpInterface:
分析代码是上面的类关系,可以知道,在AudioDumpInterface中是new了AudioStreamInDump和AudioStreamOutDump两个对象来进行输入输出操作。
其中的AudioStreamInDump.write会生成一个PCM文件,而read函数能够将一个一个指定的Audio文件读入,比如Android5.0中是打开一个/sdcard/music/目录下的.wav文件
怎么命名参见程序实现:
ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) { ssize_t ret; if (mFinalStream) { ret = mFinalStream->read(buffer, bytes); if(!mFile) { if (mInterface->fileName() != "") { char name[255]; sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); mFile = fopen(name, "wb"); ALOGV("Opening input dump file %s, fh %p", name, mFile); } } if (mFile) { fwrite(buffer, bytes, 1, mFile); } } else { usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000); ret = bytes; if(!mFile) { char name[255]; strcpy(name, "/sdcard/music/sine440"); if (channels() == AudioSystem::CHANNEL_IN_MONO) { strcat(name, "_mo"); } else { strcat(name, "_st"); } if (format() == AudioSystem::PCM_16_BIT) { strcat(name, "_16b"); } else { strcat(name, "_8b"); } if (sampleRate() < 16000) { strcat(name, "_8k"); } else if (sampleRate() < 32000) { strcat(name, "_22k"); } else if (sampleRate() < 48000) { strcat(name, "_44k"); } else { strcat(name, "_48k"); } strcat(name, ".wav"); mFile = fopen(name, "rb"); ALOGV("Opening input read file %s, fh %p", name, mFile); if (mFile) { fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); } } if (mFile) { ssize_t bytesRead = fread(buffer, bytes, 1, mFile); if (bytesRead >=0 && bytesRead < bytes) { fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile); } } } return ret; }(3)AudioHardwareGeneric是一个真正和硬件交互的实现
3.1先在构造函数中指定了一个音频设备节点:kAudioDeviceName = "/dev/eac"
AudioHardwareGeneric::AudioHardwareGeneric() : mOutput(0), mInput(0), mFd(-1), mMicMute(false) { mFd = ::open(kAudioDeviceName, O_RDWR); }3.2然后在openInputStream和openOutStream中创建输入输出对象的时候会将文件句柄传进去,
// create new output stream AudioStreamInGeneric* in = new AudioStreamInGeneric(); status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);3.3最后就是在write和read中去读写文件节点了。
ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes) { Mutex::Autolock _l(mLock); return ssize_t(::write(mFd, buffer, bytes)); }
好了,现在整个Android主机端的实现方式就分析完了。
实际使用的时候,可以由Android层的系统工程师和驱动工程师配合工作,驱动工程师完成音频驱动后,给出音频数据的节点,Android系统层去对这个设备节点进行读写。或者与其他网络模块比如蓝牙模块工作的时候,可以不通过内核。遥控器端将数据加密,编码压缩后,通过蓝牙部分接受裸数据,然后蓝牙模块通过socket传给语音模块进行解码,然后给上层使用。
后面会进行音频编解码以及蓝牙无线传输音频这两个部分的总结。
相关文章推荐
- android入门学习-java数据类型和运算符
- Android突击:Fragment
- Android:Layout_weight的深刻理解
- 显示意图和隐式意图
- 打开一个已经写好的Android studio工程的方法
- Android获取系统外置存储卡路径的方法
- Android开发秘籍学习笔记(十一)
- Android资源布局文件命名规范
- Android 模拟器错误PANIC: Could not open XXX
- android shape的使用
- android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据
- Android Studio 如何通过gradle实现同一套代码的开发不同特性的apk
- android layout parser
- 005-android studio的安装
- 【Android】AudioRecord--录音并将 PCM文件转为WAV
- AndroidManifest配置文件简介
- android开发步步为营之66:android图片选取
- AndroidStudio学习(一)--区分版本
- 2.如何创建Activity,启动下一个activity
- Android MediaScanner源代码解析