首页 > 解决方案 > 如何使用 Uno Platform 在多个平台上录制音频

问题描述

我正在尝试录制音频并在之后进行处理。据我了解,没有可以用来跨不同平台访问麦克风的统一 API。我的目标是 WASM、UWP 和 Android。

我的方法是使用特定于平台的代码录制音频。

对于UWP,我可以使用此处描述的 MediaCapture 类:link。我已经实现了这部分,它工作得很好。

对于Android,它也应该是直截了当的。我可以使用 Android.Media.MediaRecorder ,如下所示:link。我不知道之后如何获取录制的音频文件。

至于WASM,我在这里完全迷失了。我想我可以使用一些 javascript 库来记录声音或 vmsg 库,如此处所述链接。但我不知道如何将记录的数据转换为 C# 代码以进行进一步处理。

是否有一些材料我应该阅读以更好地理解该主题。我是否忽略了一些重要的细节?或者有没有一种简单的方法可以在 xamarin.android 和 wasm 中录制音频?

更新:我已经使用 Android.Media.MediaRecorder 在 Android 上成功实现了音频捕获,完成录制后我可以简单地访问该文件。

标签: xamarin.androidwebassemblyuno-platform

解决方案


我终于可以在所有三个平台(UWP、Android、WASM)上进行录制了。这里的目标是获得具有 48 kHz 采样率、1 个通道和每个样本 16 位的原始 PCM 音频数据。

超轻量级

全局变量:

MediaCapture audioCapture = new MediaCapture();
IRandomAccessStream buffer = new InMemoryRandomAccessStream();

录制音频:

public async Task RecordAudio(int recordingLength, uint sampleRate, uint channels, uint bitsPerSample)
{
    //initialization
    await audioCapture.InitializeAsync(new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Audio });

    //encoding setup
    MediaEncodingProfile profile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.Auto);
    profile.Audio = AudioEncodingProperties.CreatePcm(sampleRate, channels, bitsPerSample);

    //start recording
    await audioCapture.StartRecordToStreamAsync(profile, buffer);

    await Task.Delay(recordingLength * 1000);

    //stop recording
    await audioCapture.StopRecordAsync();
}

以字节数组的形式获取 PCM 数据:

public async Task<byte[]> GetPCMData()
{
    byte[] data = new byte[buffer.Size];
    DataReader dataReader = new DataReader(buffer.GetInputStreamAt(0));

    await dataReader.LoadAsync((uint)buffer.Size);
    dataReader.ReadBytes(data);
    return data;
}

ANDROID:记得先检查麦克风权限。全局变量:

byte[] buffer;
AudioRecord recorder;
int bufferLimit;

录制音频:

public async Task RecordAudio(int recordingLength, uint sampleRate, uint channels, uint bitsPerSample)
{
    //initialization
    // seconds * (number of bytes bytes per 1 sample) * sampleRate
    bufferLimit = recordingLength * bitsPerSample/8 * sampleRate;

    //encoding setup
    ChannelIn channels = Parameters.Channels == 1 ? ChannelIn.Mono : ChannelIn.Stereo;
    if (bitsPerSample != 16)
        throw new Exception("Unsupported bits per sample value");

    recorder = new AudioRecord(
                  AudioSource.Mic,
                  (int)sampleRate,
                  channels,
                  Android.Media.Encoding.Pcm16bit,
                  bufferLimit
               );

    //start recording
    buffer = new byte[bufferLimit];
    int totalBytesRead = 0;
    recorder.StartRecording();

    //record until specified amount of bytes was read
    while(totalBytesRead < bufferLimit)
    {
        int bytesRead = recorder.Read(buffer, 0, bufferLimit);
        if (bytesRead < 0)
        {
            throw new Exception(String.Format("Exception code: {0}", bytesRead));
        }
        else
        {
            totalBytesRead += bytesRead;
        }
    }
    
    //stop recording
    recorder.Stop();
    recorder.Dispose();    
}

以字节数组的形式获取 PCM 数据:

public async Task<byte[]> GetPCMData()
{
    return buffer;
}

蜂鸣器

我使用RecordRTC javascript 库来获取音频数据:


function record(recordingLength, sampleRate, channels) {
    navigator.mediaDevices.getUserMedia({
        audio: true
    }).then(async function (stream) {
        
        //initialization
        let recorder = RecordRTC(stream, {
            type: 'audio',
            mimeType: 'audio/wav',
            recorderType: StereoAudioRecorder,
            sampleRate: sampleRate,
            desiredSampRate: sampleRate,
            numberOfAudioChannels: channels

        });
        
        //start recording
        recorder.startRecording();

        const sleep = m => new Promise(r => setTimeout(r, m));
        await sleep(recordingLength * 1000);

        recorder.stopRecording(function () {
            //blob of PCM audio data that can be further processed
            let blob = recorder.getBlob();
            }

        });
    });

}

WASM 中,我使用 blob 作为 base64 字符串从 javascript 调用 C# 代码,以在 C# 中进一步处理 PCM 音频数据的 blob(如何从 javascript 调用 C# 代码可以在 Uno Platform docs中找到)。

我知道,这不是最干净的解决方案,但它是一个可行的解决方案。


推荐阅读