Voglio registrare l'audio dal vivo e riprodurlo. Per quanto riguarda l'interfaccia utente, l'app ha solo tre pulsanti: uno per avviare la registrazione e lo streaming, uno per giocare un file pre-registrato e l'ultimo per fermare l'attività corrente (registrazione/riproduzione). A tale scopo ho utilizzato le classi AudioRecord e AudioTrack rispettivamente per la registrazione e la riproduzione. Il mio programma si presenta come ....Registrazione audio dal vivo e riproduzione in Android e gestione thread e callback
/** * @author Amit * */
public class AudioRecorder extends Activity {
private String LOG_TAG = null;
/* variables which are required to generate and manage the UI of the App */
// private RecordButton mRecordButton = null;
private Button recordBtn, stopBtn, playBtn;
/*
* variables which are required for the actual functioning of the recording
* and playing
*/
private AudioRecord recorder = null;
private AudioTrack player = null;
private AudioManager audioManager = null;
private int recorderBufSize, recordingSampleRate;
private int trackBufSize;
private short[] audioData;
private boolean isRecording = false, isPlaying = false;
private Thread startRecThread;
private AudioRecord.OnRecordPositionUpdateListener posUpdateListener;
/**
* constructor method for initializing the variables
*/
public AudioRecorder() {
super();
LOG_TAG = "Constructor";
recorderBufSize = recordingSampleRate = trackBufSize = 0;
// init function will initialize all the necessary variables ...
init();
if (recorder != null && player != null) {
Log.e(LOG_TAG, "recorder and player initialized");
audioData = new short[recorderBufSize/2]; // since we r reading shorts
} else {
Log.e(LOG_TAG, "Problem inside init function ");
}
posUpdateListener = new AudioRecord.OnRecordPositionUpdateListener() {
int numShortsRead = 0;
@Override
public void onPeriodicNotification(AudioRecord rec) {
// TODO Auto-generated method stub
// String LOG_TAG = Thread.currentThread().getName();
// Log.e(LOG_TAG, "inside position listener");
audioData = new short[recorderBufSize/2]; // divide by 2 since now we are reading shorts
numShortsRead = rec.read(audioData, 0, audioData.length);
player.write(audioData, 0, numShortsRead);
}
@Override
public void onMarkerReached(AudioRecord recorder) {
// TODO Auto-generated method stub
Log.e(LOG_TAG, "Marker Reached");
}
};
// listener will be called every time 160 frames are reached
recorder.setPositionNotificationPeriod(160);
recorder.setRecordPositionUpdateListener(posUpdateListener);
Log.e(LOG_TAG, "inside constructor");
}
private void init() {
LOG_TAG = "initFunc";
// int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 };
short audioFormat = AudioFormat.ENCODING_PCM_16BIT;
// for (int rate : mSampleRates) {
this.recordingSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
try {
// Log.d(LOG_TAG, "Attempting rate " + rate + "Hz, bits: " +
// audioFormat);
int bufrSize = AudioRecord.getMinBufferSize(this.recordingSampleRate,
AudioFormat.CHANNEL_IN_MONO, audioFormat);
// lets find out the minimum required size for AudioTrack
int audioTrackBufSize = AudioTrack.getMinBufferSize(this.recordingSampleRate,
AudioFormat.CHANNEL_OUT_MONO, audioFormat);
if (bufrSize != AudioRecord.ERROR_BAD_VALUE
&& bufrSize != AudioRecord.ERROR) {
// check if we can instantiate and have a success
if(audioTrackBufSize >= bufrSize){
this.recorderBufSize = audioTrackBufSize;
}else{
this.recorderBufSize = bufrSize;
}
AudioRecord rec = new AudioRecord(
MediaRecorder.AudioSource.DEFAULT, this.recordingSampleRate,
AudioFormat.CHANNEL_IN_MONO, audioFormat, this.recorderBufSize);
if (rec != null
&& rec.getState() == AudioRecord.STATE_INITIALIZED) {
// storing variables for future use . . .
// this.recordingSampleRate = rate;
// this.recorderBufSize = bufrSize;
Log.e(LOG_TAG,
"Returning..(rate:channelConfig:audioFormat:recorderBufSize)"
+ this.recordingSampleRate + ":" + AudioFormat.CHANNEL_IN_MONO
+ ":" + audioFormat + ":" + this.recorderBufSize);
// Now create an instance of the AudioTrack
// int audioTrackBufSize = AudioTrack.getMinBufferSize(rate,
// AudioFormat.CHANNEL_OUT_MONO, audioFormat);
Log.e(LOG_TAG, "Audio Record/Track/Final buf size :" + bufrSize + "/ " +audioTrackBufSize + "/ "+this.recorderBufSize);
this.player = new AudioTrack(AudioManager.STREAM_MUSIC,
this.recordingSampleRate, AudioFormat.CHANNEL_OUT_MONO, audioFormat,
this.recorderBufSize, AudioTrack.MODE_STREAM);
this.recorder = rec;
this.player.stop();
this.player.flush();
this.player.setPlaybackRate(this.recordingSampleRate);
return;
}
}
} catch (IllegalArgumentException e) {
Log.d(LOG_TAG, this.recordingSampleRate + "Exception, keep trying.", e);
} catch (Exception e) {
Log.e(LOG_TAG, this.recordingSampleRate + "Some Exception!!", e);
}
// for loop for channel config ended here. . . .
// for loop for audioFormat ended here. . .
// }// for loop for sampleRate
return;
}
private void startPlaying() {
LOG_TAG = "startPlaying";
Log.e(LOG_TAG, "start Playing");
}
private void stopPlaying() {
LOG_TAG = "stopPlaying";
Log.e(LOG_TAG, "stop Playing");
}
private void startRecording() {
LOG_TAG = "startRecording";
/* start a separate recording thread from here . . . */
startRecThread = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
android.os.Process
.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
// String LOG_TAG = Thread.currentThread().getName();
if(recorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){
recorder.startRecording();
}
// Log.e(LOG_TAG, "running" +recorder.getRecordingState());
while (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
recorder.read(audioData, 0, audioData.length);
try {
Thread.sleep(1000); // sleep for 2s
} catch (InterruptedException e) {
// TODO Auto-generated catch block
Log.e("run Method", "recorder thread is interrupted");
e.printStackTrace();
}
}
}
};
setVolumeControlStream(AudioManager.STREAM_MUSIC);
audioManager.setSpeakerphoneOn(false);
player.flush();
player.play();
startRecThread.start();
Log.e(LOG_TAG, "start Recording");
}
private void stopRecording() {
LOG_TAG = "stopRecording";
recorder.stop();
if (startRecThread != null && startRecThread.isAlive()) {
startRecThread.destroy();
startRecThread = null;
}
player.stop();
player.flush();
Log.e(LOG_TAG, "stop Recording");
}
private void stop() {
if (isRecording) {
isRecording = false;
stopRecording();
}
if (isPlaying) {
isPlaying = false;
stopPlaying();
}
recordBtn.setEnabled(true);
playBtn.setEnabled(true);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LOG_TAG = "onCreate";
// Log.e(LOG_TAG, "Create Called");
// getting the audio service
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
LinearLayout ll = new LinearLayout(this);
// creating Buttons one by one . . . .
// button to start the recording process
recordBtn = new Button(this);
recordBtn.setText("Record");
recordBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
recordBtn.setEnabled(false);
playBtn.setEnabled(false);
isRecording = true;
startRecording();
}
});
// single button to stop recording and playing as applicable
stopBtn = new Button(this);
stopBtn.setText("Stop");
stopBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
stop();
}
});
// button to play the recorded sound
playBtn = new Button(this);
playBtn.setText("Play");
playBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// reverse the isPlaying
isPlaying = true;
recordBtn.setEnabled(false);
playBtn.setEnabled(false);
startPlaying();
}
});
ll.addView(recordBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
ll.addView(playBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
ll.addView(stopBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
setContentView(ll);
}
@Override
protected void onDestroy() {
// Clean up code . ..
super.onDestroy();
if (recorder != null)
recorder.release();
if (startRecThread!=null && startRecThread.isAlive())
startRecThread.destroy();
if (recorder != null)
recorder.release();
if (player != null)
player.release();
startRecThread = null;
recorder = null;
player = null;
recordBtn = null;
stopBtn = null;
playBtn = null;
audioData = null;
System.gc();
}
}
Come si può vedere che startPlaying()
e stopPlaying()
funzioni non sono ancora implementate in modo da permette di non parlare loro. Attualmente sto solo cercando di registrare e riprodurre. Quando eseguo il programma, riproduce l'audio registrato ma l'audio viene visualizzato da una distanza. Un altro problema è che il thread dell'interfaccia dell'applicazione si blocca anche se ho un thread separato per leggere l'audio. Per favore aiuto ....
scegliere uno dei tassi, configurazione, e il formato. Quindi seguiteli o fate in modo che la vostra funzione init prenda la proprietà e la passi attraverso. – L7ColWinters
@ L7ColWinters ringrazia e vedere la domanda modificata .... – aProgrammer
è la funzionalità desiderata per poter dire qualcosa durante la registrazione e la riproduce automaticamente senza toccare il gioco? Questo è ciò che fa il tuo codice attuale, anche se si blocca e riproduce un squeel molto alto, che potrebbe essere un feedback. – L7ColWinters