1. 背景
一个需求 : 要将手机上的画面和音频 投屏 到 车机的Android屏幕上。
车机有一个支持OTG的USB-A口,由于设备有限,我们有一个USB-A转HDMI转接口,一跟HDMI线,一个USB-C的拓展坞 (包括HDMI口,两个USB-A口,一个网口),我们将这几根线接在一起,成功将手机和车机连在了一起。
接着,我们在网上找到了一个 jiangdongguo/AndroidUSBCamera ,我们使用Android Studio打开编译安装到车机,并将车机的从切换为,这个时候,会弹出打开USB摄像头的弹框,我们点击同意,就可以看到手机上的画面显示到车机上了。
使用yorkZJC/UvcCameraDemo这个库也可以成功
和这个相关的所有的项目,基本都是基于 saki4510t/UVCCamera 这个开源项目来改的
那么,我们有了以下两个疑问
- 是如何读取到手机上的画面,显示到车机上的 ?
- 为什么只有画面,没有声音 ?
2. 是如何读取到手机上的画面,显示到车机上的 ?
带着这个疑问,看了下的代码。
原来,现在所有主流操作系统都已提供UVC设备驱动,因此符合UVC规格的硬件设备在不需要安装任何的驱动程序下即可在主机中正常使用。使用UVC技术的包括摄像头、数码相机、类比影像转换器、电视棒及静态影像相机等设备。
UVC全称,即 USB视频类,是一种为USB视频捕获设备定义的协议标准。
是Microsoft与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标准,已成为USB org标准之一。
而项目中,对USB Camera (UVC设备)的使用和视频数据采集进行了高度封装。
通过方法,会调用到方法
最终调用到方法
这时候,我们就可以预览到手机上的画面了。
3. 为什么只有画面,没有声音 ?
这个时候,我们可以发现,车机上只显示出了画面,没有声音播放的。
看了下里的代码,当点击了录像按钮,调用方法,回调里type==0,表示是的,但实际测试中,永远都只会收到的情况,而收不到的情况。
在Github 的issue上,我也看到了这个问题 : 可以支持USB的音频输入吗?
看上去大家也有同样的问题
这时候,找到的USB摄像头这个应用市场上的app,却是可以在投屏的同时,播放出声音的。
反编译了这个apk,可以看到它的so里面,有一个,看上去就是用来处理音频的
我们在网上查找了一下这个so,得知
libusb是一底层的API,可以跨平台实现。
基于libusb可以获取到usb mac的pcm流数据,从而可以读取到音频。
libusb库使用C语言编写,在Android中使用该库需要用到JNI技术。
github : libusb/libusb:用于访问 USB 设备的跨平台库
然后,我们找到了一个的库 jim0608/android_usbaudio: 基于libusb,实现无驱动获取USBAudio
当然,这个库本身是有点问题的,但大体思路可以参考
由于库使用到了JNI,所以我们需要先配置好NDK,其对应版本为
代码中有一个,当把视频线插到车机的USB-A口的时候,
onAttach方法就会被调用,这个时候会调用去请求权限。
当连接上的时候,会记录下和
接着,我们就可以去初始化音频了
然后再开始捕获
这个时候,我们在手机端播放音乐,车机的音响就会输出声音了。
播放声音其实是用过来播放的
在Android中,播放声音可以用MediaPlayer和AudioTrack
区别如下
这里,有个采样率的问题,得找到合适的采样率,否则会有播放声音不清晰、白噪音等情况。
结合在一起使用
将和结合起来,就可以实现既播放视频,同时播放出声音的效果了。
4. AudioTrack基础的使用
最后,介绍下AudioTrack基础的使用
AudioTrack 的构造方法
streamType 音频流类型
sampleRateInHz 采样率
播放的音频每秒钟会有多少次采样,一般为44100,最好是通过代码动态获取采样率,其他常见的采样率还有
如果发现播放后声音不清晰、白噪音等情况,可以调整这个采样率值
channelConfig 声道数
单声道,双声道,建议选择单声道
audioFormat 数据位宽
只支持和两种,后者支持所有Android手机
bufferSizeInBytes 音频缓冲区大小
建议使用这个方法获取
mode 播放模式
有两种播放模式:
- MODE_STATIC : 一次性将所有数据都写入播放缓冲区中,简单高效,一般用于铃声,系统提醒音,内存比较小的。
- MODE_STREAM : 需要按照一定的时间间隔,不断的写入音频数据,理论上它可以应用于任何音频播放的场景。
AudioTrack 播放示例
初始化
写入数据
停止播放,销毁资源
5.本文代码下载
本文Demo下载地址 : Android UVC USBCamera投屏Demo