我想从蓝牙麦克风输入音频并大声输出 - 如扩音器或简单的扩声系统 - 并实时广播。
为此目的,我正在使用AudioRecord和AudioTrack类 - 因为MediaRecorder和MediaPlayer会写入和读取外部文件,我可以想象这会使音频延迟得多(这是真的吗?)。
我已经放弃了使用任何蓝牙类的想法,因为Android API并不支持Android设备作为源/接收器场景中的接收器(至少现在还没有),然后需要本机编程Android库(这也是事实,对吧?)
立即。该应用正在运行,但延迟太长,并且该应用假设实际播放音频。
我的第一个问题是:AudioRecord / AudioTrack是否适用于此目的(通过蓝牙麦克风将音频流式传输到设备扬声器并实时播放)?
如果是这样的话:如何减少音频的延迟,以便它以实时实时方式从麦克风流式传输音频?此处列出的整个代码,请自己帮忙:
在Manifest中,需要录制音频的权限。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
我有一个专门的类,它扩展了一个用于处理音频的线程:
public class AudioStreamer extends Thread {
/**
* @Params:
*/
private int audioSource = MediaRecorder.AudioSource.MIC;
private int sampleRate = 11025;
private int streamType = AudioManager.STREAM_MUSIC;
private int mode = AudioTrack.MODE_STREAM;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int channelConfigIn = AudioFormat.CHANNEL_IN_MONO;
private int channelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
private int recordSize;
private int trackSize;
private AudioTrack track;
private AudioRecord recorder;
/**
* Initializes the un-initialized params: buffer, bufferSize, track and recorder
* starts recording/playing with AudioRecord and AudioTrack respectively
*/
public AudioStreamer() {
System.out.println("New code!");
recordSize = AudioRecord.getMinBufferSize(sampleRate,
channelConfigIn, audioFormat);
System.out.println("recordSize: "+recordSize);
trackSize = AudioTrack.getMinBufferSize(sampleRate,
channelConfigOut, audioFormat);
System.out.println("trackSize: "+trackSize);
recorder = new AudioRecord(audioSource, sampleRate,
channelConfigIn, audioFormat, recordSize);
if (recorder.getState() == AudioRecord.STATE_INITIALIZED) {
track = new AudioTrack(streamType, sampleRate,
channelConfigOut, audioFormat, trackSize, mode);
if (track.getState() == AudioTrack.STATE_INITIALIZED) {
System.out.println("Record and Track initialized");
} else {
System.out.println("Track != init");
}
} else {
System.out.println("Recorder != init");
}
}
/**
* Runs thread--which reads and writes from/to the Android hardware
*/
public void run() {
recorder.startRecording();
track.play();
if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING
&& track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
System.out.println("Recorder and track playing");
} else {
System.out.println("Track and recorder != PLAYING");
}
short[] buffer = new short[recordSize];
int audioLenght = 0;
while (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING
&& track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioLenght = recorder.read(buffer, 0, recordSize);
track.write(buffer, 0, audioLenght);
}
}
/**
* sets up the AudioManager for bluetooth audio streaming
*/
public void setAudioManager(AudioManager manager) {
manager.setMode(AudioManager.MODE_IN_COMMUNICATION);
// set true and test
manager.setBluetoothScoOn(true);
manager.setSpeakerphoneOn(true);
System.out.println("bluetoothScoOn: " + manager.isBluetoothScoOn()
+ ", bluetoothA2DP: " + manager.isBluetoothA2dpOn()
+", speakerPhone: "+manager.isSpeakerphoneOn());
/**
* Start BluetoothSCO
*/
if (manager.isBluetoothA2dpOn()) {
manager.startBluetoothSco();
System.out.println("BtSco started");
}
}
/**
* Pauses the audio stream
*/
public void pause() {
if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
recorder.stop();
}
if (track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
track.pause();
track.flush();
}
if (track.getPlayState() == AudioTrack.PLAYSTATE_PAUSED
&& recorder.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) {
System.out.println("Stopped");
}
}
}
我的Main类提供了可点击的按钮,可以在音频流上调用start / stop-methods:
public class MainActivity extends AppCompatActivity {
private AudioStreamer audioStreamer;
private AudioManager manager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("Program running ... ");
audioStreamer = new AudioStreamer();
manager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
audioStreamer.setAudioManager(manager);
}
public void startAudioStreamer(View view) {
audioStreamer.start();
}
public void pauseAudioStreamer(View view) {
audioStreamer.pause();
}
}
通过带有如下按钮的图形布局显示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.android.audiorecordrevisited.MainActivity">
<Button
android:id="@+id/startAudioStreamer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startAudioStreamer"
android:text="Start AudioStreamer" />
<Button
android:id="@+id/stopAudioStreamer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/startAudioStreamer"
android:onClick="pauseAudioStreamer"
android:text="Stop Audio recording" />
</RelativeLayout>
如何减少音频流的延迟?我使用的是正确的类,还是有其他/更好的方法解决这个问题?
另外:音频输入似乎不是来自实际的蓝牙麦克风,而是来自Android硬件麦克风 - 这不是想法。 如何直接将音频输入读取到蓝牙麦克风而不是读取内置麦克风呢?