2015-09-20 10 views
1

У меня проблема, когда я записывал звук, и я нажал кнопку «Воспроизвести», он воспроизводится только около 3 секунд, а не полностью записанный звук. Я попытался увеличить размер буфера, но вместо этого он отключил мое приложение. Кто-нибудь может посоветовать, пожалуйста? ThanksAudioTrack - AudioTack не воспроизводит полностью записанный звук

Below is my code 
package com.exercise.AndroidAudioRecord; 

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 

import android.app.Activity; 
import android.media.AudioFormat; 
import android.media.AudioManager; 
import android.media.AudioRecord; 
import android.media.AudioTrack; 
import android.media.MediaRecorder; 
import android.os.Bundle; 
import android.os.Environment; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.ArrayAdapter; 
import android.widget.Button; 
import android.widget.Spinner; 
import android.widget.Toast; 

public class AndroidAudioRecordActivity extends Activity { 

    String[] freqText = {"11.025 KHz (Lowest)", "16.000 KHz", "22.050 KHz", "44.100 KHz (Highest)"}; 
    Integer[] freqset = {11025, 16000, 22050, 44100}; 
    private ArrayAdapter<String> adapter; 

    Spinner spFrequency; 
    Button startRec, stopRec, playBack; 

    Boolean recording; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     startRec = (Button)findViewById(R.id.startrec); 
     stopRec = (Button)findViewById(R.id.stoprec); 
     playBack = (Button)findViewById(R.id.playback); 

     startRec.setOnClickListener(startRecOnClickListener); 
     stopRec.setOnClickListener(stopRecOnClickListener); 
     playBack.setOnClickListener(playBackOnClickListener); 

