功能:根据需求选择音频音频设备的输入输出
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;
}
}