我正在开发一个应用程序,我们只需要将耳机插孔用作按钮。
要求:连接耳机时通过听筒播放默认音频(通话)(无需通过耳机收听音频)
有许多通过扬声器和耳机以及蓝牙耳机路由音频的示例,但没有任何关于通过连接耳机的设备的耳式扬声器路由音频的内容。我已经尝试了很多,有些链接是
Android:强制音频路由(在我的场景中不起作用)
我查过sound about(https://play . Google . com/store/apps/details?id = com . Woods link . Android . wiredheadphoneroutingfix
如果连接了耳机,我可以将音频连接到扬声器:这是我的代码
if (Build.VERSION.SDK_INT >= 21) {
ForegroundService.audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
ForegroundService.audioManager.setSpeakerphoneOn(true);
SplashScreen.preferences.edit().putBoolean("isKey", true).commit();
} else {
Class audioSystemClass = null;
try {
audioSystemClass = Class.forName("android.media.AudioSystem");
Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
setForceUse.invoke(null, FOR_MEDIA, FORCE_SPEAKER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
SplashScreen.preferences.edit().putBoolean("isKey", true).commit();
ForegroundService.audioManager.setSpeakerphoneOn(true);
}
经过大量研究,我发现没有任何方法可以在不使用反射的情况下实现这种功能。首先,您需要将耳机插孔放入,然后使用合适的参数调用方法setWiredDeviceConnectionState(),然后它的行为就像耳机断开连接一样,但点击仍然有效。所以这是一个黑客,但根据我的要求,这不是一个万无一失的解决方案,但目前有效。这是我的代码,
private void sendIntent(Intent i) {
Method m;
Log.i(TAG, "Device sdk = " + Build.VERSION.SDK_INT);
try {
if (Build.VERSION.SDK_INT < 16) {
Class<?> clazz = Class.forName("android.app.ActivityManagerNative");
m = clazz.getMethod("broadcastStickyIntent", Intent.class, String.class);
m.setAccessible(true);
m.invoke(clazz, i, null);
return;
} else if (Build.VERSION.SDK_INT < 23) {
//int type, int state, String address, String name
m = am.getClass().getMethod("setWiredDeviceConnectionState", Integer.TYPE, Integer.TYPE, String.class);
m.setAccessible(true);
Object[] objArr = new Object[3];
objArr[0] = (i.getIntExtra("microphone", 0) == 0) ? 8 : 4;
objArr[1] = i.getIntExtra("state", 0);
objArr[2] = i.getStringExtra("name");
m.invoke(am, objArr);
} else {
//int type, int state, String address, String name
m = am.getClass().getMethod("setWiredDeviceConnectionState", Integer.TYPE, Integer.TYPE, String.class, String.class);
m.setAccessible(true);
Object[] objArr = new Object[4];
objArr[0] = (i.getIntExtra("microphone", 0) == 0) ? 8 : 4;
objArr[1] = i.getIntExtra("state", 0);
objArr[2] = i.getStringExtra("address");
objArr[3] = i.getStringExtra("name");
m.invoke(am, objArr);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
发送的意图:
@TargetApi(Build.VERSION_CODES.M)
public class HeadSetJackReciever extends AudioDeviceCallback {
public static boolean isAudioChecked;
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
if (addedDevices.length != 0) {
for (int i = 0; i < addedDevices.length; i++) {
if (addedDevices[i].getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
AudioDeviceInfo audioDeviceInfo = addedDevices[i];
int microphone = audioDeviceInfo.getType();
String headsetName = "DCS";
String headsetAddress = "";
try {
Method method = audioDeviceInfo.getClass().getMethod("getAddress");
method.setAccessible(true);
headsetAddress = (String) method.invoke(audioDeviceInfo);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Log.e("TEST", "microphone:"+microphone);
Log.e("TEST", "headsetName:"+headsetName);
Log.e("TEST", "headsetAddress:"+headsetAddress );
Intent intent = new Intent(ForegroundService.context, SelectAudioOutput.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("microphone",microphone);
intent.putExtra("headsetName",headsetName);
intent.putExtra("headsetAddress",headsetAddress);
ForegroundService.context.startActivity(intent);
}
}
}
}
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
if (removedDevices.length != 0) {
Log.e("TEST", "Audio deinserted");
if (SplashScreen.preferences.getBoolean("isKey", false)) {
Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class);
startIntent.setAction(Constants.ACTION.STARTNOTIFICATION_ACTION);
ForegroundService.context.startService(startIntent);
} else {
Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class);
startIntent.setAction(Constants.ACTION.STOPNOTIFICATION_ACTION);
ForegroundService.context.startService(startIntent);
}
ForegroundService.audioManager.setMode(AudioManager.MODE_IN_CALL);
ForegroundService.audioManager.setSpeakerphoneOn(false);
}
}
}
对于Lollipop和更低版本:
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
headsetName = intent.getStringExtra("name");
microphone = intent.getIntExtra("microphone", 0);
int state = intent.getIntExtra("state", -1);
switch (state) {
case 0:
Log.d("onReceive", "Headset unplugged");
Log.e("TEST", "Audio deinserted");
if (SplashScreen.preferences.getBoolean("isKey", false)) {
Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class);
startIntent.setAction(Constants.ACTION.STARTNOTIFICATION_ACTION);
context.startService(startIntent);
} else {
Intent startIntent = new Intent(ForegroundService.context, ForegroundService.class);
startIntent.setAction(Constants.ACTION.STOPNOTIFICATION_ACTION);
context.startService(startIntent);
}
ForegroundService.audioManager.setMode(AudioManager.MODE_IN_CALL);
ForegroundService.audioManager.setSpeakerphoneOn(false);
break;
case 1:
Log.d("onReceive", "Headset plugged");
Log.e("TEST", "microphone:"+microphone);
Log.e("TEST", "headsetName:"+headsetName);
Log.e("TEST", "headsetAddress:"+headsetAddress );
Intent intentone = new Intent(ForegroundService.context, SelectAudioOutput.class);
intentone.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentone.putExtra("microphone",microphone);
intentone.putExtra("headsetName",headsetName);
intentone.putExtra("headsetAddress",headsetAddress);
context.startActivity(intentone);
break;
}
}
如果我错过了什么,请告诉我。谢谢。
听筒在Android中从不用于媒体,只有在手机处于“通话”或“通信”(VoIP)状态时才能使用。
我猜你已经注意到没有“FORCE_EARPIECE”常量,所以它不能在对< code>setForceUse的调用中指定。
此外,听筒在呼叫的输出设备选择中具有最低的优先级,因此,如果电话连接了任何东西(在您的情况下,有假耳机),则将选择该设备(请参阅 html" target="_blank">https://android.googlesource.com/platform/frameworks/av/ /322b4d2/services/audiopolicy/enginedefault/src/Engine.cpp#381)。
对不起,似乎不可能实现你的意图。
更新
在SoundAbout强制对媒体使用耳机时检查< code>media.audio_policy状态后,我发现了该应用程序使用的以下技巧:
>
它调用AudioSystem.setPhoneState(MODE_IN_COMMUNICATION)
来强制执行“通信”电话状态(通常用于VoIP呼叫)。
如果连接了耳机(或多个耳机),为了防止由于优先级较高而将声音传送到耳机,应用程序会调用AudioSystem。设置DeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,DEVICE_ STATE_UNAVAILABLE,…)
欺骗音频管理器相信没有耳机。
这些都是黑客攻击,需要应用程序密切监控手机状态。也不是一直都管用。
另一个缺点是,使用听筒会禁用片上音频解压缩,因此电池使用率较高。
一般来说,我不建议使用这些技术。
我正在寻找一种方法来播放Android设备扬声器中的音频,即使是在插入耳机的情况下。 事实上,典型的行为是,当插入耳机时,扬声器不会输出任何音频。然而,一些应用程序,例如默认的时钟应用程序(com.google.android.deskclock),即使插入耳机,也能够将音频路由到扬声器。 如何以编程方式获得此行为? 我正在寻找(至少)在Nexus 5设备上运行KitKat(Android 4.4
我试图让用户能够在我的应用程序中切换音频输出,我可以使用AVAudioSession在扬声器和背部之间切换,但我找不到在连接的蓝牙设备和耳机之间切换的方法,以任何顺序。 谢谢你的帮助。
我创建了语音通话录音应用程序,它与手机的麦克风和听筒配合得很好。但是当插入耳机时,它不能录制音频。我试图将AudioSource更改为AudioSource.default,以为它会自动接受默认音频源。它什么也没记录。
我正在使用语音识别应用程序。蓝牙耳机成功连接到我的android设备后,我想在内置麦克风和耳机麦克风之间自由切换音频输入,如何做到?
在我的应用程序中,有一个使用设备音频插孔的读卡器。现在,我的问题是,当读卡器在设备的耳机插孔中完好无损时,我想从内置扬声器中发出声音。 以下是我尝试过的代码: 1) 使用反射方法 2)使用setMode方法 但这两种代码仅在具有默认FM应用程序的设备中运行。但我想在所有设备中都具有此功能。 请分享你的经验!!
当有线耳机或USB耳机都连接到Android设备时,我在检测哪个设备播放音频时遇到问题。 有没有一个API可以检查它? 我注意到不同的设备以不同的方式工作。例如,在装有Android 9的三星S10上,后来连接的外围设备用于播放音频。然而,在Moto G6 Android 7和三星S8 Android 9上,无论后来连接了哪种外设,都始终使用有线耳机。 我需要这些信息来正确配置音频流并显示当前正在