     spFrequency = (Spinner)findViewById(R.id.frequency); 
     adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, freqText); 
     adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
     spFrequency.setAdapter(adapter); 

     stopRec.setEnabled(false); 
    } 

    OnClickListener startRecOnClickListener 
    = new OnClickListener(){ 

     @Override 
     public void onClick(View arg0) { 

      Thread recordThread = new Thread(new Runnable(){ 

       @Override 
       public void run() { 
        recording = true; 
        startRecord(); 
       } 

      }); 

      recordThread.start(); 
      startRec.setEnabled(false); 
      stopRec.setEnabled(true); 

     }}; 

    OnClickListener stopRecOnClickListener 
    = new OnClickListener(){ 

     @Override 
     public void onClick(View arg0) { 
      recording = false; 
      startRec.setEnabled(true); 
      stopRec.setEnabled(false); 
     }}; 

    OnClickListener playBackOnClickListener 
     = new OnClickListener(){ 

      @Override 
      public void onClick(View v) { 
       playRecord(); 
      } 

    }; 

    private void startRecord(){ 

     File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); 

     int selectedPos = spFrequency.getSelectedItemPosition(); 
     int sampleFreq = freqset[selectedPos]; 

     final String promptStartRecord = 
       "startRecord()\n" 
       + file.getAbsolutePath() + "\n" 
       + (String)spFrequency.getSelectedItem(); 

     runOnUiThread(new Runnable(){ 

      @Override 
      public void run() { 
       Toast.makeText(AndroidAudioRecordActivity.this, 
         promptStartRecord, 
         Toast.LENGTH_LONG).show(); 
      }}); 

     try { 
      file.createNewFile(); 

      OutputStream outputStream = new FileOutputStream(file); 
      BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); 
      DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream); 

      int minBufferSize = AudioRecord.getMinBufferSize(sampleFreq, 
        AudioFormat.CHANNEL_IN_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT); 

      short[] audioData = new short[minBufferSize]; 

      AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 
        sampleFreq, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        minBufferSize); 

      audioRecord.startRecording(); 

      while(recording){ 
       int numberOfShort = audioRecord.read(audioData, 0, minBufferSize); 
       for(int i = 0; i < numberOfShort; i++){ 
        dataOutputStream.writeShort(audioData[i]); 
       } 
      } 

      audioRecord.stop(); 
      audioRecord.release(); 
      dataOutputStream.close(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 




    void playRecord(){ 

     File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); 

     int shortSizeInBytes = Short.SIZE/Byte.SIZE; 
     int bufferSizeInBytes = (int)(file.length()/shortSizeInBytes); 

     short[] audioData = new short[bufferSizeInBytes]; 
     //int buflen=bufferSizeInBytes/2; 
     try { 
      InputStream inputStream = new FileInputStream(file); 
      BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 
      DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); 

      int i = 0; 
      while(dataInputStream.available() > 0){ 
       audioData[i] = dataInputStream.readShort(); 
       i++; 
      } 

      dataInputStream.close(); 

      int selectedPos = spFrequency.getSelectedItemPosition(); 
      int sampleFreq = freqset[selectedPos]; 
      int sampleFreq1 = 12000; 
      int sampleFreq2 = 15000; 
      final String promptPlayRecord = 
        "PlayRecord()\n" 
        + file.getAbsolutePath() + "\n" 
        + (String)spFrequency.getSelectedItem(); 

      Toast.makeText(AndroidAudioRecordActivity.this, 
        promptPlayRecord, 
        Toast.LENGTH_LONG).show(); 

      AudioTrack audioTrack = new AudioTrack(
        AudioManager.STREAM_MUSIC, 
        sampleFreq1, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        bufferSizeInBytes, 
        AudioTrack.MODE_STREAM); 

      int stereo=audioTrack.setStereoVolume(0.0f, 1.0f); 

      audioTrack.write(audioData, 0, bufferSizeInBytes); 
      audioTrack.play(); 


      AudioTrack audioTrack2 = new AudioTrack(
        AudioManager.STREAM_MUSIC, 
        sampleFreq2, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        bufferSizeInBytes, 
        AudioTrack.MODE_STREAM); 

      int stereo2=audioTrack.setStereoVolume(1.0f, 0.0f); 

      audioTrack2.write(audioData, 0, bufferSizeInBytes); 
      audioTrack2.play(); 




     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Спасибо всем!

ответ

1

Во-первых, я предполагаю, что записанный файл PCM имеет ожидаемый размер и делает весь код, который вы сбросили, связанный с записью файла неуместным.

Я вижу одну проблему в коде воспроизведения, которая приведет к воспроизведению в 1/2 от ожидаемой длины.

int shortSizeInBytes = Short.SIZE/Byte.SIZE; 
int bufferSizeInBytes = (int)(file.length()/shortSizeInBytes); 

bufferSizeInBytes должен просто file.length() и fileLength/2 это число выборок.

Где вы определяете short[] audioData вы хотите использовать количество образцов:

short[] audioData = new short[file.length()/2]; 

А где вы строите AudioTrack вы хотите использовать количество байт:

AudioTrack audioTrack = new AudioTrack(
       AudioManager.STREAM_MUSIC, 
       sampleFreq1, 
       AudioFormat.CHANNEL_OUT_STEREO, 
       AudioFormat.ENCODING_PCM_16BIT, 
       file.length(), 
       AudioTrack.MODE_STREAM); 

И, наконец, , где вы вызываете audioTrack.write, вам нужно снова использовать количество образцов.

EDIT: Из трассировки стека, добавленной в вопрос, ясно, что конструктор AudioTrack не работает с ошибкой. Вы можете проверить эту ошибку, вызвав audioTrack.status после вызова конструктора. Я могу представить пару возможных проблем.

Во-первых, вы указываете AudioTrack.MODE_STREAM, что обычно означает, что вы укажете небольшой (несколько килобайт) буфер для звуковой дорожки, а затем выполните последовательные вызовы функции write для воспроизведения всего исходного буфера. С другой стороны, AudioTrack.MODE_STATIC используется для воспроизведения всего буфера одним выстрелом - как вы пытаетесь сделать. Учитывая, что целью в MODE_STREAM является использование самого маленького буфера, возможно, что указание размера буфера 1,64 МБ (20 секунд * 2 байта на образец * 44100) не поддерживается. Поэтому первое, что я хотел бы сделать, это изменить режим MODE_STATIC. Я не знаю API достаточно хорошо, чтобы сказать вам, если размер буфера, который большой даже поддерживается в этом режиме. Если нет, тогда вам нужно будет протолкнуть правильный путь.

+0

Привет, Спасибо вам за помощь – user1730935

+0

Привет, Спасибо вам за помощь. Я отредактировал код, как вы упомянули. Но если я попытался записать звук примерно через 20 секунд и нажал кнопку «play», он просто сработает приложение. Почему это происходит? Это из-за моего размера буфера недостаточно? Привет, Спасибо за вашу помощь. Я отредактировал код, как вы упомянули. Но если я попытался записать звук примерно через 20 секунд и нажал кнопку «play», он просто сработает приложение. Почему это происходит? audioTrack.write (audioData, 0, (int) (file.length()/2)); audioTrack.play(); – user1730935

+0

«Просто падает» довольно расплывчато. Какое исключение выбрасывается и из какой строки? – jaket

0

Logcat Выход

09-22 01:23:42.940: I/Reverb(22286): getpid() 22286, IPCThreadState::self()->getCallingPid() 22286 
09-22 01:23:42.955: E/AudioTrack(22286): AudioFlinger could not create track, status: -12 
09-22 01:23:42.955: E/AudioTrack-JNI(22286): Error initializing AudioTrack 
09-22 01:23:42.965: E/AudioTrack-Java(22286): [ android.media.AudioTrack ] Error code -20 when initializing AudioTrack. 
09-22 01:23:42.965: D/AndroidRuntime(22286): Shutting down VM 
09-22 01:23:42.965: W/dalvikvm(22286): threadid=1: thread exiting with uncaught exception (group=0x40eed2a0) 
09-22 01:23:42.985: E/AndroidRuntime(22286): FATAL EXCEPTION: main 
09-22 01:23:42.985: E/AndroidRuntime(22286): java.lang.IllegalStateException: play() called on uninitialized AudioTrack. 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.media.AudioTrack.play(AudioTrack.java:887) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at com.example.android2.MainActivity.playRecord(MainActivity.java:225) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at com.example.android2.MainActivity$3.onClick(MainActivity.java:99) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.view.View.performClick(View.java:4211) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.view.View$PerformClick.run(View.java:17267) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.os.Handler.handleCallback(Handler.java:615) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.os.Handler.dispatchMessage(Handler.java:92) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.os.Looper.loop(Looper.java:137) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at android.app.ActivityThread.main(ActivityThread.java:4898) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at java.lang.reflect.Method.invokeNative(Native Method) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at java.lang.reflect.Method.invoke(Method.java:511) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773) 
09-22 01:23:42.985: E/AndroidRuntime(22286): at dalvik.system.NativeStart.main(Native Method) 

