【发布时间】:2021-12-27 23:02:40
【问题描述】:
我在 Android 上将音频作为原始字节录制到一个变量中,该变量可由 AudioTrack 的实例播放。
也就是说,不是作为文件。
我选择了采样率为 44100 的 8 位单声道 PCM,因为该音频数据应该是未压缩的……并且是可预测的、与平台无关的格式。
别担心...我们在这里只处理小型音频 sn-ps...此外,现在人们拥有如此多的 RAM,以至于它是超高频的。
我已经尝试过下面的方法......虽然它显然有效,但相关部分 writeAudioToLocalVariable() 是来自互联网的修改后的剪切粘贴而且我对内容还不是很了解。
考虑到我们无法预测最终用户设备的硬件能力,是否有更博学的人告诉我,这是否是 writeAudioToLocalVariable() 函数中最稳定可靠的处理方式?
这是我得到的:
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.pm.PackageManager;
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.util.Log;
import android.view.View;
import java.io.ByteArrayOutputStream;
public class MainActivity extends AppCompatActivity {
private static final int NOT_USED = 999999999;
private static final int SAMPLERATE = 44100;
private static final int REC_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int PLAYBACK_CHANNELS = AudioFormat.CHANNEL_OUT_MONO;
private static final int ENCODING = AudioFormat.ENCODING_PCM_8BIT;
// !!! needs to be large enough for all devices
private static final int MY_CHOSEN_BUFFER_SIZE = 8192;
private AudioRecord recorder = null;
private Thread recordingThread = null;
boolean isRecording = false;
byte[] recordedAudioAsBytes; // <------ this is where recorded audio ends up
AudioTrack player;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLERATE,
REC_CHANNELS, ENCODING);
Log.i("ABC", "FYI, min buffer size for this device is : " + minBufferSize);
}
private void startRecording() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, NOT_USED);
Log.i("ABC", "permission fail, returning.");
return;
}
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLERATE, REC_CHANNELS,
ENCODING, MY_CHOSEN_BUFFER_SIZE);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
public void run() {
Log.i("ABC", "the thread is running");
writeAudioToLocalVariable();
}
}, "AudioRecorder Thread");
recordingThread.start();
}
private void writeAudioToLocalVariable() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] temporaryChunkOfBytes = new byte[MY_CHOSEN_BUFFER_SIZE];
while (isRecording) {
recorder.read(temporaryChunkOfBytes, 0, MY_CHOSEN_BUFFER_SIZE);
try {
System.out.println("Appending to baos : " + temporaryChunkOfBytes);
//printBytes(temporaryChunkOfBytes);
baos.write(temporaryChunkOfBytes, 0, MY_CHOSEN_BUFFER_SIZE);
} catch (Exception e) {
Log.i("ABC", "Exception while appending bytes : " + e); // <----- this is not called and that is good.
}
}
recordedAudioAsBytes = baos.toByteArray();
}
private void stopRecording() {
// stops the recording activity
if (null != recorder) {
isRecording = false;
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
}
public void recordButtonClicked(View v) {
isRecording = true;
startRecording();
}
public void stopButtonClicked(View v) {
isRecording = false;
stopRecording();
}
public void playButtonPressed(View v) {
// this verifies that audio data exists as expected
for (int i=0; i<recordedAudioAsBytes.length; i++) {
Log.i("ABC", "byte[" + i + "] = " + recordedAudioAsBytes[i]);
}
// STREAM MODE ACTUALLY WORKS!! (STATIC MODE DOES NOT WORK)
AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLERATE, PLAYBACK_CHANNELS,
ENCODING, MY_CHOSEN_BUFFER_SIZE, AudioTrack.MODE_STREAM);
player.play();
player.write(recordedAudioAsBytes, 0, recordedAudioAsBytes.length);
}
}
谢谢你...来自我和许多其他人在未来丰富的 RAM !
【问题讨论】:
标签: java android audio encoding audiorecord