2014-09-22 4 views
1

Разрабатывает приложение для Android, которое имеет функцию записи речи пользователя. Для этого я использовал AndroidRecord Audio API.Записанное аудио Использование AndroidRecord API не удается воспроизвести

В настоящее время файл pcm (записанный аудиофайл - записаноAudio.pcm) успешно сгенерирован на SD-карте. Но я не могу воспроизвести этот файл. Я попробовал на ПК также с Windows media palyer и некоторыми другими игроками. Но ничего не помогает.

Ниже приведены мои фрагмент кода.

private int minBufSize; 
private AudioRecord recorder; 
private int sampleRate = 44100; 
private int channelConfig = AudioFormat.CHANNEL_IN_MONO; 
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 
private boolean status; 

minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, 
      audioFormat); 
status = true; 
startStreaming(); 

public void startStreaming() { 
Thread streamThread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      String filePath = Environment.getExternalStorageDirectory() 
        .getPath() + "/audioRecord.pcm"; 
      FileOutputStream fileOutputStreamObj = null; 
      try { 
       fileOutputStreamObj = new FileOutputStream(filePath); 
      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
       Log.e(TAG, "Exception" + e.getMessage()); 
      } 

       // short[] sData = new short[minBufSize]; 
       byte[] buffer = new byte[minBufSize]; 

       // recorder = findAudioRecord(); 
       recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 
         sampleRate, channelConfig, audioFormat, minBufSize); 
       Log.d(TAG, "Recorder initialized"); 

       recorder.startRecording(); 

       while (status) { 
        // reading data from MIC into buffer 
        minBufSize = recorder.read(buffer, 0, buffer.length); 
        try { 
         // writes the data to file from buffer 
         // stores the voice buffer 
         // byte bData[] = short2byte(sData); 

         fileOutputStreamObj.write(buffer, 0, buffer.length); 
        } catch (IOException e) { 
         e.printStackTrace(); 
         Log.e(TAG, "Exception" + e.getMessage()); 
        } 
        // mConnection.sendBinaryMessage(buffer); 
        System.out.println("MinBufferSize: " + minBufSize); 
       } 

      } catch (Exception e) { 
       e.printStackTrace(); 
       Log.e(TAG, "Exception" + e.getMessage()); 
      } 
     } 

    }); 
    streamThread.start(); 
} 

Пожалуйста, помогите мне в этом. Заранее спасибо.

+0

Как вы пытались воспроизвести файл? По внешнему виду вы сохраняете несжатый PCM без каких-либо заголовков. Итак, почему вы даете файлу расширение .mp3? – Michael

+0

Я попытался дать .mp3 и некоторые другие расширения. Да, я не добавил заголовков и несжатых. Должен ли он добавлять заголовки? –

+1

В настоящее время ваш файл не содержит информации, которая сообщает игроку, какой аудиофайл содержит файл. Поэтому, если вы хотите, чтобы файл воспроизводился на ПК, вам, вероятно, придется помещать аудиоданные в какой-то контейнер, например WAV. – Michael

ответ

0

Да, наконец, я нашел ответ с подсказкой комментария Майкла выше.

Публикация здесь рабочего кода.

Код на стороне клиента as Follow, С клиентской стороны потоковая передача аудиоданных на сервер веб-сокетов.

private int minBufSize; 
private AudioRecord recorder; 
private int sampleRate = 44100; 
private int channelConfig = AudioFormat.CHANNEL_IN_MONO; 
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 

minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, 
       audioFormat); 
startStreaming(); 

public void startStreaming() { 
     Thread streamThread = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       try { 

        byte[] buffer = new byte[minBufSize]; 

        recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 
          sampleRate, channelConfig, audioFormat, minBufSize); 
        Log.d(TAG, "Recorder initialized"); 

        recorder.startRecording(); 

        while (status) { 

         // reading data from MIC into buffer 
         minBufSize = recorder.read(buffer, 0, buffer.length); 

         mConnection.sendBinaryMessage(buffer); 
         System.out.println("MinBufferSize: " + minBufSize); 
        } 

       } catch (Exception e) { 
        e.printStackTrace(); 
        Log.e(TAG, "Exception" + e.getMessage()); 
       } 
      } 

     }); 
     streamThread.start(); 
    } 

Server Side Code добавил реализацию следующим образом, Первый сервер создаст .pcm из потоковых данных. Затем из этого файла pcm он создаст волновой файл, добавив заголовок.

@OnMessage 
    public void onMessage(byte[] data, boolean arg1) 
    { 
    if ((!this.currentCommand.equals("stop")) && 
     (this.currentCommand.equals("start"))) 
     try { 
     System.out.println("Starting new recording."); 
     FileOutputStream fOut = new FileOutputStream(this.f2, true); 
     fOut.write(data); 
     fOut.close(); 

     properWAV(this.f2, 111133.0F); 
     } 
     catch (Exception e) { 
     e.printStackTrace(); 
     } 
    } 

