rk3399 android 11 音频设备优先级管理

本文介绍了如何在Android系统的Settings应用中增加设备管理选项,允许用户选择音频输出设备(如扬声器或USB音箱)和输入设备(内置麦克风或USB麦克风),并通过系统属性文件进行设备状态的动态管理。还展示了如何通过AudioManager服务调整USB耳机功能和修改音频策略,涉及权限管理及硬件级别的音频控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

功能:根据需求选择音频音频设备的输入输出

1.在Settings中增加设备管理选项

packages/apps/Settings/src/com/android/settings/notification/AudioManagerReceiver.java

​
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.settings.notification;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.FileUtils;
import android.provider.Settings;

/*
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
*/
import androidx.preference.SwitchPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.util.Log;

import android.os.SystemProperties;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.DataOutputStream;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
//import com.android.settings.dashboard.SummaryLoader;

import java.util.List;


public  class AudioManagerReceiver extends BroadcastReceiver {
		private static final String TAG = "AudioManagerReceiver";


        @Override
        public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
                 Log.d(TAG,"AudioManagerReceiver---max-chen");
         			                       
				
				String audioOutDevice = getAudioOutDeviceState();
				if(audioOutDevice.equals("SPEAKER")){
				}else if(audioOutDevice.equals("USB SPEAKER")){
				}

				String audioInDevice = getAudioInDeviceState();
			
				if(audioInDevice.equals("BuildIn Mic")){
				}else if(audioInDevice.equals("USB Mic")){
				}
				
			}
        }

		private  static String getAudioOutDeviceState(){
			return SystemProperties.get("persist.current.audio.output.device","SPEAKER");	
		}

		private  static String getAudioInDeviceState(){
			return SystemProperties.get("persist.current.audio.input.device","BuildIn Mic");	
		}
 
}

​
waysion@waysion:/home/sdb/workspace/rk3399_android11.0_sdk/packages/apps/Settings$ git diff
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 16b29dc..fc5985e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -107,6 +107,10 @@
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION" />
 
+    <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
+
     <application android:label="@string/settings_label"
             android:icon="@drawable/ic_launcher_settings"
             android:theme="@style/Theme.Settings"
@@ -3291,6 +3295,13 @@
             android:permission="android.permission.MANAGE_SLICE_PERMISSIONS"
             android:exported="true" />
 
+        <receiver 
+            android:name=".notification.AudioManagerReceiver" >
+            <intent-filter android:priority="1000" >
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
         <!-- Couldn't be triggered from outside of settings. Statsd can trigger it because we send
              PendingIntent to it-->
         <receiver android:name=".fuelgauge.batterytip.AnomalyDetectionReceiver"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 035feed..f06d42b 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1602,4 +1602,26 @@
         <item>2</item>
         <item>3</item>
     </string-array>
+
+    <!-- AUDIO -->
+    <string-array name="audio_device_output_entries">
+    <item>SPEAKER</item>
+    <item>USB SPEAKER</item>
+    </string-array>
+
+    <string-array name="audio_device_output_values">
+    <item>SPEAKER</item>
+    <item>USB SPEAKER</item>
+    </string-array>
+
+    <string-array name="audio_device_input_entries">
+    <item>BuildIn Mic</item>
+    <item>USB Mic</item>
+    </string-array>
+
+    <string-array name="audio_device_input_values">
+    <item>BuildIn Mic</item>
+    <item>USB Mic</item>
+    </string-array>
+
 </resources>

diff --git a/res/values/strings.xml b/res/values/strings.xml
index 692ab2c..0de019d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7909,6 +7909,11 @@
         <item quantity="other"><xliff:g id="on_count" example="10">%d</xliff:g> schedules set</item>
     </plurals>
 
+    <!-- Audio Manager -->
+    <string name="audio_device_manager_preference_title">Audio Device Manager</string>
+    <string name="audio_output_device_manager_title">Audio OutPut Device</string>
+    <string name="audio_input_device_manager_title">Audio Input Device</string>
+
     <!-- Sound: Title for the Do not Disturb option and associated settings page. [CHAR LIMIT=50]-->
     <string name="zen_mode_settings_title">Do Not Disturb</string>
 
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index fc5c3e2..494174e 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -210,6 +210,30 @@
           android:summary="%s"/>
     </PreferenceCategory>
 
