Живая аудиозапись и воспроизведение в Android и обработка обратного вызова и обратного вызова

Я хочу записать живое аудио и воспроизвести его. Что касается UI, приложение имеет всего три кнопки: один для начала записи и потоковой передачи, один для воспроизведения предварительно записанного файла и последний для остановки текущей задачи (запись / Воспроизведение). Для этой цели я использовал классы AudioRecord и AudioTrack для записи и воспроизведения соответственно. Моя программа выглядит …

/ ** * @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(); } } 

Поскольку вы можете видеть, что функции startPlaying() и stopPlaying() еще не реализованы, давайте не будем говорить о них. В настоящее время я просто пытаюсь записать и воспроизвести. Когда я запускаю программу, он воспроизводит записанный звук, но звук появляется издалека. Другая проблема заключается в том, что поток пользовательского интерфейса приложения зависает, хотя у меня есть отдельный поток для чтения аудио . Пожалуйста помоги….

Solutions Collecting From Web of "Живая аудиозапись и воспроизведение в Android и обработка обратного вызова и обратного вызова"

Если ваше требование находится во время записи, оно должно воспроизводиться (означает циклическое воспроизведение звука). В потоке цикла while вы сохраняете записанные данные (builder audioData), там вы можете скопировать его в объект игрока с помощью цикла while ( Player.write (audioData, 0, numShortsRead);). Вы сказали, что ваш поток пользовательского интерфейса застрял, возможно, из-за того, что вы уделяете больше внимания потоку аудиозаписи.

Проверьте приведенный ниже код, который я использовал для вышеуказанного требования обратной связи

 boolean m_isRun=true; public void loopback() { // Prepare the AudioRecord & AudioTrack try { buffersize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); if (buffersize <= BUF_SIZE) { buffersize = BUF_SIZE; } Log.i(LOG_TAG,"Initializing Audio Record and Audio Playing objects"); m_record = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize * 1); m_track = new AudioTrack(AudioManager.STREAM_ALARM, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, buffersize * 1, AudioTrack.MODE_STREAM); m_track.setPlaybackRate(SAMPLE_RATE); } catch (Throwable t) { Log.e("Error", "Initializing Audio Record and Play objects Failed "+t.getLocalizedMessage()); } m_record.startRecording(); Log.i(LOG_TAG,"Audio Recording started"); m_track.play(); Log.i(LOG_TAG,"Audio Playing started"); while (m_isRun) { m_record.read(buffer, 0, BUF_SIZE); m_track.write(buffer, 0, buffer.length); } Log.i(LOG_TAG, "loopback exit"); } private void do_loopback() { m_thread = new Thread(new Runnable() { public void run() { loopback(); } }); 

Еще одна вещь: если ваше требование – запись в течение нескольких секунд, а затем воспроизведение, в то время как воспроизведение вашей записи должно начинаться снова, вы можете сделать это с помощью потока обработчика задержки с тайм-аутом. В этом потоке вы можете прекратить запись копии буфера , Затем начните запись.

Мое предложение состоит в том, чтобы использовать задачу Async, другую, известную как безболезненная резьба. Это лучший способ использовать потоки в Android. Вы можете использовать методы фоновой обработки, предзапуска и отправки, деля вашу существующую программу.

http://android-developers.blogspot.ca/2009/05/painless-threading.html