private void properWAV(File fileToConvert, float newRecordingID) 
    { 
    try { 
     long mySubChunk1Size = 16L; 
     int myBitsPerSample = 16; 
     int myFormat = 1; 
     long myChannels = 1L; 
     long mySampleRate = 44100L; 
     long myByteRate = mySampleRate * myChannels * myBitsPerSample/8L; 
     int myBlockAlign = (int)(myChannels * myBitsPerSample/8L); 

     byte[] clipData = getBytesFromFile(fileToConvert); 

     long myDataSize = clipData.length; 
     long myChunk2Size = myDataSize * myChannels * myBitsPerSample/8L; 
     long myChunkSize = 36L + myChunk2Size; 

     OutputStream os = new FileOutputStream(new File("D:/audio/" + newRecordingID + ".wav")); 
     BufferedOutputStream bos = new BufferedOutputStream(os); 
     DataOutputStream outFile = new DataOutputStream(bos); 

     outFile.writeBytes("RIFF"); 
     outFile.write(intToByteArray((int)myChunkSize), 0, 4); 
     outFile.writeBytes("WAVE"); 
     outFile.writeBytes("fmt "); 
     outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4); 
     outFile.write(shortToByteArray((short)myFormat), 0, 2); 
     outFile.write(shortToByteArray((short)(int)myChannels), 0, 2); 
     outFile.write(intToByteArray((int)mySampleRate), 0, 4); 
     outFile.write(intToByteArray((int)myByteRate), 0, 4); 
     outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); 
     outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2); 
     outFile.writeBytes("data"); 
     outFile.write(intToByteArray((int)myDataSize), 0, 4); 
     outFile.write(clipData); 

     outFile.flush(); 
     outFile.close(); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 

    private static byte[] intToByteArray(int i) 
    { 
    byte[] b = new byte[4]; 
    b[0] = (byte)(i & 0xFF); 
    b[1] = (byte)(i >> 8 & 0xFF); 
    b[2] = (byte)(i >> 16 & 0xFF); 
    b[3] = (byte)(i >> 24 & 0xFF); 
    return b; 
    } 

    public static byte[] shortToByteArray(short data) 
    { 
    return new byte[] { (byte)(data & 0xFF), (byte)(data >>> 8 & 0xFF) }; 
    } 

    public byte[] getBytesFromFile(File file) 
    throws IOException 
    { 
    byte[] buffer = new byte[(int)file.length()]; 
    InputStream ios = null; 
    try { 
     ios = new FileInputStream(file); 
     if (ios.read(buffer) == -1) 
     throw new IOException("EOF reached while trying to read the whole file"); 
    } 
    finally { 
     try { 
     if (ios != null) 
      ios.close(); 
     } 
     catch (IOException localIOException) 
     { 
     } 
    } 
    try 
    { 
     if (ios != null) 
     ios.close(); 
    } 
    catch (IOException localIOException1) 
    { 
    } 
    return buffer; 
    } 

Надеюсь, что это избавит многих разработчиков от времени.

2

Вам не нужно преобразовывать его в WAV и Play.
AudioTrack может непосредственно воспроизводить записанное аудио.

Ниже приведен фрагмент кода для записи звука в файл с использованием AudioRecord и воспроизведения с использованием AudioTrack API.

Операция управляется пользователем с помощью кнопок.


Код

private int BufferSize; 
byte[] buffer = new byte[BufferSize]; 

/* AudioRecord and AudioTrack Object */ 
private AudioRecord record = null; 
private AudioTrack track = null; 

/* Audio Configuration */ 
private int sampleRate = 44100; 
private int channelConfig = AudioFormat.CHANNEL_IN_MONO; 
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 

private boolean isRecording = true; 
private Thread recordingThread = null; 

Audio Configuration может изменяться для каждого устройства.
См. Вопрос this.


GUI имеет три кнопки, запись, Стоп и Play

protected void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    setButtonHandlers(); 

    /* Set Button Visibility */ 
    enableButton(R.id.btnStartRec,true); 
    enableButton(R.id.btnStopRec,false); 
    enableButton(R.id.btnStartPlay,false); 

    BufferSize = AudioRecord.getMinBufferSize(sampleRate, 
         channelConfig, audioFormat); 
} 

/* Function to Enable/Disable Buttons */ 
private void enableButton(int id,boolean isEnable){ 
    ((Button)findViewById(id)).setEnabled(isEnable); 
} 

