两个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. python 时间合集 一

    **以下内容均为我个人的理解,如果发现错误或者疑问可以联系我共同探讨**#### python中4种时间表示形式:1.格式化时间字符串 2.时间戳 3.时间元祖 4.时间对象- string_time ...

  2. 浅谈Git与SVN的使用感受

    作为版本号控制工作.两者的做大的差别应该在于:Git属于分布式版本号控制工具,而SVN属于集中式的版本号控制工具.分布式的优点是什么呢?举个样例来说.当你在火车上离线状态下编程工作,在某个阶段会须要先 ...

  3. ubuntu14中 memcached安装与使用

    第一步,先安装lib-event 下载lib-event  的包http://libevent.org/ 下载完之后,解压安装 ./configure –prefix=/usr (或 ./config ...

  4. Invalid property 'annotatedClasses' of bean class

    Invalid property 'annotatedClasses' of bean class 在整合Hibernate和Spring时出现,Invalid property 'annotated ...

  5. cocos2d-x中六种持续性动作

    持续性动作: (一) 位置变化动作 Move by to Jump by to (二) 属性变化动作 Scale by to Rotate by to Fade in out to Tint to b ...

  6. 为easyUI的dataGrid加入自己的查询框

    dataGrid作为easyUI的一个核心组件,其功能上是非常强大的. 可是外观上似乎就有点差强人意了,首先说一下我对dataGrid外观的2点感受 1.图标不好看,且尺寸非常小(16x16)-- 关 ...

  7. Linux字符界面安装图形界面XWindow

    https://jingyan.baidu.com/article/219f4bf790f4c7de442d3825.html

  8. 微服务实战(一):微服务架构的优势与不足 - DockOne.io

    原文:微服务实战(一):微服务架构的优势与不足 - DockOne.io [编者的话]本文来自Nginx官方博客,是微服务系列文章的第一篇,主要探讨了传统的单体式应用的不足,以及微服务架构的优势与挑战 ...

  9. ZJOI2002昂贵的聘礼题解

    http://codevs.cn/problem/1324/ 题目大意 一个部落,你能够和社会地位等级的极差不大于M的全部人交易.你能够拿金币直接从一个人手里买东西,也能够从别人那里买到那个人想要的东 ...

  10. ganglia错误解决

    1.      运行: 解决: 这时重新启动gmetad,输入命令: service gmetad stop 显示: Shutting down GANGLIA gmetad:             ...