使用AndroidRecord API录制的音频无法播放



Am正在开发一款具有记录用户语音功能的android应用程序。为此,我使用了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();
}

请帮我一下。提前谢谢。

您不必将其转换为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;

音频配置可以根据设备进行更改
请参阅此问题。


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是这样的
string.xml是这样的。

上面的代码正在运行并经过测试。

您也可以执行相同的操作,不使用文件,并使用中间缓冲区
请参阅:Android 中的音频录制和流媒体

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

我在这里张贴工作代码。

客户端代码作为Follow's,我从客户端将音频数据流式传输到网络套接字服务器。

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

希望这个能节省开发人员的很多时间。

相关内容

  • 没有找到相关文章

最新更新