两个USB设备各自是:

A:USB摄像头带录音功能,但不带放音功能。

B:USB无线耳机是使用USB转2.4G的无线耳机。





详细现象:

1, A,B两者同一时候插上机顶盒,并开机进入android,此时去播放音乐或电影,声音是从HDMI出来的,并不是从无线耳机出来。

此时又一次插拔一下2.4G无线耳机,声音就会从耳机中出来。

2, 机顶盒上电。进入android系统,然后播放音乐或电影,此时声音从HDMI中出来。这个时候接上USB摄像头,声音还是从HDMI出来。

再接上无线耳机。这时候声音却还是从HDMI中出来,此时应该要从耳机出来。又一次插拔一下耳机就恢复正常了。





总结现象,基本能够得出一个结论:开机后。先插上USB摄像头再插上2.4G耳麦,声音并不会从耳机出来,仅仅有又一次插拔一次USB耳麦后才会正常。





从现象能够看出,出现异常的原因是音频系统没有从摄像头切换到麦克风。





细致查看日志,发现正常时会有一段以下的打印。不正常时并没有。

V/AudioService( 1582): Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = 1

I/AudioPolicyManagerBase( 1059): setDeviceConnectionState() device: 800, state 1, address 

I/AudioPolicyManagerBase( 1059): [setDeviceConnectionState : 245] device already connected: 16777216

V/WiredAccessoryObserver( 1582): Headset UEVENT: {SUBSYSTEM=switch, SWITCH_STATE=1, DEVPATH=/devices/virtual/switch/usb_audio, SEQNUM=1271, ACTION=change, SWITCH_NAME=usb_audio}

V/WiredAccessoryObserver( 1582): newState = 4, headsetState = 4,mHeadsetState = 0

V/WiredAccessoryObserver( 1582): Intent.ACTION_USB_HEADSET_PLUG: state: 1 name: usb_audio





从日志能够看出,AudioService收到了ACTION_USB_ANLG_HEADSET_PLUG广播消息。才干正常。在源代码中搜索发出ACTION_USB_ANLG_HEADSET_PLUG广播的地方,查得在WiredAccessoryObserver.java文件里sendIntent()函数调用了。

private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {

        .......

                    intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);

                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);

                    intent.putExtra("state", state);

                    intent.putExtra("name", headsetName);

                    ActivityManagerNative.broadcastStickyIntent(intent, null);

        .......

    }

此函数被sendIntents()调用,接着被mHandler的handleMessage()调用。

    private final Handler mHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            sendIntents(msg.arg1, msg.arg2, (String)msg.obj);

            mWakeLock.release();

        }

    };

接着被update()调用

    private synchronized final void update(String newName, int newState) {

        ........

        mHandler.sendMessageDelayed(mHandler.obtainMessage(0,

                                                           mHeadsetState,

                                                           mPrevHeadsetState,

                                                           mHeadsetName),

                                    delay);

    }

接着被updateState()调用。然后被onUEvent()调用。

onUEvent()重载了UEventObserver.java中的相应函数。细致查看该文件源代码能够得知当中有个线程会读取netlink消息。并由相应的Observer去处理。

在run()函数中增加打印日志的函数。将uevent打印出来。

public void run() {

            native_setup();





            byte[] buffer = new byte[1024];

            int len;

            while (true) {

                len = next_event(buffer);

                if (len > 0) {

                    String bufferStr = new String(buffer, 0, len);  // easier to search a String

                    Log.d (TAG,"uevent:"+bufferStr);

                    synchronized (mObservers) {

                        for (int i = 0; i < mObservers.size(); i += 2) {

                            if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {

                                ((UEventObserver)mObservers.get(i+1))

                                        .onUEvent(new UEvent(bufferStr));

                            }

                        }

                    }

                }

            }

        }





改完后编译frameworks/base。将core.jar文件push到机顶盒进行測试。当正常时会有例如以下打印

D/UEventObserver( 1582): uevent:change@/devices/virtual/switch/usb_audio��ACTION=change��DEVPATH=/devices/virtual/switch/usb_audio��SUBSYSTEM=switch��SWITCH_NAME=usb_audio��SWITCH_STATE=1��SEQNUM=1271��

V/AudioService( 1582): Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = 1

I/AudioPolicyManagerBase( 1059): setDeviceConnectionState() device: 800, state 1, address 

I/AudioPolicyManagerBase( 1059): [setDeviceConnectionState : 245] device already connected: 16777216

