如何将麦克风音频流式传输到同一设备的扬声器
how to Stream mic Audio to the same device throw speakers
我正在尝试从麦克风获取音频并通过连接到 aux 的扬声器流式传输我使用了这段代码,但它在录音机的初始化中不起作用
但我真正的问题是 "is this the right way to do it or there is a better way to do it " 以及如何解决初始化音频的问题
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
// the buttons for start and Stop BoadCast
Button mStartBoadCast;
Button mStopBoadCast;
// variables for audio recording
AudioRecord recorder;
private int sampleRate = 44100;
private int channelConfig = AudioFormat.CHANNEL_IN_DEFAULT;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
private boolean status = true;
// audio instance is meant for playing audio input from stream
private AudioTrack speaker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init layout views
initViews();
// init start boadcast method with the button
initStartBoadCast();
// init stop boadcast method with the button
initStartBoadCast();
}
private void initStartBoadCast() {
mStartBoadCast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startBoadCast();
}
});
}
private void initStopBoadCast() {
mStartBoadCast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopBoadCast();
}
});
}
private void stopBoadCast() {
//todo: add the function to stop boad casr
status = false;
recorder.release();
speaker.release();
}
private void startPlayingAudio(byte[] buffer, int minBufSize) {
status = true;
speaker = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, minBufSize, AudioTrack.MODE_STREAM);
speaker.play();
while (status) {
speaker.write(buffer, 0, minBufSize);
Log.d("VR", "Writing buffer content to speaker");
}
}
private void startBoadCast() {
status = true;
Log.d("VS", "Socket Created");
byte[] buffer = new byte[minBufSize];
recorder = findAudioRecord();
Log.d("VS", "Recorder initialized");
recorder.startRecording();
while (status) {
//reading data from MIC into buffer
minBufSize = recorder.read(buffer, 0, buffer.length);
/**
* here we finished recording then we will start to play the recorded audio
*/
startPlayingAudio(buffer, minBufSize);
System.out.println("MinBufferSize: " + minBufSize);
}
}
private void initViews() {
mStartBoadCast = findViewById(R.id.start_boadcast);
mStopBoadCast = findViewById(R.id.stop_boadcast);
}
private static int[] mSampleRates = new int[]{8000, 11025, 22050, 44100};
public AudioRecord findAudioRecord() {
for (int rate : mSampleRates) {
for (short audioFormat : new short[]{AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT}) {
for (short channelConfig : new short[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO}) {
try {
Log.d(TAG, "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: "
+ channelConfig);
int bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
// check if we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, rate, channelConfig, audioFormat, bufferSize);
if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
return recorder;
}
} catch (Exception e) {
Log.e(TAG, rate + "Exception, keep trying.", e);
}
}
}
}
return null;
}
}
交易是在细节上,你没有告诉我们这是怎么回事,或者它给出了什么样的错误。我不得不做一个类似的程序,我就是这样做的。
音频 Class 第一:
class audio {
AudioRecord arec;
AudioTrack atrack;
private volatile boolean isRecording= false;
private static int buffer_size;
//final short[] buffer = new short[buffersize];
//short[] readbuffer = new short[buffersize];
private int sample_rate;//the rate of recording used to initialise AudioRecord
private int[] msample_rates = new int[]{44100, 22050, 11025, 8000};
private short audio_format;
private short[] audio_formats = new short[]{AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT};
private short channel_config;
private short[] channel_configs = new short[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO};
private short channelOutConfig;
public AudioRecord findAudioRecord(){
for (int rate_f : msample_rates){
for (short audioformat_f : audio_formats){
for (short channelconfig_f : channel_configs){
try {
Log.i("AudioC", "Attempting rate : "+ rate_f + "Hz, bits: " + audioformat_f + ", Channel: " + channelconfig_f);
int buffersize_f = AudioRecord.getMinBufferSize(rate_f, channelconfig_f, audioformat_f);
Log.i("AudioC", "Buffersize: " + buffersize_f);
if (buffersize_f != AudioRecord.ERROR_BAD_VALUE){
//Check of we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, rate_f, channelconfig_f, audioformat_f, buffersize_f);
Log.i("AudioC", "Recorder State Value: " + recorder.getState());
if(recorder.getState() == AudioRecord.STATE_INITIALIZED){
Log.i("Audio", "Success");
//global values
buffer_size = buffersize_f;
sample_rate = rate_f;
audio_format = audioformat_f;
channel_config = channelconfig_f;
if (channelconfig_f == AudioFormat.CHANNEL_IN_MONO) channelOutConfig = AudioFormat.CHANNEL_OUT_MONO;
else channelOutConfig = AudioFormat.CHANNEL_OUT_STEREO;
return recorder;
}
}
}catch (Exception e){
Log.i("AudioC", rate_f + " Exception, keep trying." + e);
}
}
}
}
Log.i("AudioC", "Failed to initialise the audio record state");
return null;
}
public void run(){
isRecording = true;
//initialization
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
//getValidSampleRates();
// int buffersize = AudioRecord.getMinBufferSize(sample_rate,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
// arec = new AudioRecord(MediaRecorder.AudioSource.MIC,sample_rate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize);
//The above lines were replaced by a looping function in order to test every occurrence of rate,audioformat and channelconfig which is usually different for different adroid devices
arec = findAudioRecord();//Still failed to initialize the Audio Recorder
atrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
sample_rate,
channelOutConfig,
audio_format,
buffer_size,
AudioTrack.MODE_STREAM);
atrack.setPlaybackRate(sample_rate);
//run
byte[] buffer = new byte[buffer_size];
arec.startRecording();
atrack.play();
while (isRecording){
arec.read(buffer, 0, buffer_size);
atrack.write(buffer, 0,buffer.length);
}
arec.release();
atrack.release();
}
public void stop(){
isRecording= false;
arec.stop();
atrack.stop();
arec.release();
atrack.release();
}
}
然后从 activity(Main Activity) 的线程或意图服务中调用它,以避免应用程序冻结。
来自线程的示例:
class playerTask implements Runnable{
public audio mic_player = new audio(); //The audio class we declared above
private Thread t;
public playerTask(){
}
public void execTask(){
t = new Thread(this,"playing_Thread");
t.start();
}
public void abortTask(){
mic_player.stop();
}
public void run(){
mic_player.run();
}
}
然后从你的activity,
public class YourActivity extends AppCompatActivity {
ToggleButton onOff;
boolean playing = false;
// Once the app start recording, the recording thread freezes the screen because of the while loop, the it works
//directly with the main thread hence doesnt release the hand until forced to stop
//For that we need to create it's own thread hence being able to play sound without freezing the remaining of the app
//private Handler myHandler
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_main);
//Handler
//Route the sound to the AUX only and always
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_CALL);
audioManager.setSpeakerphoneOn(false);
audioManager.setWiredHeadsetOn(true);
audioManager.setBluetoothScoOn(false);
final playerTask pl_task = new playerTask();
/////Use a toggle button to start or stop the recording///You could use anything
onOff = (ToggleButton)findViewById(R.id.OnOff);
onOff.setTextOff("PLAY");
onOff.setTextOn("STOP");
onOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonview, boolean isCheked){
//Running thread
if (isCheked){
messagefield.setText("Playing");
pl_task.execTask(); ///Start streaming
}
else{
messagefield.setText("Not Playing");
pl_task.abortTask(); ///Stop streaming
}
}
});
}
这些是您需要请求的权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
我正在尝试从麦克风获取音频并通过连接到 aux 的扬声器流式传输我使用了这段代码,但它在录音机的初始化中不起作用 但我真正的问题是 "is this the right way to do it or there is a better way to do it " 以及如何解决初始化音频的问题
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
// the buttons for start and Stop BoadCast
Button mStartBoadCast;
Button mStopBoadCast;
// variables for audio recording
AudioRecord recorder;
private int sampleRate = 44100;
private int channelConfig = AudioFormat.CHANNEL_IN_DEFAULT;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
private boolean status = true;
// audio instance is meant for playing audio input from stream
private AudioTrack speaker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init layout views
initViews();
// init start boadcast method with the button
initStartBoadCast();
// init stop boadcast method with the button
initStartBoadCast();
}
private void initStartBoadCast() {
mStartBoadCast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startBoadCast();
}
});
}
private void initStopBoadCast() {
mStartBoadCast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopBoadCast();
}
});
}
private void stopBoadCast() {
//todo: add the function to stop boad casr
status = false;
recorder.release();
speaker.release();
}
private void startPlayingAudio(byte[] buffer, int minBufSize) {
status = true;
speaker = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, minBufSize, AudioTrack.MODE_STREAM);
speaker.play();
while (status) {
speaker.write(buffer, 0, minBufSize);
Log.d("VR", "Writing buffer content to speaker");
}
}
private void startBoadCast() {
status = true;
Log.d("VS", "Socket Created");
byte[] buffer = new byte[minBufSize];
recorder = findAudioRecord();
Log.d("VS", "Recorder initialized");
recorder.startRecording();
while (status) {
//reading data from MIC into buffer
minBufSize = recorder.read(buffer, 0, buffer.length);
/**
* here we finished recording then we will start to play the recorded audio
*/
startPlayingAudio(buffer, minBufSize);
System.out.println("MinBufferSize: " + minBufSize);
}
}
private void initViews() {
mStartBoadCast = findViewById(R.id.start_boadcast);
mStopBoadCast = findViewById(R.id.stop_boadcast);
}
private static int[] mSampleRates = new int[]{8000, 11025, 22050, 44100};
public AudioRecord findAudioRecord() {
for (int rate : mSampleRates) {
for (short audioFormat : new short[]{AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT}) {
for (short channelConfig : new short[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO}) {
try {
Log.d(TAG, "Attempting rate " + rate + "Hz, bits: " + audioFormat + ", channel: "
+ channelConfig);
int bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);
if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
// check if we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, rate, channelConfig, audioFormat, bufferSize);
if (recorder.getState() == AudioRecord.STATE_INITIALIZED)
return recorder;
}
} catch (Exception e) {
Log.e(TAG, rate + "Exception, keep trying.", e);
}
}
}
}
return null;
}
}
交易是在细节上,你没有告诉我们这是怎么回事,或者它给出了什么样的错误。我不得不做一个类似的程序,我就是这样做的。
音频 Class 第一:
class audio {
AudioRecord arec;
AudioTrack atrack;
private volatile boolean isRecording= false;
private static int buffer_size;
//final short[] buffer = new short[buffersize];
//short[] readbuffer = new short[buffersize];
private int sample_rate;//the rate of recording used to initialise AudioRecord
private int[] msample_rates = new int[]{44100, 22050, 11025, 8000};
private short audio_format;
private short[] audio_formats = new short[]{AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT};
private short channel_config;
private short[] channel_configs = new short[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO};
private short channelOutConfig;
public AudioRecord findAudioRecord(){
for (int rate_f : msample_rates){
for (short audioformat_f : audio_formats){
for (short channelconfig_f : channel_configs){
try {
Log.i("AudioC", "Attempting rate : "+ rate_f + "Hz, bits: " + audioformat_f + ", Channel: " + channelconfig_f);
int buffersize_f = AudioRecord.getMinBufferSize(rate_f, channelconfig_f, audioformat_f);
Log.i("AudioC", "Buffersize: " + buffersize_f);
if (buffersize_f != AudioRecord.ERROR_BAD_VALUE){
//Check of we can instantiate and have a success
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, rate_f, channelconfig_f, audioformat_f, buffersize_f);
Log.i("AudioC", "Recorder State Value: " + recorder.getState());
if(recorder.getState() == AudioRecord.STATE_INITIALIZED){
Log.i("Audio", "Success");
//global values
buffer_size = buffersize_f;
sample_rate = rate_f;
audio_format = audioformat_f;
channel_config = channelconfig_f;
if (channelconfig_f == AudioFormat.CHANNEL_IN_MONO) channelOutConfig = AudioFormat.CHANNEL_OUT_MONO;
else channelOutConfig = AudioFormat.CHANNEL_OUT_STEREO;
return recorder;
}
}
}catch (Exception e){
Log.i("AudioC", rate_f + " Exception, keep trying." + e);
}
}
}
}
Log.i("AudioC", "Failed to initialise the audio record state");
return null;
}
public void run(){
isRecording = true;
//initialization
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
//getValidSampleRates();
// int buffersize = AudioRecord.getMinBufferSize(sample_rate,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
// arec = new AudioRecord(MediaRecorder.AudioSource.MIC,sample_rate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize);
//The above lines were replaced by a looping function in order to test every occurrence of rate,audioformat and channelconfig which is usually different for different adroid devices
arec = findAudioRecord();//Still failed to initialize the Audio Recorder
atrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
sample_rate,
channelOutConfig,
audio_format,
buffer_size,
AudioTrack.MODE_STREAM);
atrack.setPlaybackRate(sample_rate);
//run
byte[] buffer = new byte[buffer_size];
arec.startRecording();
atrack.play();
while (isRecording){
arec.read(buffer, 0, buffer_size);
atrack.write(buffer, 0,buffer.length);
}
arec.release();
atrack.release();
}
public void stop(){
isRecording= false;
arec.stop();
atrack.stop();
arec.release();
atrack.release();
}
}
然后从 activity(Main Activity) 的线程或意图服务中调用它,以避免应用程序冻结。 来自线程的示例:
class playerTask implements Runnable{
public audio mic_player = new audio(); //The audio class we declared above
private Thread t;
public playerTask(){
}
public void execTask(){
t = new Thread(this,"playing_Thread");
t.start();
}
public void abortTask(){
mic_player.stop();
}
public void run(){
mic_player.run();
}
}
然后从你的activity,
public class YourActivity extends AppCompatActivity {
ToggleButton onOff;
boolean playing = false;
// Once the app start recording, the recording thread freezes the screen because of the while loop, the it works
//directly with the main thread hence doesnt release the hand until forced to stop
//For that we need to create it's own thread hence being able to play sound without freezing the remaining of the app
//private Handler myHandler
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_main);
//Handler
//Route the sound to the AUX only and always
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.setMode(AudioManager.MODE_IN_CALL);
audioManager.setSpeakerphoneOn(false);
audioManager.setWiredHeadsetOn(true);
audioManager.setBluetoothScoOn(false);
final playerTask pl_task = new playerTask();
/////Use a toggle button to start or stop the recording///You could use anything
onOff = (ToggleButton)findViewById(R.id.OnOff);
onOff.setTextOff("PLAY");
onOff.setTextOn("STOP");
onOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonview, boolean isCheked){
//Running thread
if (isCheked){
messagefield.setText("Playing");
pl_task.execTask(); ///Start streaming
}
else{
messagefield.setText("Not Playing");
pl_task.abortTask(); ///Stop streaming
}
}
});
}
这些是您需要请求的权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />