Обширный проект: потоковое аудио с микрофона на устройство Android
Я хочу взять аудиовход с микрофона Bluetooth и транслировать его громко - как мегафон или простая система громкой связи -и транслировать его в режиме реального времени.
Для этой цели я использую классы AudioRecord и AudioTrack - поскольку MediaRecorder и MediaPlayer записывают и читают во внешний файл, что, я могу себе представить, задерживает звук намного больше, чем необходимо (это правда?).
Я отказался от идеи использовать какие-либо классы Bluetooth, поскольку API Android не поддерживает устройство Android как приемник в сценарии «источник / приемник» (по крайней мере, пока), а затем потребует собственного программирования библиотек Android (это тоже правда, правда?)
Сейчас. Приложение работает, нозадержка слишком длинная и приложение должно воспроизводить звук в реальном времени.
Мой первый вопрос: являются ли AudioRecord / AudioTrack подходящими классами для этой цели (потоковая передача звука через микрофон Bluetooth на динамики устройства и громкое воспроизведение в режиме реального времени)?
И если это так:Как я могу уменьшить задержку звука так что он передает аудио с микрофона вфактическое в реальном времени? Весь код указан здесь, поэтому, пожалуйста, помогите себе:
В 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;
p,rivate 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");
}
}
}
А мой основной класс снабжен интерактивными кнопками, которые вызывают методы start / stop в аудиопотоке:
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>
Как я могу уменьшить задержку аудиопотока? Я использую правильные классы, или есть другой / лучший подход к этой проблеме?
Кроме того: кажется, что аудиовход поступает не через микрофон Bluetooth, а через аппаратный микрофон Android - но это не идея.Как я могу направить чтение аудиовхода на микрофон Bluetooth вместо считывания с внутреннего?