V/WiredAccessoryObserver( 1582): Headset UEVENT: {SUBSYSTEM=switch, SWITCH_STATE=1, DEVPATH=/devices/virtual/switch/usb_audio, SEQNUM=1271, ACTION=change, SWITCH_NAME=usb_audio}

V/WiredAccessoryObserver( 1582): newState = 4, headsetState = 4,mHeadsetState = 0

V/WiredAccessoryObserver( 1582): Intent.ACTION_USB_HEADSET_PLUG: state: 1 name: usb_audio





从日志能够知道,不正常的原因在于kernel并没有发出uevent。google去查uevent机制,了解到change这个ACTION由KOBJ_CHANGE来控制。

依据uevent中SWITCH_NAME和SWITCH_STATE对kernel/下进行搜索,得到drivers/switch/switch_class.c文件。同一时候也依据KOBJ_CHANGE对drivers下进行搜索。也发现switch/switch_class.c文件,推測这个文件是关键。在switch_set_state()函数中增加打印,又一次编译内核,执行,查看日志,果然发现都调了这里。

void switch_set_state(struct switch_dev *sdev, int state)

{

    ......

    if (sdev->state != state) {

        sdev->state = state;

        ......

    }

    ......

}





继续搜索调用switch_set_state()的地方,发如今sound/usb/card.c的snd_usb_audio_probe()函数中调用了。

static void *snd_usb_audio_probe(struct usb_device *dev,

                 struct usb_interface *intf,

                 const struct usb_device_id *usb_id)

{

    ......

    //switch_set_state(&sdev, STATE_DISCONNECTED);

    switch_set_state(&sdev, STATE_CONNECTED);

    ......

}





能够知道多个usb音频设备通过switch进行管理。一个时刻仅仅使用一个。

当带录音功能的usb摄像头插上时。sdev的状态改为已连接。

当usb耳麦接上后,相同会调用switch_set_state(),但由于先前已经连了一个usb音频设备。sdev->state已经变为1,不再继续发消息。于是我凝视掉推断语句:if (sdev->state != state) 。再次进行測试,发现uevent已经上报了,但声音仍然没有从usb耳麦中出来。

继续回到Android层,查看WiredAccessoryObserver.java中update()函数

    private synchronized final void update(String newName, int newState) {

        ......

        if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+","

            + "mHeadsetState = "+mHeadsetState);

        if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {

            Log.e(TAG, "unsetting h2w flag");

            h2wStateChange = false;

        }

        // - c: 0 usb headset to 1 usb headset

        // - d: 1 usb headset to 0 usb headset

        if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {

            Log.e(TAG, "unsetting usb flag");

            usbStateChange = false;

        }

        if (!h2wStateChange && !usbStateChange) {

            Log.e(TAG, "invalid transition, returning ...");

            return;

        }

        .......

}

分析代码可知,因为上报的消息跟上次一样,此函数并未继续运行。

为了简单起见,我想直接在内核载入新的usb音频设备时先将switch断开原来的。再连接新的。于是在snd_usb_audio_probe()函数中,先运行switch_set_state(&sdev, STATE_DISCONNECTED);欺骗系统switch已经断开。然后再运行switch_set_state(&sdev, STATE_CONNECTED);





编译,烧录,測试后发现一切都正常了。录音与放音都正常。

当USB耳麦连接时用耳麦进行录音和放音。

当USB耳麦不在时用USB摄像头进行录音,由HDMI进行放音。





对这个结果感到非常意外。意想之中的状况应该是始终使用后插上的那个设备。查看日志后得知,由摄像头没有放音功能,在open这个设备进行放音的时候会失败。于是就会使用下一个设备,直到找到能放音的设备,查看日志发现这是alsa-lib这么设计的。为何录音也总是优先使用USB耳麦,没有深究,应该也是alsa-lib完毕了。

