Android AudioRecord录制WAV保存后无法找到问题求助
Android AudioRecord录制音频后无法找到保存的WAV文件
我在Android开发中使用AudioRecord录制音频信号,通过AFSK解码音频内容,切换至SSTV模式时将录制的音频保存到设备外部存储。Logcat日志已显示文件的保存路径,但实际无法找到该WAV文件。尝试过调整代码变量的作用域(将变量设为全局、移到循环外)、创建专属保存目录等操作,问题仍未解决。
相关实现代码
startAFSKDecoder方法
private void startAFSKDecoder(double specialFrequencySSTVactivator) { checkAndShowAFSKSignalDetected(); Thread thread = new Thread(() -> { boolean saveAudio = false; // Flag to indicate when to save audio String timestamp = null; // Initialize timestamp outside the loop AudioRecord audioRecord = null; // Initialize AudioRecord outside the loop // String outputFile = null; Log.d("349 Activation", "AFSK Successfully Activated "); if (isDecoderSwitched) { Log.d("ALERT351", "Previously Decoded Message is Cleared"); isAFSKDecodingActive = true; isDecoderSwitched = false; } int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { return; } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()); timestamp = sdf.format(new Date()); // Assign timestamp here // Specify the output file path with WAV extension in external storage // audioFilePath = externalDir.getAbsolutePath() + "/audio_" + timestamp + ".wav"; // Assign to global variable audioFilePath = Environment.getExternalStorageDirectory() + "/audio_" + timestamp + ".wav"; // Assign to global variable audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); outputFile = audioFilePath; try { audioRecord.startRecording(); if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { Log.e("AudioRecordState", "AudioRecord is not in RECORDSTATE_RECORDING state after starting."); return; // Exit the thread or handle the error appropriately } Log.d("AudioRecordAFSK381", "Started audio recording successfully."); } catch (IllegalStateException e) { Log.e("AFSK_Decoder", "Failed to start audio recording: " + e.getMessage()); e.printStackTrace(); return; // Exit the thread or handle the error appropriately } StringBuilder binaryText = new StringBuilder(); boolean previousBit = false; long startTime = System.currentTimeMillis(); while (isAFSKDecodingActive) { short[] buffer = new short[bufferSize]; // Before starting recording Log.d("AudioRecording", "Starting audio recording..."); // Inside your audio recording loop int bytesRead = audioRecord.read(buffer, 0, bufferSize); if (bytesRead <= 0) { Log.d("AudioRecording", "No audio data read."); continue; } double frequency = calculateInstantaneousFrequency(buffer); if (Math.abs(frequency - specialFrequencySSTVactivator) <= frequencyTolerance) { Log.d("AFSK_Decoder", "Detected Special Frequency - Switching to SSTV"); isAFSKDecodingActive = false; isSSTVDecodingActive = true; if (audioRecord != null) { try { audioRecord.stop(); audioRecord.release(); // After stopping recording Log.d("AudioRecording", "Recording stopped."); if (audioFilePath != null) { Log.d("RecordedOutputExist", "Records Exist"); saveAudioFile(audioFilePath, "audio_" + timestamp + ".wav"); } else { Log.d("NoRecordedOutputExist", "NO Records Exist"); } } catch (IllegalStateException e) { Log.e("AFSK_Decoder417", "Failed to stop audio recording: " + e.getMessage()); } } decoder = null; stopRecordingAFSK(); break; } else { for (int i = 0; i < bytesRead; i++) { double amplitude = (double) buffer[i] / Short.MAX_VALUE; if (Math.abs(amplitude) < THRESHOLD) { amplitude = 0; } boolean currentBit = amplitude > 0; if (currentBit != previousBit) { if (currentBit) { binaryText.append("1"); //Log.d("AFSK_Decoder", "Detected Rising Edge (Mark Bit)."); } else { binaryText.append("0"); //Log.d("AFSK_Decoder", "Detected Falling Edge (Space Bit)."); } } previousBit = currentBit; } if (binaryText.length() >= MIN_BIT_COUNT && System.currentTimeMillis() - startTime > DURATION_THRESHOLD) { String decodedText = getDecodedText(binaryText.toString(), buffer); appendToDecodedText(decodedText); binaryText.setLength(0); startTime = System.currentTimeMillis(); } } } }); thread.start(); }
saveAudioFile方法
private void saveAudioFile(String sourceFilePath, String destinationFileName) { // Check if external storage is available for read and write if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { // Get the root external storage directory File externalDir = Environment.getExternalStorageDirectory(); // Use externalDir for saving files directly in the root File destinationFile = new File(externalDir, destinationFileName); // Get the absolute paths String sourceAbsolutePath = sourceFilePath; String destinationAbsolutePath = destinationFile.getAbsolutePath(); // Copy the recorded audio from source to destination try { FileInputStream inputStream = new FileInputStream(sourceAbsolutePath); FileOutputStream outputStream = new FileOutputStream(destinationFile); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } inputStream.close(); outputStream.close(); Log.d("FilePathDebug", "Source File Path: " + sourceFilePath); Log.d("FilePathDebug", "Destination File Path: " + destinationFile.getAbsolutePath()); // Delete the source file if needed File sourceFile = new File(sourceAbsolutePath); if (sourceFile.exists()) { sourceFile.delete(); } } catch (IOException e) { Log.e("FileCopyError", "Error copying audio file: " + e.getMessage()); } } else { Log.e("ExternalStorageError", "External storage is not available or not writable."); } }
问题核心原因
- 未实际写入音频数据到文件:AudioRecord仅将音频读取到内存缓冲区,代码中没有将
read获取到的PCM数据写入到audioFilePath指向的文件,导致该路径下根本不存在文件。 saveAudioFile逻辑无效:传入的源文件路径是未生成的空文件,拷贝操作从一开始就失败,后续删除操作也不会有实质效果。- 缺少WAV文件头:即使写入了PCM数据,裸PCM没有WAV文件头,也无法被系统识别为可播放的WAV文件。
修复方案
步骤1:录制过程中写入PCM数据到临时文件
修改startAFSKDecoder方法,在循环读取音频数据时,将内存中的PCM数据写入到临时文件:
private void startAFSKDecoder(double specialFrequencySSTVactivator) { checkAndShowAFSKSignalDetected(); Thread thread = new Thread(() -> { String timestamp = null; AudioRecord audioRecord = null; FileOutputStream pcmOutputStream = null; File pcmFile = null; Log.d("349 Activation", "AFSK Successfully Activated "); if (isDecoderSwitched) { Log.d("ALERT351", "Previously Decoded Message is Cleared"); isAFSKDecodingActive = true; isDecoderSwitched = false; } int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); // 动态申请录音权限 if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { return; } // 动态申请存储权限(Android 6.0+) if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1001); return; } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()); timestamp = sdf.format(new Date()); // 创建临时PCM文件 pcmFile = new File(Environment.getExternalStorageDirectory(), "audio_" + timestamp + ".pcm"); try { pcmOutputStream = new FileOutputStream(pcmFile); } catch (IOException e) { Log.e("AFSK_Decoder", "Failed to create PCM file: " + e.getMessage()); return; } audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); try { audioRecord.startRecording(); if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { Log.e("AudioRecordState", "AudioRecord is not in RECORDSTATE_RECORDING state after starting."); return; } Log.d("AudioRecordAFSK381", "Started audio recording successfully."); } catch (IllegalStateException e) { Log.e("AFSK_Decoder", "Failed to start audio recording: " + e.getMessage()); e.printStackTrace(); return; } StringBuilder binaryText = new StringBuilder(); boolean previousBit = false; long startTime = System.currentTimeMillis(); while (isAFSKDecodingActive) { short[] buffer = new short[bufferSize]; int bytesRead = audioRecord.read(buffer, 0, bufferSize); if (bytesRead <= 0) { Log.d("AudioRecording", "No audio data read."); continue; } // 将PCM数据写入临时文件 try { byte[] byteBuffer = shortToByteArray(buffer, bytesRead); pcmOutputStream.write(byteBuffer); } catch (IOException e) { Log.e("AFSK_Decoder", "Failed to write PCM data: " + e.getMessage()); } double frequency = calculateInstantaneousFrequency(buffer); if (Math.abs(frequency - specialFrequencySSTVactivator) <= frequencyTolerance) { Log.d("AFSK_Decoder", "Detected Special Frequency - Switching to SSTV"); isAFSKDecodingActive = false; isSSTVDecodingActive = true; // 关闭流和录音 try { if (pcmOutputStream != null) pcmOutputStream.close(); audioRecord.stop(); audioRecord.release(); } catch (Exception e) { Log.e("AFSK_Decoder417", "Error stopping recording: " + e.getMessage()); } // 转换PCM为标准WAV文件 convertPcmToWav(pcmFile.getAbsolutePath(), Environment.getExternalStorageDirectory() + "/audio_" + timestamp + ".wav"); // 删除临时PCM文件 if (pcmFile.exists()) pcmFile.delete(); decoder = null; stopRecordingAFSK(); break; } else { // 原有AFSK解码逻辑 for (int i = 0; i < bytesRead; i++) { double amplitude = (double) buffer[i] / Short.MAX_VALUE; if (Math.abs(amplitude) < THRESHOLD) amplitude = 0; boolean currentBit = amplitude > 0; if (currentBit != previousBit) { binaryText.append(currentBit ? "1" : "0"); } previousBit = currentBit; } if (binaryText.length() >= MIN_BIT_COUNT && System.currentTimeMillis() - startTime > DURATION_THRESHOLD) { String decodedText = getDecodedText(binaryText.toString(), buffer); appendToDecodedText(decodedText); binaryText.setLength(0); startTime = System.currentTimeMillis(); } } } }); thread.start(); } // short数组转byte数组工具方法 private byte[] shortToByteArray(short[] shorts, int length) { byte[] bytes = new byte[length * 2]; for (int i = 0; i < length; i++) { bytes[i * 2] = (byte) (shorts[i] & 0x00FF); bytes[i * 2 + 1] = (byte) ((shorts[i] & 0xFF00) >> 8); } return bytes; }
步骤2:添加PCM转WAV的方法
给裸PCM数据添加WAV文件头,生成可识别的WAV文件:
private void convertPcmToWav(String pcmFilePath, String wavFilePath) { File pcmFile = new File(pcmFilePath); File wavFile = new File(wavFilePath); long pcmSize = pcmFile.length(); try (FileInputStream fis = new FileInputStream(pcmFile); FileOutputStream fos = new FileOutputStream(wavFile)) { // 写入WAV文件头 byte[] header = new byte[44]; // RIFF标识 header[0] = 'R'; header[1] = 'I'; header[2] = 'F'; header[3] = 'F'; // 文件总大小 long totalSize = pcmSize + 36; header[4] = (byte)(totalSize & 0xff); header[5] = (byte)((totalSize >> 8) & 0xff); header[6] = (byte)((totalSize >> 16) & 0xff); header[7] = (byte)((totalSize >> 24) & 0xff); // WAVE标识 header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E'; // fmt子块标识 header[12] = 'f'; header[13] = 'm'; header[14] = 't'; header[15] = ' '; // fmt子块大小(PCM为16) header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0; // 音频格式(PCM为1) header[20] = 1; header[21] = 0; // 声道数(单声道为1) header[22] = 1; header[23] = 0; // 采样率 int sampleRate = SAMPLE_RATE; header[24] = (byte)(sampleRate & 0xff); header[25] = (byte)((sampleRate >> 8) & 0xff); header[26] = (byte)((sampleRate >> 16) & 0xff); header[27] = (byte)((sampleRate >> 24) & 0xff); // 字节率 int byteRate = sampleRate * 1 * 16 / 8; header[28] = (byte)(byteRate & 0xff); header[29] = (byte)((byteRate >> 8) & 0xff); header[30] = (byte)((byteRate >> 16) & 0xff); header[31] = (byte)((byteRate >> 24) & 0xff); // 块对齐 header[32] = (byte)(1 * 16 / 8); header[33] = 0; // 位深(16位) header[34] = 16; header[35] = 0; // data子块标识 header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a'; // 数据大小 header[40]
相关产品推荐
相关产品推荐

