日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

海思hi3716c机顶盒接usb摄像头和usb无线耳机时,无线耳机有时没有声音

發布時間:2024/1/8 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 海思hi3716c机顶盒接usb摄像头和usb无线耳机时,无线耳机有时没有声音 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
兩個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无线耳机时,无线耳机有时没有声音的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。