我正在使用https://github.com/nonameentername/soundtouch-android/blob/master/src/org/tecunhuman/ExtAudioRecorder.java中的AudioRecord
类,但稍加修改。
在start()
方法中,我开始使用AudioRecord
类进行录制。我也开始MediaPlayer
演奏乐器。为了让人声和乐器混合在服务器上的正确位置,我发送乐器延迟以在开头用静音填充乐器(beatDelayInSeconds - MediaPlayer
从调用start到实际播放时的延迟因为启动媒体播放器时存在延迟。)
我的逻辑肯定是错的,因为人声和乐器的播放时间在设备上关闭。有时录音会太快,有时候与乐器演奏时相比会太慢。有什么建议。任何帮助将不胜感激。
为了更好的解释:
开始录音
| ---------------------------------------- |
Beat / Instrumental开始播放
[X] | ------------------------------------------- ---- |
我正在尝试找到X,所以我可以将它作为beatDelayInSeconds发送到startPlayback()方法并发送到服务器。 X是语音开始录制直到节拍实际开始播放之间的时间。目前在我的startPlayback()方法中,播放beat和vocals,它们与录制时不同步。希望这是有道理的。
注意:我必须将延迟处理程序放在一些Jelly Bean设备中,因为没有调用AudioRecord
侦听器。
public void start()
{
if (state == State.READY)
{
if (rUncompressed)
{
payloadSize = 0;
RecordReadDelayInSeconds = 0;
RecordDelayInSeconds = 0;
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mp3Path);
mPlayer.prepare();
} catch (IllegalArgumentException e) {e.printStackTrace();}
catch (SecurityException e) {e.printStackTrace();}
catch (IllegalStateException e) {e.printStackTrace();}
catch (IOException e) { e.printStackTrace();}
final long recordstarted = System.nanoTime() + 1500000000; //handler delay
audioRecorder.startRecording();
//Fix for recording issue with Samsung s3 Sprint phones.Doing a delayed first read
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
long recordstopped = System.nanoTime();
long recordDelay = recordstopped - recordstarted;
double RecordDelayInSeconds = recordDelay / 1000000.0;
Log.i("StartRecording() Delay in seconds",
String.valueOf(RecordDelayInSeconds));
long recordreadstarted = System.nanoTime();
int bytesReceived = audioRecorder.read(buffer, 0, buffer.length);
Log.d(TAG,"Delayed first read: bytes recieved "+ bytesReceived);
long recordreadstopped = System.nanoTime();
long recordreadDelay = recordreadstopped - recordreadstarted;
RecordReadDelayInSeconds = recordreadDelay / 1000000.0;
Log.i("Record read() Delay in seconds",
String.valueOf(RecordReadDelayInSeconds));
long mediastarted = System.nanoTime();
mPlayer.start();
long mediastopped = System.nanoTime();
long beatDelay = mediastopped - mediastarted;
beatDelayInSeconds = 0;
beatDelayInSeconds = (beatDelay) / 1000000000.0;
Log.i("Beat Delay in seconds",
String.valueOf(beatDelayInSeconds));
}
}, 1500);
}
这是用户在向服务器发送信息之前侦听的播放代码。它首先开始播放用户刚录制的wav,然后根据另一种方法的beatDelayInSeconds变量播放乐器。
private void startPlayback() {
wavPlayer.start();
RefreshHandler mp3PlaybackHandler = new RefreshHandler();
mp3PlaybackHandler.sleep((long) (beatDelayInSeconds * 1000));
}
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
mp3Player.start();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
Log.i(TAG, "Beat delayed for " + delayMillis + " milliseconds");
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
答案 0 :(得分:0)
我不明白“时间总是关闭”?这是什么意思?
我对你的问题和你的描述不太清楚,但这是真的:你想在一段时间后推迟执行代码块吗?
如果是这种情况,您必须考虑是否在其他UI线程内调用 new Handler().postDelayed(..)
。如果这是一个活动的过程,请尝试这个:
your_activity_instance.runOnUiThread(new Runnable()
{
@Override
public void run()
{
//delay with thread
try{
Thread.sleep(1500);
}catch(.....)
{..}
//your work load here
}
});
注意:
Handler.postDelayed()不会为您的代码块创建一个单独的线程,但只会将带有计时器标签的新消息(与您的Runnable实例相关)附加到当前线程的消息队列中。
activity.runOnUiThread()做类似的事情,但 Runnable.run()
必须等到系统回到活动UI线程然后被执行。当你想在子线程中做一些活动的工作时,这很有用。
已修改问题的更新:
我可能理解您的意图:尝试同时执行 wavPlayer.start()
和 mp3Player.start()
;但是你目前的解决方案并不好,甚至不可能:
在你使用处理程序的同一个线程中,你很难同步这两个函数(正如我所提到的,handler.run()不会产生分离的线程)。
您无法确定 hanler.run()
的确切时间戳,因为系统控制何时将消息附加到队列,延迟后的帖子是相对值。< / p>
我建议的解决方案:
您为每个玩家生成一个单独的线程。
在每个线程开始()之前,你标记时间戳(可能使用毫秒,而不是使用纳米的准确度)
在稍后调用的第二个线程中,您还会传递时间戳的DELTA(标记之间的差异)。然后使用 Thread.Sleep()
或 Handler.postDelayed()
进行同步调整。