java - 如何使用 AudioTrack 循环播放音频?
问题描述
我有一个记录 pcm 文件并保存它的程序。该文件的路径存储在一个名为pcmFile
. 我想更改此代码,以便它在无缝循环中播放 PCM 文件,直到线程停止(通过更改isPlaying
为 false)。
我有这样的AudioManager
课:
public class AudioManager {
static final String TAG = "AudioRecorder";
boolean isPlaying = false;
static final int frequency = 16000;
private static final String AUDIO_RECORDER_FOLDER = "4TRACK";
static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int playBufSize;
AudioTrack audioTrack;
String filename;
File pcmFile;
public AudioManager() {
playBufSize=AudioTrack.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
audioTrack = new AudioTrack(android.media.AudioManager.STREAM_MUSIC, frequency,
channelConfiguration, audioEncoding,
playBufSize, AudioTrack.MODE_STREAM);
audioTrack.setStereoVolume(0.7f, 0.7f);
}
public void startPlaying() {
isPlaying = true;
new PlayThread().start();
}
public void stopPlaying() {
isPlaying = false;
}
private String getFilename(){
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath,AUDIO_RECORDER_FOLDER);
return (file.getAbsolutePath() + "/" + filename + ".pcm");
}
class PlayThread extends Thread {
public void run() {
try {
System.out.println("~~Playing audio");
byte[] buffer = new byte[playBufSize];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pcmFile), playBufSize);
audioTrack.play();
int readSize = -1;
while (isPlaying && (readSize = bis.read(buffer)) != -1) {
audioTrack.write(buffer, 0, readSize);
}
audioTrack.stop();
MainActivity main = (MainActivity) ctx;
main.audioStopped();
System.out.println("~~No longer playing");
bis.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
这里的重要部分是PlayThread
类。现在它可以完美地播放 pcm 文件。如何调整此代码以便循环播放 PCM 文件?
解决方案
我可以看到您正在main.audioStopped
从您的函数调用MainActivity
通知媒体已停止播放的函数。audioStopped
您可以轻松处理MainActivity
.
我已将AudioManager
课程修改如下。其中需要在构造函数中播放的音频的context
和。这可以帮助您从您fileName
的实例中创建实例,因此,您可以在音频播放完毕后重新开始音频。AudioManager
MainActivity
public class AudioManager {
static final String TAG = "AudioRecorder";
Context ctx;
public static boolean isPlaying = false;
static final int frequency = 16000;
private static final String AUDIO_RECORDER_FOLDER = "4TRACK";
static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int playBufSize;
AudioTrack audioTrack;
String filename;
File pcmFile;
public AudioManager(Context ctx, String fileName) {
this.ctx = ctx;
this.filename = fileName;
playBufSize = AudioTrack.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
audioTrack = new AudioTrack(android.media.AudioManager.STREAM_MUSIC, frequency,
channelConfiguration, audioEncoding,
playBufSize, AudioTrack.MODE_STREAM);
audioTrack.setStereoVolume(0.7f, 0.7f);
startPlaying();
}
public void startPlaying() {
isPlaying = true;
new PlayThread().start();
}
private String getFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
return file.getAbsolutePath() + "/" + filename + ".pcm";
}
class PlayThread extends Thread {
public void run() {
try {
System.out.println("~~Playing audio");
byte[] buffer = new byte[playBufSize];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(getFilename()), playBufSize);
audioTrack.play();
int readSize = -1;
while (isPlaying && (readSize = bis.read(buffer)) != -1) {
audioTrack.write(buffer, 0, readSize);
}
audioTrack.stop();
MainActivity main = (MainActivity) ctx;
main.audioStopped();
System.out.println("~~No longer playing");
bis.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
并从中MainActivity
,检查第一个的值isPlaying
并在找到时重复启动线程true
。
public void audioStopped() {
if (AudioManager.isPlaying) {
AudioManager am = new AudioManager(this, pcmFileName);
} else {
// Do something else
}
}
希望有帮助!
推荐阅读
- xcode - 运行时的颠倒方向
- c++ - CryptoPP 生成无效密钥 RSA
- typescript - 如何在不忽略 TypeScript 警告的情况下测试 Object 是否具有键值:“字符串”不能用于索引类型?
- laravel - Laravel Backpack 的 CRUD 数据未显示在自定义操作表单上
- c - 澄清“区域不能紧密嵌套在'parallel for'区域内”
- javascript - 在任何参数行中侦听用户的 ID 和提及
- selenium - Robot Framework Keyword for Connecting and disconnecting internet
- bash - 测试带有扩展名的现有文件失败并出现通配符
- android - 在命令提示符下获取调试证书时出错
- java - 如何在纯文本中输入内容时填充运行 textView