+    <PreferenceCategory
+       android:key="audio_device_manager"
+        android:title="@string/audio_device_manager_preference_title"
+        android:order="-50">
+       <ListPreference
+            android:key="audio_output_device_manager"
+            android:title="@string/audio_output_device_manager_title"
+            android:summary="audio_output_device_summary"
+            android:entries="@array/audio_device_output_entries"
+            android:entryValues="@array/audio_device_output_values" 
+           android:defaultValue="SPEAKER"
+           />
+
+       <ListPreference
+          android:key="audio_input_device_manager"
+          android:title="@string/audio_input_device_manager_title"
+          android:summary="audio_input_device_summary"
+          android:entries="@array/audio_device_input_entries"
+          android:entryValues="@array/audio_device_input_values"
+          android:defaultValue="BuildIn Mic"
+       />
+
+    </PreferenceCategory>
+
     <com.android.settings.widget.WorkOnlyCategory
         android:key="sound_work_settings_section"
         android:title="@string/sound_work_settings"
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index b088fe3..6dd3010 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -19,18 +19,20 @@ package com.android.settings.notification;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.SystemProperties;
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
 import android.preference.SeekBarVolumizer;
+import android.preference.Preference.OnPreferenceChangeListener;
 import android.text.TextUtils;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
-
 import com.android.settings.R;
 import com.android.settings.RingtonePreference;
 import com.android.settings.core.OnActivityResultListener;
@@ -44,18 +46,25 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.widget.UpdatableListPreferenceDialogFragment;
 
+import android.media.AudioManager;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import android.util.Log;
 
 @SearchIndexable
