在nativescript/javascript中运行非阻塞、高性能的活动



这个问题是关于在nativedescription中运行一个非阻塞、高性能的活动,这是通过本机Android API直接访问硬件从麦克风读取和保存原始音频的简单任务所需的。我相信我已经将本机描述的框架带到了它的能力的边缘,我需要专家的帮助。

我正在Nativescript Android中构建一个WAV录音机。这里描述了本机实现(下面是相关代码(。

简而言之,这可以通过从android.media.AudioRecord缓冲区读取音频蒸汽,然后将缓冲区写入单独线程中的文件来完成,如所述:

原生Android实现

按下按钮触发startRecording(),并启动运行writeAudioDataToFile():的新线程

private void startRecording() {
// ... init Recorder
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
@Override
public void run() {
writeAudioDataToFile();
}
}, "AudioRecorder Thread");
recordingThread.start();
}

通过将isRecording设置为false停止记录(按下按钮触发stopRecording()(:

private void stopRecording() {
isRecording = false;
recorder.stop();
recorder.release();
recordingThread = null;
}

如果isRecording=false,则停止读取和保存缓冲区:

private void writeAudioDataToFile() {
// ... init file and buffer
ByteArrayOutputStream recData = new ByteArrayOutputStream(); 
DataOutputStream dos = new DataOutputStream(recData);
int read = 0;
while(isRecording) {
read = recorder.read(data, 0, bufferSize);
for(int i = 0; i < bufferReadResult; i++) {
dos.writeShort(buffer[i]);
}
}
}

我的Nativescript javascript实现:

我写了一个本机描述的typescript代码,它的作用与上面的本机Android代码相同。我面临的问题#1是,我无法运行while(isRecording),因为javascript线程将忙于在while循环中运行,并且永远无法捕捉到运行stopRecording()的按钮点击。

我试图通过使用setInterval进行异步执行来解决问题#1,如下所示:

按下按钮触发startRecording(),并设置10ms的时间间隔执行writeAudioDataToFile():

startRecording() {
this.audioRecord.startRecording();
this.audioBufferSavingTimer = setInterval(() => this.writeAudioDataToFile(), 10);
}

writeAudioDataToFile()回调每10ms排队一次:

writeAudioDataToFile() {
let bufferReadResult = this.audioRecord.read(
this.buffer,
0,
this.minBufferSize / 4
);
for (let i = 0; i < bufferReadResult; i++) {
dos.writeShort(buffer[i]);
}
}

通过清除时间间隔停止记录(按下按钮触发stopRecording()(:

stopRecording() {
clearInterval(this.audioBufferSavingTimer);
this.audioRecord.stop();
this.audioRecord.release();
}

问题2:虽然这很有效,但在许多情况下,它会使UI冻结1-10秒(例如,在单击按钮停止录制后(。

我试图将执行writeAudioDataToFile()的时间间隔从10ms更改为0ms,最高可达1000ms(同时具有很大的缓冲区(,但随后UI冻结时间更长,并且我在保存的数据中遇到了丢失(未保存到文件中的缓冲数据(。

我试图通过使用本文所述的本机描述的工作线程将此操作卸载到一个单独的线程,其中startRecording()stopRecording()由发送到线程的消息调用,如下所示:

global.onmessage = function(msg) {
if (msg.data === 'startRecording') {
startRecording();
} else if (msg.data === 'stopRecording') {
stopRecording();
} 
}

这解决了UI问题,但产生了问题#3:记录器stop未按时执行(即在工作线程收到"stopRecording"消息数据后10到50秒停止录制(。我尝试在工作线程内的setInterval中使用不同的时间间隔(0ms到1000ms(,但这并没有解决问题,甚至使stopRecording()的执行延迟更大。

有人知道如何在nativescript/javascript中执行这样一个无阻塞的高性能录制活动吗?有没有更好的方法来解决我上面描述的问题#1(javascript异步执行(?

感谢

我会在实际的Java中保留完整的Java实现,您可以通过在插件文件夹中创建一个Java文件来做到这一点:平台/android/java,所以可能有类似的东西:platforms/android/java.org/nativescriptt/AudioRecord.java

在那里,你可以做任何线程化的事情,这样你就不会因为UI被阻止而感到困扰。您可以直接从NativeScript调用Java方法来启动和停止录制。当您构建项目时,Java文件将自动编译并包含在内。

您可以通过从插件({plugin_name}.aar(的生成.aar文件中获取classes.jar,并为其生成类型声明,从Java类中生成打字法:https://docs.nativescript.org/core-concepts/android-runtime/metadata/generating-typescript-declarations

这样,您就可以在编辑器中获得所有可用的方法/类/类型信息。

最新更新