2014-09-22 58 views
1

我正在开发一款具有录制用户语音功能的android应用程序。为此,我使用了AndroidRecord Audio API。录制的音频使用AndroidRecord API无法播放

当前pcm文件(记录的音频文件 - recordedAudio.pcm)在SD卡中成功生成。但我无法播放该文件。我在PC上也尝试过使用Windows媒体播放器和其他一些播放器。但没有任何帮助。

以下是我代码片段

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 2014-09-22 09:24:48

+0

我尝试了.mp3和其他扩展名。是的,我没有添加任何标题和未压缩。是否必须添加标题? – 2014-09-22 09:28:14

+1

目前您的文件不包含任何告诉玩家该文件包含哪种音频的信息。所以如果你想要在PC上播放文件,你可能需要将音频数据放在某种容器中,比如WAV。 – Michael 2014-09-22 09:30:43

回答

0

是的,终于我找到了上面迈克尔评论线索的答案。

在这里发布工作代码。

客户端代码 as, 从客户端我流音频数据到网络套接字服务器。

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

服务器端代码加入执行如下命令, 首先,服务器将创建从流传输数据的.PCM。然后从该pcm文件开始,它将通过添加标题来创建wave文件。

@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; 

音频配置可以为每个设备改变。
请参阅this的问题。


GUI有三个按钮,记录停止播放

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; 
     } 
     } 
    } 
}; 

代码开始录制

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文件。所以只有我这样实现。 – 2014-09-23 05:40:08

+1

是的,在这种情况下,你将不得不将其转换为WAV或MP3。我认为你正在试图发挥同一方面,因此我的上述答案。 – 2014-09-23 05:58:15

+0

是的。谢谢Saurabh。 – 2014-09-23 12:49:24