Memproses bingkai audio dengan MediaFrameReader

Artikel ini menunjukkan kepada Anda cara menggunakan MediaFrameReader dengan MediaCapture untuk mendapatkan data audio dari sumber bingkai media. Untuk mempelajari tentang menggunakan MediaFrameReader untuk mendapatkan data gambar, seperti dari kamera warna, inframerah, atau kedalaman, lihat Memproses bingkai media dengan MediaFrameReader. Artikel itu memberikan gambaran umum tentang pola penggunaan pembaca bingkai dan membahas beberapa fitur tambahan dari kelas MediaFrameReader , seperti menggunakan MediaFrameSourceGroup untuk mengambil frame dari berbagai sumber secara bersamaan.

Catatan

Fitur yang dibahas dalam artikel ini hanya tersedia mulai dari Windows 10, versi 1803.

Catatan

Ada sampel aplikasi Universal Windows yang menunjukkan menggunakan MediaFrameReader untuk menampilkan bingkai dari berbagai sumber bingkai, termasuk warna, kedalaman, dan camrea inframerah. Untuk informasi selengkapnya, lihat Contoh bingkai kamera.

Menyiapkan proyek Anda

Proses untuk memperoleh frame audio sebagian besar sama dengan memperoleh jenis frame media lainnya. Seperti halnya aplikasi apa pun yang menggunakan MediaCapture, Anda harus menyatakan bahwa aplikasi Anda menggunakan kemampuan webcam sebelum mencoba mengakses perangkat kamera apa pun. Jika aplikasi Anda akan menangkap dari perangkat audio, Anda juga harus mendeklarasikan kemampuan perangkat mikrofon .

Menambahkan kemampuan ke manifes aplikasi

  1. Di Microsoft Visual Studio, di Penjelajah Solusi, buka desainer untuk manifes aplikasi dengan mengklik dua kali item package.appxmanifest.
  2. Pilih tab Kemampuan.
  3. Centang kotak untuk Webcam dan kotak untuk Mikrofon.
  4. Untuk akses ke pustaka Gambar dan Video, centang kotak untuk Perpustakaan Gambar dan kotak untuk Perpustakaan Video.

Pilih sumber bingkai dan grup sumber bingkai

Langkah pertama dalam menangkap bingkai audio adalah menginisialisasi MediaFrameSource yang mewakili sumber data audio, seperti mikrofon atau perangkat pengambilan audio lainnya. Untuk melakukan ini, Anda harus membuat instance baru dari objek MediaCapture . Untuk contoh ini, satu-satunya pengaturan inisialisasi untuk MediaCapture adalah mengatur StreamingCaptureMode untuk menunjukkan bahwa kami ingin melakukan streaming audio dari perangkat pengambilan.

Setelah menelepon MediaCapture.InitializeAsync, Anda bisa mendapatkan daftar sumber bingkai media yang dapat diakses dengan properti FrameSources . Contoh ini menggunakan kueri Linq untuk memilih semua sumber bingkai tempat MediaFrameSourceInfo yang menjelaskan sumber bingkai memiliki MediaStreamTypeaudio, yang menunjukkan bahwa sumber media menghasilkan data audio.

Jika kueri mengembalikan satu atau beberapa sumber bingkai, Anda dapat memeriksa properti CurrentFormat untuk melihat apakah sumber mendukung format audio yang Anda inginkan - dalam contoh ini, mengapungkan data audio. Periksa AudioEncodingProperties untuk memastikan pengkodean audio yang Anda inginkan didukung oleh sumbernya.

mediaCapture = new MediaCapture();
MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings()
{
    StreamingCaptureMode = StreamingCaptureMode.Audio,
};
await mediaCapture.InitializeAsync(settings);

var audioFrameSources = mediaCapture.FrameSources.Where(x => x.Value.Info.MediaStreamType == MediaStreamType.Audio);

if (audioFrameSources.Count() == 0)
{
    Debug.WriteLine("No audio frame source was found.");
    return;
}

MediaFrameSource frameSource = audioFrameSources.FirstOrDefault().Value;

MediaFrameFormat format = frameSource.CurrentFormat;
if (format.Subtype != MediaEncodingSubtypes.Float)
{
    return;
}

if (format.AudioEncodingProperties.ChannelCount != 1
    || format.AudioEncodingProperties.SampleRate != 48000)
{
    return;
}

Membuat dan Memulai MediaFrameReader

Dapatkan contoh baru MediaFrameReader dengan memanggil MediaCapture.CreateFrameReaderAsync, melewati objek MediaFrameSource yang Anda pilih di langkah sebelumnya. Secara default, frame audio diperoleh dalam mode buffered, sehingga kecil kemungkinan bahwa frame akan dijatuhkan, meskipun ini masih dapat terjadi jika Anda tidak memproses frame audio cukup cepat dan mengisi buffer memori yang dialokasikan sistem.

Daftarkan penangan untuk acara MediaFrameReader.FrameArrived , yang dinaikkan oleh sistem saat bingkai data audio baru tersedia. Panggil StartAsync untuk memulai akuisisi bingkai audio. Jika pembaca bingkai gagal memulai, nilai status yang dikembalikan dari panggilan akan memiliki nilai selain Sukses.

