音频

Emscripten自带OpenAL 1.1 API的实现,使用Web Audio API作为后端。

您可以合理地预期移植的OpenAL应用程序“开箱即用”,无需任何额外努力。只需使用-lopenal链接器标志。

这里记录了一些特定于实现的方面,值得考虑。

警告

以前没有额外的标志传递给编译器以使用OpenAL。但是,如上所述指定-lopenal应该被认为是强制性的(在将来的某个时刻,它**将**是)!

支持的OpenAL扩展

Emscripten的OpenAL实现支持以下扩展。

  • ALC_SOFT_pause_device;

  • ALC_SOFT_HRTF;

  • AL_EXT_float32;

  • AL_SOFT_loop_points;

  • AL_SOFT_source_length;

  • AL_EXT_source_distance_model;

  • AL_SOFT_source_spatialize;

警告

这并不意味着您可以假设它们的存在!为了正确性,您应该**始终**在使用扩展之前检查它是否受支持,就像一个好的应用程序会做的那样。

Emscripten上的音频指南

请注意,您的应用程序需要让步给Javascript主循环以进行音频处理(参见浏览器主循环)。简而言之,这种代码将无限期地阻塞

while(nframes < THE_NUMBER_OF_FRAMES_WE_WANT)
    alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nframes);

上面的代码片段通常在原生应用程序中有效,因为大多数OpenAL实现拥有并管理一个或多个独立线程。在Emscripten中**并非如此**。您必须做的是在每个“主循环迭代”中只执行一次这样的查询(即您通过emscripten_set_main_loop()emscripten_set_main_loop_arg()提供的回调)。

您可能会遇到的另一个问题是,浏览器不允许在用户输入之前播放音频。这可以防止页面自动播放媒体,如果您不希望这样,这可能会很烦人。Emscripten的OpenAL实现(以及SDL1)会自动监听文档和画布上的用户点击或按键,并为您恢复音频。这意味着音频应该在用户在页面上执行操作后开始播放。(参见autoResumeAudioContext()以了解这是如何在内部完成的。)

Emscripten特定捕获行为

尝试打开用户音频捕获设备的输入流会导致异步出现一个小型的浏览器特定对话框,询问用户的许可,以及在某些浏览器上,要选择的捕获设备。

考虑到这一点,当alcCaptureOpenDevice()使用有效且受支持的参数调用时,将返回一个“代理”设备,该设备在用户在上述对话框中点击“允许”之前不会成功捕获任何样本。

这意味着,当调用alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, 1, &nframes)时,nframes将保持为零,直到用户点击“允许”。您可能需要让您的应用程序处理此特定行为。

如果用户点击“拒绝”,则设备将被失效(因为这与拔掉物理设备有点类似),并且对该设备上的alcCapture*函数的调用将始终失败,错误代码为ALC_INVALID_DEVICE。您的应用程序应该准备好正确地处理这种情况。

注意

一些浏览器“记住”此选择,并在每次再次询问时自动应用它。实现无法检测到此行为。

OpenAL捕获的有用实现细节

在内部,Web Audio的捕获数据始终由Javascript Float32Array支持。因此,AL_FORMAT_MONO_FLOAT32AL_FORMAT_STEREO_FLOAT32是唯一不需要将获取的样本从其初始类型转换为另一种类型的格式。

此外,从设备获取样本的实际采样率目前由浏览器和硬件决定,而不是由用户代码决定。如果此采样率与您的应用程序请求的采样率不匹配,则实现需要代表您执行重采样。

该采样率由audioCtx.sampleRate给出,其中audioCtx是相关捕获ALCdevice内部使用的AudioContext对象。目前,Emscripten没有提供任何直接方法让应用程序访问此值,但这可能会通过特定于Emscripten的OpenAL扩展提供(这还没有出现,因为它需要注册)。

但是现在有一个快速且事实上的可靠方法来做到这一点(C示例)

#ifdef __EMSCRIPTEN__

#include <emscripten.h>

// Avoid calling this more than once! Caching the value is up to you.
unsigned query_sample_rate_of_audiocontexts() {
    return EM_ASM_INT({
        var AudioContext = window.AudioContext || window.webkitAudioContext;
        var ctx = new AudioContext();
        var sr = ctx.sampleRate;
        ctx.close();
        return sr;
    });
}
#endif

可以合理地预期此采样率为44100Hz或48000Hz。如果您好奇,您可以通过将javascript部分复制到浏览器的控制台中立即测试它。

改进和扩展实现

目前,OpenAL捕获实现执行简单的线性重采样,因为它很简单,并且质量损失很小是可以接受的。

但是,如果您愿意,欢迎您进行改进!例如,参见此问题

同样,如果您希望看到某个特定扩展的实现(无论它是否已注册),那么您最好的选择是提交一个问题(前提是之前没有为此相关问题存在),或者贡献代码!参见贡献以获取指南。