海思hi3716c机顶盒接usb摄像头和usb无线耳机时,无线耳机有时没有声音的更多相关文章

  1. 2.7 usb摄像头之usb摄像头描述符打印

    学习目标:参考lsusb源码,打印USB摄像头的设备描述符.配置描述符.接口联合描述符.端点描述符: 一.lsusb命令和源码 使用命令lsusb可以看看设备的id,并执行 # lsusb -v -d ...

  2. RTSP流和USB摄像头转MJPEG使用VLC

    测试环境: 系统: Ubuntu14.04 LTS Desktop 设备:海康IP摄像头和USB摄像头 1.需要先安装vlc包,命令行运行 sudo apt-get update sudo apt-g ...

  3. 主流芯片解决方案Ambarella的高清网络摄像机、德州仪器和控制海思

    (本文由四川艾普作为数码科技有限公司 苏斌.范清华 收集) 高清网络视频监控发展到今天.正的高清时代.诸多有实力的高清摄像机厂家的产品线也逐渐完好起来,高清网络视频监控的配套产品有更加丰富和成熟.与此 ...

  4. 海思HI3518EV200+AR0130开发板DIY——前篇

    海思HI3518EV200+AR0130开发板DIY 今天开始要围绕这个项目学习了(还是得从C开始学 ) 缘起(这段主要水废话)相关开发资料 →_→ 原理图设计 原理图整体框架 一.电源部分 HI35 ...

  5. [转帖]IPC网络高清摄像机基础知识1(IPC芯片市场分析以及“搅局者”华为海思 “来自2013年”)

    IPC网络高清摄像机基础知识1(IPC芯片市场分析以及“搅局者”华为海思 “来自2013年”) 2016-06-02 14:23:49 Times_poem 阅读数 9734更多 分类专栏: IPC网 ...

  6. Hi3516开发笔记(一):海思HI3516DV300芯片介绍,入手开发板以及Demo测试

    前言   目前主流国产芯片为RV11XX.RK33XX.Hi35XX系列,本系列开启Hi3516系列的开发教程.   Hi3516DV300芯片介绍   Hi3516DV300为专业行Smart IP ...

  7. 海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器)

    海思3516系列芯片SPI速率慢问题深入分析与优化(基于PL022 SPI 控制器) 我在某个海思主控的项目中需要使用SPI接口来驱动一块液晶屏,液晶屏主控为 st7789,分辨率 240x240,图 ...

  8. 海思h264解码库

    海思的dll,解码h264  解码后转出yuv12 dll自己百度下载  hi_h264dec.dll   hi_h264dec_w.dll   调用方法: if (H264Dec.Hi264DecA ...

  9. 海思H264解码库 hi_h264dec_w.dll 水印问题

    上一篇   海思h264解码库 , 实现了H264帧的简单解码,但更换相机后,出现了解码视频中央出现水印的问题,水印如下图 查找网络,基本就这一篇相关的,还没给出好的解决办法. http://bbs. ...

随机推荐

  1. 前端项目中常用es6知识总结 -- let、const及数据类型延伸

    项目开发中一些常用的es6知识,主要是为以后分享小程序开发.node+koa项目开发以及vueSSR(vue服务端渲染)做个前置铺垫. 项目开发常用es6介绍 1.块级作用域 let const  2 ...

  2. 【Codeforces Round #451 (Div. 2) B】Proper Nutrition

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 可以直接一层循环枚举. 也可以像我这样用一个数组来存y*b有哪些. 当然.感觉这样做写麻烦了.. [代码] /* 1.Shoud i ...

  3. [Python] Object spread operator in Python

    In JS, we have object spread opreator: const x = { a: '1', b: '2' } const y = { c: '3', d: '4' } con ...

  4. 转 openssl 建立服务器证书

    openssl 建立服务器证书 ##  1,建立目录和文件     set path=D:/openssl/bin     D:     cd D:/openssl/conf/     ren ope ...

  5. Solr 读数据流程

    Solr 读数据流程: 1.用户提供搜索关键词,也就是搜索语句,需要经过分词器处理以及语言处理. 2.对处理之后的关键词,搜索索引找出对应Document 即记录. 3.用户根据需要从找到的Docum ...

  6. 洛谷——P1096 Hanoi双塔问题

    https://www.luogu.org/problem/show?pid=1096 题目描述 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个 ...

  7. Mahjong tree (hdu 5379 dfs)

    Mahjong tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot ...

  8. stm32的ADC左右对齐

  9. 【AtCoder ABC 075 D】Axis-Parallel Rectangle

    [链接] 我是链接,点我呀:) [题意] 让你找到一个各边和坐标轴平行的矩形.使得这个矩形包含至少K个点. 且这个矩形的面积最小. [题解] 把所有的"关键点""都找出来 ...

  10. 【BZOJ 2119】股市的预测

    [链接]h在这里写链接 [题意]     给你一个长度为n的数组a[]     设b[i] = a[i+1]-a[i];     然后让你在b[i]里面找ABA的形式.     这里B的长度要求为m; ...