mediaFrameReader = await mediaCapture.CreateFrameReaderAsync(frameSource);

// Optionally set acquisition mode. Buffered is the default mode for audio.
mediaFrameReader.AcquisitionMode = MediaFrameReaderAcquisitionMode.Buffered;

mediaFrameReader.FrameArrived += MediaFrameReader_AudioFrameArrived;

var status = await mediaFrameReader.StartAsync();

if (status != MediaFrameReaderStartStatus.Success)
{
    Debug.WriteLine("The MediaFrameReader couldn't start.");
}

Di penangan peristiwa FrameArrived , panggil TryAcquireLatestFrame pada objek MediaFrameReader yang diteruskan sebagai pengirim ke penangan untuk mencoba mengambil referensi ke bingkai media terbaru. Perhatikan bahwa objek ini bisa null, jadi Anda harus selalu memeriksa sebelum menggunakan objek. Kesalahan bingkai media yang dibungkus dalam MediaFrameReference yang dikembalikan dari TryAcquireLatestFrame bergantung pada jenis sumber bingkai atau sumber yang Anda konfigurasikan untuk diperoleh pembaca bingkai. Karena pembaca bingkai dalam contoh ini diatur untuk memperoleh bingkai audio, ia mendapatkan bingkai yang mendasarinya menggunakan properti AudioMediaFrame .

Metode pembantu ProcessAudioFrame ini pada contoh di bawah ini menunjukkan cara mendapatkan AudioFrame yang memberikan informasi seperti stempel waktu bingkai dan apakah itu terputus-putus dari objek AudioMediaFrame . Untuk membaca atau memproses data sampel audio, Anda harus mendapatkan objek AudioBuffer dari objek AudioMediaFrame , membuat IMemoryBufferReference, dan kemudian memanggil metode COM IMemoryBufferByteAccess::GetBuffer untuk mengambil data. Lihat catatan di bawah daftar kode untuk informasi lebih lanjut tentang mengakses buffer asli.

Format data tergantung pada sumber bingkai. Dalam contoh ini, saat memilih sumber bingkai media, kami secara eksplisit memastikan bahwa sumber bingkai yang dipilih menggunakan satu saluran data float. Sisa kode contoh menunjukkan cara menentukan durasi dan jumlah sampel untuk data audio dalam bingkai.

private void MediaFrameReader_AudioFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
    using (MediaFrameReference reference = sender.TryAcquireLatestFrame())
    {
        if (reference != null)
        {
            ProcessAudioFrame(reference.AudioMediaFrame);
        }
    }
}
unsafe private void ProcessAudioFrame(AudioMediaFrame audioMediaFrame)
{

    using (AudioFrame audioFrame = audioMediaFrame.GetAudioFrame())
    using (AudioBuffer buffer = audioFrame.LockBuffer(AudioBufferAccessMode.Read))
    using (IMemoryBufferReference reference = buffer.CreateReference())
    {
        byte* dataInBytes;
        uint capacityInBytes;
        float* dataInFloat;


        ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);
        
        // The requested format was float
        dataInFloat = (float*)dataInBytes;

        // Get the number of samples by multiplying the duration by sampling rate: 
        // duration [s] x sampling rate [samples/s] = # samples 

        // Duration can be gotten off the frame reference OR the audioFrame
        TimeSpan duration = audioMediaFrame.FrameReference.Duration;

        // frameDurMs is in milliseconds, while SampleRate is given per second.
        uint frameDurMs = (uint)duration.TotalMilliseconds;
        uint sampleRate = audioMediaFrame.AudioEncodingProperties.SampleRate;
        uint sampleCount = (frameDurMs * sampleRate) / 1000;

    }
}

Catatan

Untuk melakukan operasi pada data audio, Anda harus mengakses buffer memori asli. Untuk melakukan ini, Anda harus menggunakan antarmuka IMemoryBufferByteAccess COM dengan menyertakan daftar kode di bawah ini. Operasi pada buffer asli harus dilakukan dengan metode yang menggunakan kata kunci yang tidak aman . Anda juga perlu mencentang kotak untuk mengizinkan kode yang tidak aman di tab Build dari dialog Project -> Properties.

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

Informasi tambahan tentang menggunakan MediaFrameReader dengan data audio

Anda dapat mengambil AudioDeviceController yang terkait dengan sumber bingkai audio dengan mengakses properti MediaFrameSource.Controller . Objek ini dapat digunakan untuk mendapatkan atau mengatur properti aliran perangkat penangkap atau untuk mengontrol tingkat pengambilan. Contoh berikut membisukan perangkat audio sehingga frame terus diperoleh oleh pembaca bingkai, tetapi semua sampel memiliki nilai 0.

audioDeviceController.Muted = true;

Anda dapat menggunakan objek AudioFrame untuk meneruskan data audio yang diambil oleh sumber bingkai media ke dalam AudioGraph. Masukkan bingkai ke dalam metode AddFramedari AudioFrameInputNode. Untuk informasi selengkapnya tentang menggunakan grafik audio untuk menangkap, memproses, dan mencampur sinyal audio, lihat Grafik audio.