Ниже исправленный код

void playRecord(){ 

     File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); 

     short[] audioData = new short[(int) (file.length()/2)]; 
     try { 
      InputStream inputStream = new FileInputStream(file); 
      BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 
      DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); 

      int i = 0; 
      while(dataInputStream.available() > 0){ 
       audioData[i] = dataInputStream.readShort(); 
       i++; 
      } 

      dataInputStream.close(); 

      int selectedPos = spFrequency.getSelectedItemPosition(); 
      int sampleFreq = freqset[selectedPos]; 
      int sampleFreq1 = 44100; 
      int sampleFreq2 = 44400; 
      final String promptPlayRecord = 
        "PlayRecord()\n" 
        + file.getAbsolutePath() + "\n" 
        + (String)spFrequency.getSelectedItem(); 

      Toast.makeText(MainActivity.this, 
        promptPlayRecord, 
        Toast.LENGTH_LONG).show(); 

      AudioTrack audioTrack = new AudioTrack(
        AudioManager.STREAM_MUSIC, 
        sampleFreq1, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        (int)file.length(), 
        AudioTrack.MODE_STREAM); 

      int stereo=audioTrack.setStereoVolume(0.0f, 1.0f); 

      audioTrack.write(audioData, 0, (int)(file.length()/2)); 
      audioTrack.play(); 

      AudioTrack audioTrack2 = new AudioTrack(
        AudioManager.STREAM_MUSIC, 
        sampleFreq2, 
        AudioFormat.CHANNEL_OUT_STEREO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        (int)file.length(), 
        AudioTrack.MODE_STREAM); 

      int stereo2=audioTrack2.setStereoVolume(1.0f, 0.0f); 

      audioTrack2.write(audioData, 0, (int)(file.length()/2)); 
      audioTrack2.play(); 

     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Вы пытаетесь создать два AudioTracks одновременно на одном устройстве вывода. – AterLux

0

Вы прочитать блок данных только один раз здесь.

 while(dataInputStream.available() > 0){ 
      audioData[i] = dataInputStream.readShort(); 
      i++; 
     } 

Поскольку доступна она не останется размер, но размер, который доступен для чтения без блокировки (т.е. он может быть равен нулю, а больше данных остаются непрочитанными), вам необходимо прочитать до read метод возвращает меньше нуля (т.е. EOF).Например:

// Do here AudioTrack initialization 
// ... 
InputStream inputStream = new FileInputStream(file); 
byte[] byteBuf = new byte[32768]; // just any even size 
short[] shortBuf = new short[byteBuf.length/2]; // buffer of shorts 
audioTrack.play(); // start playback. Will wait until first data is written 
for(;;) { 
    int l = inputStream.read(byteBuf); 
    if (l < 0) break; // finish reading when EOF is truly reached 
    int o = 0; 
    for (int i = 0; i < l; i += 2) { 
     shortBuf[o] = (short)((byteBuf[i] << 8) | (byteBuf[i + 1] & 0xFF)); // convert two big-endian bytes to one short 
     o++; 
    } 
    int res = audioTrack.write(shortBuf, 0, o); // write next portion 
    if (res < 0) { 
     // handle audio writing error; 
     break; 
    } 
} 
// ... 

 Смежные вопросы

  • Нет связанных вопросов^_^