在 Android 上将音频路由到蓝牙耳机(非 A2DP)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2144694/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Routing audio to Bluetooth Headset (non-A2DP) on Android
提问by Jayesh
I have a non-A2DP single ear BT headset (Plantronics 510) and would like to use it with my Android HTC Magic to listen to low quality audio like podcasts/audio books.
我有一个非 A2DP 单耳 BT 耳机 (Plantronics 510),并希望将它与我的 Android HTC Magic 一起使用以收听低质量音频,如播客/有声读物。
After much googling I found that only phone call audio can be routed to the non-A2DP BT headsets. (I would like to know if you have found a ready solution to route all kinds of audio to non-A2DP BT headsets)
经过多次谷歌搜索,我发现只能将电话音频路由到非 A2DP BT 耳机。(我想知道您是否找到了将各种音频路由到非 A2DP BT 耳机的现成解决方案)
So I figured, somehow programmatically I can channel the audio to the stream that carries phone call audio. This way I will fool the phone to carry my mp3 audio to my BT headset. I wrote following simple code.
所以我想,以某种方式以编程方式我可以将音频引导到携带电话音频的流。通过这种方式,我将欺骗手机将我的 mp3 音频传输到我的 BT 耳机。我写了以下简单的代码。
import android.content.*;
import android.app.Activity;
import android.os.Bundle;
import android.media.*;
import java.io.*;
import android.util.Log;
public class BTAudioActivity extends Activity
{
private static final String TAG = "BTAudioActivity";
private MediaPlayer mPlayer = null;
private AudioManager amanager = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
amanager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
amanager.setBluetoothScoOn(true);
amanager.setMode(AudioManager.MODE_IN_CALL);
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(new FileInputStream(
"/sdcard/sample.mp3").getFD());
mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
mPlayer.prepare();
mPlayer.start();
} catch(Exception e) {
Log.e(TAG, e.toString());
}
}
@Override
public void onDestroy()
{
mPlayer.stop();
amanager.setMode(AudioManager.MODE_NORMAL);
amanager.setBluetoothScoOn(false);
super.onDestroy();
}
}
As you can see I tried combinations of various methods that I thought will fool the phone to believe my audio is a phone call:
如您所见,我尝试了各种方法的组合,我认为这些方法会欺骗电话相信我的音频是电话:
- Using MediaPlayer's setAudioStreamType(STREAM_VOICE_CALL)
- using AudioManager's setBluetoothScoOn(true)
- using AudioManager's setMode(MODE_IN_CALL)
- 使用 MediaPlayer 的 setAudioStreamType(STREAM_VOICE_CALL)
- 使用 AudioManager 的 setBluetoothScoOn(true)
- 使用 AudioManager 的 setMode(MODE_IN_CALL)
But none of the above worked. If I remove the AudioManager calls in the above code, the audio plays from speaker and if I replace them as shown above then the audio stops coming from speakers, but it doesn't come through the BT headset. So this might be a partial success.
但以上都没有奏效。如果我删除上面代码中的 AudioManager 调用,音频会从扬声器播放,如果我如上所示替换它们,音频将停止来自扬声器,但它不会通过 BT 耳机。所以这可能是部分成功。
I have checked that the BT headset works alright with phone calls.
我已经检查过 BT 耳机是否可以正常通话。
There must be a reason for Android not supporting this. But I can't let go of the feeling that it is not possible to programmatically reroute the audio. Any ideas?
Android 不支持这一点肯定是有原因的。但是我不能放弃无法以编程方式重新路由音频的感觉。有任何想法吗?
P.S. above code needs following permission
PS上面的代码需要以下权限
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
回答by Vic
This thread may be long dead but for those who might be trying the same thing, some notes from the AudioManager docs may be useful. It looks like the missing element is the startBluetoothSco() command but there are restrictions on the use of this channel. From the Android Dev site here:
这个线程可能已经死了很久,但对于那些可能正在尝试同样事情的人来说,AudioManager 文档中的一些注释可能有用。看起来缺少的元素是 startBluetoothSco() 命令,但对该通道的使用有限制。从这里的 Android 开发站点:
public void startBluetoothSco () Since: API Level 8 Start bluetooth SCO audio connection.
Requires Permission: MODIFY_AUDIO_SETTINGS.
This method can be used by applications wanting to send and received audio to/from a bluetooth SCO headset while the phone is not in call.
As the SCO connection establishment can take several seconds, applications should not rely on the connection to be available when the method returns but instead register to receive the intent ACTION_SCO_AUDIO_STATE_CHANGED and wait for the state to be SCO_AUDIO_STATE_CONNECTED.
As the connection is not guaranteed to succeed, applications must wait for this intent with a timeout.
When finished with the SCO connection or if the establishment times out, the application must call stopBluetoothSco() to clear the request and turn down the bluetooth connection.
Even if a SCO connection is established, the following restrictions apply on audio output streams so that they can be routed to SCO headset: - the stream type must be STREAM_VOICE_CALL - the format must be mono - the sampling must be 16kHz or 8kHz
The following restrictions apply on input streams: - the format must be mono - the sampling must be 8kHz
Note that the phone application always has the priority on the usage of the SCO connection for telephony. If this method is called while the phone is in call it will be ignored. Similarly, if a call is received or sent while an application is using the SCO connection, the connection will be lost for the application and NOT returned automatically when the call ends.
See Also stopBluetoothSco() ACTION_SCO_AUDIO_STATE_CHANGED
public void startBluetoothSco() 自:API 级别 8 启动蓝牙 SCO 音频连接。
需要权限:MODIFY_AUDIO_SETTINGS。
想要在电话未通话时向/从蓝牙 SCO 耳机发送和接收音频的应用程序可以使用此方法。
由于 SCO 连接建立可能需要几秒钟,因此应用程序不应依赖方法返回时连接可用,而是注册以接收意图 ACTION_SCO_AUDIO_STATE_CHANGED 并等待状态变为 SCO_AUDIO_STATE_CONNECTED。
由于不能保证连接成功,应用程序必须超时等待此意图。
当完成 SCO 连接或建立超时时,应用程序必须调用 stopBluetoothSco() 来清除请求并关闭蓝牙连接。
即使建立了 SCO 连接,以下限制也适用于音频输出流,以便它们可以路由到 SCO 耳机: - 流类型必须是 STREAM_VOICE_CALL - 格式必须是单声道 - 采样必须是 16kHz 或 8kHz
以下限制适用于输入流: - 格式必须是单声道 - 采样必须是 8kHz
请注意,电话应用程序始终优先使用 SCO 连接进行电话。如果在电话通话时调用此方法,它将被忽略。同样,如果在应用程序使用 SCO 连接时接收或发送呼叫,应用程序的连接将丢失,并且不会在呼叫结束时自动返回。
另见 stopBluetoothSco() ACTION_SCO_AUDIO_STATE_CHANGED
Note that I have not tested this, I'm just passing along a lead I found in researching a similar project. I think Jayesh was close to the solution and the restrictions above may have been what was keeping it from working.
请注意,我没有对此进行测试,我只是传递了我在研究类似项目时发现的线索。我认为 Jayesh 接近解决方案,上述限制可能是阻止它工作的原因。
回答by Uriel Frankel
To turn on:
打开:
localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setMode(0);
localAudioManager.setBluetoothScoOn(true);
localAudioManager.startBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_IN_CALL);
To turn off:
把关掉:
localAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
localAudioManager.setBluetoothScoOn(false);
localAudioManager.stopBluetoothSco();
localAudioManager.setMode(AudioManager.MODE_NORMAL);
回答by Aditya Hari Kishan
Great Work it is working fine for me please do bit modification in your code it'll work perfectly i.e.
伟大的工作它对我来说很好,请在你的代码中做一些修改,它会完美地工作,即
mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
to
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
回答by Arjuna
There should be a ALSA route path configured for Media player, so that it can open a different audio path and then route your audio to BT headset.
应该为媒体播放器配置一个 ALSA 路由路径,以便它可以打开不同的音频路径,然后将您的音频路由到 BT 耳机。
回答by Saurav
Cannot see a clear accepted working application so putting a new answer. This application routes music and audio to Non A2dp headsets. Try my application and find the source code also in github for reference code. https://github.com/sauravpradhan/AnySound2BT
看不到明确接受的工作申请,所以提出一个新的答案。此应用程序将音乐和音频路由到非 A2dp 耳机。试试我的应用程序,并在 github 中找到源代码作为参考代码。https://github.com/sauravpradhan/AnySound2BT