- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我想录制现场音频并播放它。就 UI 而言,该应用程序只有三个按钮:一个用于开始录制和流式传输,一个用于播放预先录制的文件,最后一个用于停止当前任务(录音/播放)。为此,我分别使用了 AudioRecord 和 AudioTrack 类进行录音和播放。我的程序看起来像....
/** * @作者阿米特 * */
public class AudioRecorder extends Activity {
private String LOG_TAG = null;
/* variables which are required to generate and manage the UI of the App */
// private RecordButton mRecordButton = null;
private Button recordBtn, stopBtn, playBtn;
/*
* variables which are required for the actual functioning of the recording
* and playing
*/
private AudioRecord recorder = null;
private AudioTrack player = null;
private AudioManager audioManager = null;
private int recorderBufSize, recordingSampleRate;
private int trackBufSize;
private short[] audioData;
private boolean isRecording = false, isPlaying = false;
private Thread startRecThread;
private AudioRecord.OnRecordPositionUpdateListener posUpdateListener;
/**
* constructor method for initializing the variables
*/
public AudioRecorder() {
super();
LOG_TAG = "Constructor";
recorderBufSize = recordingSampleRate = trackBufSize = 0;
// init function will initialize all the necessary variables ...
init();
if (recorder != null && player != null) {
Log.e(LOG_TAG, "recorder and player initialized");
audioData = new short[recorderBufSize / 2]; // since we r reading shorts
} else {
Log.e(LOG_TAG, "Problem inside init function ");
}
posUpdateListener = new AudioRecord.OnRecordPositionUpdateListener() {
int numShortsRead = 0;
@Override
public void onPeriodicNotification(AudioRecord rec) {
// TODO Auto-generated method stub
// String LOG_TAG = Thread.currentThread().getName();
// Log.e(LOG_TAG, "inside position listener");
audioData = new short[recorderBufSize / 2]; // divide by 2 since now we are reading shorts
numShortsRead = rec.read(audioData, 0, audioData.length);
player.write(audioData, 0, numShortsRead);
}
@Override
public void onMarkerReached(AudioRecord recorder) {
// TODO Auto-generated method stub
Log.e(LOG_TAG, "Marker Reached");
}
};
// listener will be called every time 160 frames are reached
recorder.setPositionNotificationPeriod(160);
recorder.setRecordPositionUpdateListener(posUpdateListener);
Log.e(LOG_TAG, "inside constructor");
}
private void init() {
LOG_TAG = "initFunc";
// int[] mSampleRates = new int[] { 8000, 11025, 22050, 44100 };
short audioFormat = AudioFormat.ENCODING_PCM_16BIT;
// for (int rate : mSampleRates) {
this.recordingSampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
try {
// Log.d(LOG_TAG, "Attempting rate " + rate + "Hz, bits: " +
// audioFormat);
int bufrSize = AudioRecord.getMinBufferSize(this.recordingSampleRate,
AudioFormat.CHANNEL_IN_MONO, audioFormat);
// lets find out the minimum required size for AudioTrack
int audioTrackBufSize = AudioTrack.getMinBufferSize(this.recordingSampleRate,
AudioFormat.CHANNEL_OUT_MONO, audioFormat);
if (bufrSize != AudioRecord.ERROR_BAD_VALUE
&& bufrSize != AudioRecord.ERROR) {
// check if we can instantiate and have a success
if(audioTrackBufSize >= bufrSize){
this.recorderBufSize = audioTrackBufSize;
}else{
this.recorderBufSize = bufrSize;
}
AudioRecord rec = new AudioRecord(
MediaRecorder.AudioSource.DEFAULT, this.recordingSampleRate,
AudioFormat.CHANNEL_IN_MONO, audioFormat, this.recorderBufSize);
if (rec != null
&& rec.getState() == AudioRecord.STATE_INITIALIZED) {
// storing variables for future use . . .
// this.recordingSampleRate = rate;
// this.recorderBufSize = bufrSize;
Log.e(LOG_TAG,
"Returning..(rate:channelConfig:audioFormat:recorderBufSize)"
+ this.recordingSampleRate + ":" + AudioFormat.CHANNEL_IN_MONO
+ ":" + audioFormat + ":" + this.recorderBufSize);
// Now create an instance of the AudioTrack
// int audioTrackBufSize = AudioTrack.getMinBufferSize(rate,
// AudioFormat.CHANNEL_OUT_MONO, audioFormat);
Log.e(LOG_TAG, "Audio Record / Track / Final buf size :" + bufrSize + "/ " +audioTrackBufSize + "/ "+this.recorderBufSize);
this.player = new AudioTrack(AudioManager.STREAM_MUSIC,
this.recordingSampleRate, AudioFormat.CHANNEL_OUT_MONO, audioFormat,
this.recorderBufSize, AudioTrack.MODE_STREAM);
this.recorder = rec;
this.player.stop();
this.player.flush();
this.player.setPlaybackRate(this.recordingSampleRate);
return;
}
}
} catch (IllegalArgumentException e) {
Log.d(LOG_TAG, this.recordingSampleRate + "Exception, keep trying.", e);
} catch (Exception e) {
Log.e(LOG_TAG, this.recordingSampleRate + "Some Exception!!", e);
}
// for loop for channel config ended here. . . .
// for loop for audioFormat ended here. . .
// }// for loop for sampleRate
return;
}
private void startPlaying() {
LOG_TAG = "startPlaying";
Log.e(LOG_TAG, "start Playing");
}
private void stopPlaying() {
LOG_TAG = "stopPlaying";
Log.e(LOG_TAG, "stop Playing");
}
private void startRecording() {
LOG_TAG = "startRecording";
/* start a separate recording thread from here . . . */
startRecThread = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
android.os.Process
.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
// String LOG_TAG = Thread.currentThread().getName();
if(recorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING){
recorder.startRecording();
}
// Log.e(LOG_TAG, "running" +recorder.getRecordingState());
while (recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
recorder.read(audioData, 0, audioData.length);
try {
Thread.sleep(1000); // sleep for 2s
} catch (InterruptedException e) {
// TODO Auto-generated catch block
Log.e("run Method", "recorder thread is interrupted");
e.printStackTrace();
}
}
}
};
setVolumeControlStream(AudioManager.STREAM_MUSIC);
audioManager.setSpeakerphoneOn(false);
player.flush();
player.play();
startRecThread.start();
Log.e(LOG_TAG, "start Recording");
}
private void stopRecording() {
LOG_TAG = "stopRecording";
recorder.stop();
if (startRecThread != null && startRecThread.isAlive()) {
startRecThread.destroy();
startRecThread = null;
}
player.stop();
player.flush();
Log.e(LOG_TAG, "stop Recording");
}
private void stop() {
if (isRecording) {
isRecording = false;
stopRecording();
}
if (isPlaying) {
isPlaying = false;
stopPlaying();
}
recordBtn.setEnabled(true);
playBtn.setEnabled(true);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LOG_TAG = "onCreate";
// Log.e(LOG_TAG, "Create Called");
// getting the audio service
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
LinearLayout ll = new LinearLayout(this);
// creating Buttons one by one . . . .
// button to start the recording process
recordBtn = new Button(this);
recordBtn.setText("Record");
recordBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
recordBtn.setEnabled(false);
playBtn.setEnabled(false);
isRecording = true;
startRecording();
}
});
// single button to stop recording and playing as applicable
stopBtn = new Button(this);
stopBtn.setText("Stop");
stopBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
stop();
}
});
// button to play the recorded sound
playBtn = new Button(this);
playBtn.setText("Play");
playBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// reverse the isPlaying
isPlaying = true;
recordBtn.setEnabled(false);
playBtn.setEnabled(false);
startPlaying();
}
});
ll.addView(recordBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
ll.addView(playBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
ll.addView(stopBtn, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
setContentView(ll);
}
@Override
protected void onDestroy() {
// Clean up code . ..
super.onDestroy();
if (recorder != null)
recorder.release();
if (startRecThread!=null && startRecThread.isAlive())
startRecThread.destroy();
if (recorder != null)
recorder.release();
if (player != null)
player.release();
startRecThread = null;
recorder = null;
player = null;
recordBtn = null;
stopBtn = null;
playBtn = null;
audioData = null;
System.gc();
}
}
如您所见,startPlaying()
和 stopPlaying()
函数尚未实现,因此暂且不谈。目前我只是想录制和播放。当我运行程序时,它会播放录制的音频,但音频似乎是从远处传来的。另一个问题是,虽然我有一个单独的线程用于读取音频,但应用程序的 UI 线程挂起。请帮忙....
最佳答案
如果您的要求是在录制时播放(意味着循环播放音频),在您的 while 循环线程中,您正在存储录制的数据(audioData 缓冲区),您可以将其复制到播放器对象中while 循环(player.write(audioData,0,numShortsRead);)。你说你的 UI 线程卡住了,这可能是因为你更优先考虑音频记录线程。
检查下面我用于上述环回要求的代码
boolean m_isRun=true;
public void loopback() {
// Prepare the AudioRecord & AudioTrack
try {
buffersize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT);
if (buffersize <= BUF_SIZE) {
buffersize = BUF_SIZE;
}
Log.i(LOG_TAG,"Initializing Audio Record and Audio Playing objects");
m_record = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffersize * 1);
m_track = new AudioTrack(AudioManager.STREAM_ALARM,
SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffersize * 1,
AudioTrack.MODE_STREAM);
m_track.setPlaybackRate(SAMPLE_RATE);
} catch (Throwable t) {
Log.e("Error", "Initializing Audio Record and Play objects Failed "+t.getLocalizedMessage());
}
m_record.startRecording();
Log.i(LOG_TAG,"Audio Recording started");
m_track.play();
Log.i(LOG_TAG,"Audio Playing started");
while (m_isRun) {
m_record.read(buffer, 0, BUF_SIZE);
m_track.write(buffer, 0, buffer.length);
}
Log.i(LOG_TAG, "loopback exit");
}
private void do_loopback() {
m_thread = new Thread(new Runnable() {
public void run() {
loopback();
}
});
还有一件事,如果您的要求是录制几秒钟然后播放,在播放时您的录制应该重新开始,您可以使用延迟处理线程来实现,在该线程中您可以停止录制复制缓冲区,然后开始记录。
关于android - Android 中的实时音频录制和播放以及线程和回调处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9413998/
我做了一个项目,使用两个不同的textview进行触摸来播放两个音频。 这是一个文本 View 的简单代码 tv.setOnTouchListener(new OnTouchListener() {
我正在使用 pygame 模块在 python 中操作声音文件。它在交互式 python session 中工作正常,但相同的代码在 bash 中不会产生任何结果: 交互式Python $ sudo
请注意它只能是 JavaScript。请参阅下面我当前的 HTML。我需要像当前代码一样在页面之间旋转。但是,我需要能够在页面之间暂停/播放。
我有一个带有一堆音频链接的html。我正在尝试使所有音频链接都在单击时播放/暂停,并且尝试了here解决方案。这正是我所追求的,只是我现在不得不修改此功能以应用于代码中的所有音频链接(因为我不能为每个
在尝试进入我的代码中的下一个文件之前,我尝试随机播放.wav文件数毫秒。最好的方法是什么? 我目前有以下代码: #!/usr/bin/env python from random import ran
我有2个回调函数,一个播放音频,另一个停止音频。 function Play_Callback(hObject, eventdata, handles) global path; global pla
我有一个电台应用程序,并与carplay集成。在Carplay仪表板中,我仅看到专辑封面图像和停止按钮。我想在仪表板上显示播放/暂停和跳过按钮。如果您对该站有任何了解,可以帮我吗? 最佳答案 您需要使
我正在使用 ffmpeg 创建一个非常基本的视频播放器。库,我有所有的解码和重新编码,但我坚持音频视频同步。 我的问题是,电影有音频和视频流混合(交织),音频和视频以“突发”(多个音频包,然后是并列的
我不知道我在做什么错 $(document).ready(function() { var playing = false; var audioElement = document.
我正在尝试通过(input:file)Elem加载本地音频文件,当我将其作为对象传递给音频构造函数Audio()时,它不会加载/播放。 文件对象参数和方法: lastModified: 1586969
在 Qt 中创建播放/暂停按钮的最佳方法是什么?我应该创建一个操作并在单击时更改其图标,还是应该创建两个操作然后以某种方式在单击时隐藏一个操作?如何使用一个快捷键来激活这两个操作? (播放时暂停,暂停
我正在用 Python 和 SQLite 构建一个预订系统。 我有一个 Staff.db 和 Play.db (一对多关系)。这个想法是这样的:剧院的唯一工作人员可以通过指定开始日期和时间来选择何时添
我有一个服务于 AAC+ (HE v2) 的 Icecast 服务器。我在我的网页中使用 JPlayer 来播放内容。在没有 Flash Player 的 Chromium 中,它工作得很好。 对于支
当我运行我的方法时,我收到一个MediaException。我使用 playSound("src/assets/timeup.mp3"); 调用该方法。 private void playSound(
我有一项正在播放播客的服务。我希望该服务检测用户何时按下暂停或从他们的 BT radio 播放,以便我可以停止和启动它。对于我的生活,我无法弄清楚要向我的监听器添加什么过滤器(当我按下 BT 按钮时,
我对 Java 不是很在行,在研究网站上的音乐循环的简单播放/暂停按钮后,我得到了这段代码。它可以很好地离线测试,但在上传到 FTP 服务器后,它不会在任何浏览器中播放音频,我得到 SyntaxErr
我有一个使用 flickity carousel library 创建的视频轮播, 见过 here on codepen .我想要发生的是,当用户滑动轮播时,所选幻灯片停止播放,然后占据所选中间位置的
这是一个 JSFiddle: http://jsfiddle.net/8LczkwLz/19/ HTML: JS: var flashcardAudio = documen
我的问题是我无法将歌曲标题文本保持在 line-height: 800px;当用户播放或暂停播放器时。我设法在 :hover 上做到了。这似乎是一件非常棘手的事情,这真的是我第一次遇到 CSS 如此困
我还没有找到与我的完全一样的帖子,所以这就是问题所在。我正在制作一个 mp3 播放器,播放/暂停是两个单独的按钮。这是我的代码。 prevButton = document.getElementByI
我是一名优秀的程序员,十分优秀!