/* Assign OnClickListener to Buttons */ 
private void setButtonHandlers() { 
    ((Button)findViewById(R.id.btnStartRec)).setOnClickListener(btnClick); 
    ((Button)findViewById(R.id.btnStopRec)).setOnClickListener(btnClick); 
    ((Button)findViewById(R.id.btnStartPlay)).setOnClickListener(btnClick); 
} 

Обработка нажатия кнопок:

private View.OnClickListener btnClick = new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     switch(v.getId()){ 
     case R.id.btnStartRec:{ 
      Log.d(TAG, "Start Recording"); 
      enableButton(R.id.btnStartRec,false); 
      enableButton(R.id.btnStopRec,true); 
      startRecording(); 
      break; 
     } 
     case R.id.btnStopRec:{ 
      Log.d(TAG, "Stop Recording"); 
      enableButton(R.id.btnStartRec,true); 
      enableButton(R.id.btnStopRec,false); 
      stopRecording(); 
      enableButton(R.id.btnStartPlay,true); 
      break; 
     } 
     case R.id.btnStartPlay:{ 
      Log.d(TAG, "Play Recording"); 
      enableButton(R.id.btnStartRec,false); 
      enableButton(R.id.btnStopRec,false); 
      StartPlaying(); 
      break; 
     } 
     } 
    } 
}; 

Код для Start Recording

private void startRecording() 
{ 
    record = new AudioRecord(AudioSource.DEFAULT, sampleRate, 
           channelConfig, audioFormat, BufferSize); 
    if (AudioRecord.STATE_INITIALIZED == record.getState()) 
     record.startRecording(); 

    isRecording = true; 

    /* Run a thread for Recording */ 
    recordingThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      writeAudioDataToFile(); 
     } 
    },"AudioRecorder Thread"); 
    recordingThread.start(); 
} 


private void writeAudioDataToFile() 
{ 
    byte data[] = new byte[BufferSize]; 

    /* Record audio to following file */ 
    String filename = "/sdcard/audiofile.pcm"; 
    FileOutputStream os = null; 

    try { 
     os = new FileOutputStream(filename); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 

    int read_bytes = 0; 

    if(null != os){ 
     while(isRecording) 
     { 
      read_bytes = record.read(data, 0, BufferSize); 

      if(AudioRecord.ERROR_INVALID_OPERATION != read_bytes){ 
       try { 
        os.write(data); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

     try { 
      os.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Код для остановки записи

private void stopRecording() 
{ 
    if(null != record) 
    { 
     isRecording = false; 

     if (AudioRecord.STATE_INITIALIZED == record.getState()) 
     { 
      record.stop(); 
      record.release(); 
      Log.d(TAG, "===== Recording Audio Completed ===== "); 
     } 

     record = null; 
     recordingThread = null; 
    } 
} 

Код для воспроизведения аудио файла:

public void startPlaying() 
{ 
    enableButton(R.id.btnStartPlay,false); 

    int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, 
      AudioFormat.CHANNEL_OUT_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 

    track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, 
          AudioFormat.CHANNEL_OUT_MONO, 
          AudioFormat.ENCODING_PCM_16BIT, minBufferSize, 
          AudioTrack.MODE_STREAM); 

    int i = 0; 
    byte[] temp = new byte[minBufferSize]; 

    try { 
     FileInputStream fin = new FileInputStream("/sdcard/audiofile.pcm"); 
     Log.d(TAG, "===== Opening File for Playing : /sdcard/audiofile.pcm ===== "); 

     DataInputStream dis = new DataInputStream(fin); 

     track.play(); 
     while((i = dis.read(temp, 0, minBufferSize)) > -1) 
     { 
      track.write(temp, 0, i); 
     } 

     Log.d(TAG, "===== Playing Audio Completed ===== "); 
     track.stop(); 
     track.release(); 
     dis.close(); 
     fin.close(); 

    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    enableButton(R.id.btnStartRec,true); 
} 

Пожалуйста, включите следующее AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" > </uses-permission> 
<uses-permission android:name="android.permission.RECORD_AUDIO" > </uses-permission> 

activity_main.xml выглядит this.
string.xml выглядит как this.

Приведенный выше код работает и проверен.

Вы также можете сделать то же самое, без файла и используя промежуточный буфер .
Audio Recording and Streaming in Android

+0

На самом деле я должен воспроизвести этот аудиофайл на стороне сервера, а не на мобильном устройстве. Поэтому проигрыватели Windows могут воспроизводить только поддерживаемые форматы, а не файл pcm напрямую. Поэтому я только реализовал это. –

+1

Да, в этом случае вам придется преобразовать его в WAV или MP3. Я предполагал, что вы пытаетесь играть на одной стороне и, следовательно, мой ответ. –

+0

Да. Спасибо Saurabh. –