-public class SoundSettings extends DashboardFragment implements OnActivityResultListener {
+public class SoundSettings extends DashboardFragment implements OnActivityResultListener, Preference.OnPreferenceChangeListener {
     private static final String TAG = "SoundSettings";
 
     private static final String SELECTED_PREFERENCE_KEY = "selected_preference";
     private static final int REQUEST_CODE = 200;
     private static final int SAMPLE_CUTOFF = 2000;  // manually cap sample playback at 2 seconds
 
+    private static final String KEY_AUDIO_OUTPUT_DEVICE = "audio_output_device_manager";
+    private static final String KEY_AUDIO_INPUT_DEVICE = "audio_input_device_manager";
+    private static Context mContext;
+
+    private  AudioManager am;
     @VisibleForTesting
     static final int STOP_SAMPLE = 1;
 
@@ -78,6 +87,9 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
     private String mHfpOutputControllerKey;
     private String mVibrationPreferencesKey = "vibration_preference_screen";
 
+    private ListPreference mAudioOutputDevicePreference = null;
+    private ListPreference mAudioInputDevicePreference = null;
+
     @Override
     public int getMetricsCategory() {
         return SettingsEnums.SOUND;
@@ -97,6 +109,26 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
                             .findFragmentByTag(TAG);
             mDialogFragment = dialogFragment;
         }
+       mContext = getContext();
+
+       am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+       if(mAudioOutputDevicePreference==null && mAudioInputDevicePreference==null){
+               mAudioOutputDevicePreference = (ListPreference) findPreference(KEY_AUDIO_OUTPUT_DEVICE);
+               mAudioInputDevicePreference = (ListPreference) findPreference(KEY_AUDIO_INPUT_DEVICE);
+               
+               mAudioOutputDevicePreference.setOnPreferenceChangeListener(this);
+                mAudioInputDevicePreference.setOnPreferenceChangeListener(this);
+               String audioOutDevice = getAudioOutDeviceState();
+               Log.d("max.chen","------audioOutDevice:"+audioOutDevice);
+               mAudioOutputDevicePreference.setValue(audioOutDevice);
+               mAudioOutputDevicePreference.setSummary(audioOutDevice);
+       
+               String audioInDevice = getAudioInDeviceState();
+               Log.d("max.chen","------audioOutDevice:"+audioInDevice);
+               mAudioInputDevicePreference.setValue(audioInDevice);
+               mAudioInputDevicePreference.setSummary(audioInDevice);
+       }
+
     }
 
     @Override
@@ -110,6 +142,51 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
         mVolumeCallback.stopSample();
     }
 
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object value) {
+       // TODO Auto-generated method stub
+         Log.d("max.chen", "max.chen preference = " + preference + " value = " + value);
+
+               //把preference这个Preference强制转化为ListPreference类型
+               ListPreference listPreference=(ListPreference)preference;
+               //获取ListPreference中的实体内容
+               CharSequence[] entries=listPreference.getEntries();
+               //获取ListPreference中的实体内容的下标值
+               int index=listPreference.findIndexOfValue((String)value);
+               //把listPreference中的摘要显示为当前ListPreference的实体内容中选择的那个项目
+               listPreference.setSummary(entries[index]);
+
+               if(listPreference == mAudioOutputDevicePreference){
+                       SystemProperties.set("persist.vendor.audio.output.device",(String)value);
+                      if(String.valueOf(value).contains("USB")){
+                               am.setParameters("saintway_usb_headset_enable=true");
+                       }else{
+                                       am.setParameters("saintway_usb_headset_enable=false");
+                       }
+               }else if(listPreference == mAudioInputDevicePreference){
+                       SystemProperties.set("persist.vendor.audio.input.device",(String)value);
+                          if(String.valueOf(value).contains("USB")){
+                                am.setParameters("saintway_usb_headset_enable=true");
+                        }else{
+                                am.setParameters("saintway_usb_headset_enable=false");
+                        }
+               }
+        
+
+       return true;
+    }
+
+
+       private   String getAudioOutDeviceState(){
+               return SystemProperties.get("persist.vendor.audio.output.device","SPEAKER");    
+       }
+
+       private   String getAudioInDeviceState(){
+               return SystemProperties.get("persist.vendor.audio.input.device","BuildIn Mic"); 
+       }
+
+
     @Override
     public boolean onPreferenceTreeClick(Preference preference) {
         if (preference instanceof RingtonePreference) {

2.frameworks/av/media/utils/ServiceUtilities.cpp中开放APP更改音频的权限 

diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index cc64f9f..ed2ecd2 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -196,12 +196,13 @@ bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid)
 
 bool settingsAllowed() {
     // given this is a permission check, could this be isAudioServerOrRootUid()?
-    if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
-    static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
+    //if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
+    //static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
-    bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
-    if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
-    return ok;
+    //bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
+    //if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+    //return ok;
+    return true;
 }

3.修改音频策略

 frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp

+#pragma clang diagnostic ignored "-Wunused-parameter"
+#include <cutils/properties.h>


DeviceVector Engine::getDevicesForStrategyInt函数中修改输出

       DeviceVector devices2;
       char value[PROPERTY_VALUE_MAX] = "";
       char value_usb[PROPERTY_VALUE_MAX] = "";

       property_get("persist.system.usb.headset_state",value, "unknow");
       property_get("persist.vendor.audio.output.device",value_usb,"unknow");

       if(devices2.isEmpty()){
               devices2 = availableOutputDevices.getFirstDevicesFromTypes({
       }

        if(/*!(strcmp(value,"on")&&*/!strcmp(value_usb,"USB SPEAKER")){
                 if(devices2.isEmpty()){
                        devices2 = availableOutputDevices.getFirstDevicesFromTypes({
                        AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_USB_DEVICE});
                  }
        }

       if(devices2.isEmpty()){
               devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
       }
       if(devices2.isEmpty()){
               devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
       }

       if(devices2.isEmpty()){
               devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
       }
       devices.add(devices2);


Engine::getDeviceForInputSource 中修改输出
   char value[PROPERTY_VALUE_MAX] = "";
   char value_usb[PROPERTY_VALUE_MAX] = "";
   char value_hdmiin[PROPERTY_VALUE_MAX] = "";

   property_get("persist.system.usb.headset_state",value, "unknow");
   property_get("persist.vendor.audio.input.device",value_usb,"unknow");
   property_get("media.audio.hdmiin",value_hdmiin,"0");

    if (isInCall()) {

             if(/*!(strcmp(value,"on")&&*/!strcmp(value_usb,"USB Mic")){

                device = availableDevices.getFirstExistingDevice({
                        AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,AUDIO_DEVICE_IN_BLUETOOTH_A2DP,  AUDIO_DEVICE_IN_USB_HEADSET,
                        AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_WIRED_HEADSET,AUDIO_DEVICE_IN_BUILTIN_MIC});
             }else{

                device = availableDevices.getFirstExistingDevice({

              }
    }else{
           if(/*!(strcmp(value,"on")&&*/!strcmp(value_usb,"USB Mic")){

                device = availableDevices.getFirstExistingDevice({
                        AUDIO_DEVICE_IN_USB_HEADSET,AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_WIRED_HEADSET,AUDIO_DEVICE_IN_BUILTIN_MIC});
             }else{

                device = availableDevices.getFirstExistingDevice({
                         AUDIO_DEVICE_IN_WIRED_HEADSET,AUDIO_DEVICE_IN_BUILTIN_MIC});

              }

    }

    if(strcmp(value_hdmiin,"1")==0){
      device = availableDevices.getFirstExistingDevice({AUDIO_DEVICE_IN_HDMI});
    }

    if (device == nullptr) {
        ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
        device = availableDevices.getDevice(
                AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
        ALOGE_IF(device == nullptr,
                 "getDeviceForInputSource() no default device defined");
    }
    ALOGD("max.chen getDeviceForInputSource()input source %d, device %08x",
             inputSource, device->type());
    return device;

 4.修改hardware/rockchip/audio/tinyalsa/audio_hw.c

static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)

   /* usb_headset enable/disable */
    ret = str_parms_get_str(parms, "saintway_usb_headset_enable", value, sizeof(value));
    if (0 <= ret) {


        if (strcmp(value, "true") == 0) {
            ALOGD("max.chen Enable usb headset ");
            struct stream_out *out = adev->outputs[OUTPUT_DIRECT];
            out->snd_reopen = true;
        } else if (strcmp(value, "false") == 0) {
            ALOGD("max.chen Disable usb headset");
            struct stream_out *out = adev->outputs[OUTPUT_DIRECT];
            out->snd_reopen = true;

        }

    }

### 设置或修改 Android 系统媒体音频输出设备的优先级Android 系统中,音频输出设备的选择遵循一定的优先级规则。当多个音频输出设备可用时,系统会选择最合适的设备进行音频播放。这种选择通常基于硬件连接状态以及应用程序的需求。 #### 后插优先机制 对于外部音频设备(如耳机、蓝牙设备),Android 实现了一种称为“后插优先”的机制。这意味着每当一个新的音频设备被插入时,它会被赋予更高的优先级,并成为默认的声音输出路径[^1]。此行为确保用户能够立即听到来自新连接设备的声音而无需额外配置。 #### 动态调整声音优先级 为了实现上述功能,在底层框架层面,特别是 `Engine.cpp` 文件中的原生逻辑负责检测并响应各种类型的外设变化事件。一旦发现新的音频设备接入,则依据预定义好的顺序重新评估现有选项,最终决定采用哪一个作为当前活动的输出端口[^2]。 #### 应用程序接口限制 值得注意的是,尽管存在多种可能的音频路由方案,但在 API 层面,开发者仅能通过有限的方式干预这一过程。例如,可以通过调用 `AudioManager.setSpeakerphoneOn()` 或者 `AudioManager.setBluetoothScoOn()` 方法来强制指定扬声器或蓝牙 SCO 连接模式下的语音通信路径。这是因为其他形式的切换操作往往由操作系统自动管理,尤其是涉及到物理连接变动的情况[^3]。 #### 修改音频输出优先级的实际方法 如果希望自定义特定场景下不同种类音频流所使用的输出装置,可以考虑利用广播接收器监听诸如 `ACTION_HEADSET_PLUG` 和 `BluetoothAdapter.ACTION_STATE_CHANGED` 等意图动作,进而根据实际情况更新应用内部的状态机或是提示用户做出相应选择。此外,还可以探索更高级别的编程接口,像 MediaSessionCompat 类所提供的控制能力,允许更加精细地调节多媒体会话期间的行为表现。 ```java // 注册广播接收器以监控耳机插入/移除事件 IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); registerReceiver(headsetPlugReceiver, filter); private final BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int state = intent.getIntExtra("state", -1); // 获取耳机状态 switch (state){ case 0: Log.d(TAG,"Headphones unplugged"); break; case 1: Log.d(TAG,"Headphones plugged in"); AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); audioManager.setMode(AudioManager.MODE_NORMAL); audioManager.startBluetoothSco(); audioManager.setBluetoothScoOn(true); break; } } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Max.Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值