Skip to content

Instantly share code, notes, and snippets.

@fukuroder
Last active January 5, 2024 17:54
Show Gist options
  • Save fukuroder/af06033821c034b3daa2ddc39e5c6906 to your computer and use it in GitHub Desktop.
Save fukuroder/af06033821c034b3daa2ddc39e5c6906 to your computer and use it in GitHub Desktop.
WASAPI capture in F#
open System.Runtime.InteropServices
open NAudio.CoreAudioApi
module NativeMethods =
[<DllImport("api-ms-win-core-synch-l1-2-0.dll")>]
extern System.IntPtr CreateEvent(System.IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, System.IntPtr lpName)
[<DllImport("api-ms-win-core-handle-l1-1-0.dll")>]
extern bool CloseHandle(System.IntPtr hObject)
[<DllImport("api-ms-win-core-synch-l1-2-0.dll")>]
extern int WaitForSingleObject(System.IntPtr hEvent, int milliseconds)
[<EntryPoint>]
let main args =
// デフォルトのキャプチャデバイス取得
let deviceEnumerator = new MMDeviceEnumerator()
let device = (DataFlow.Capture, Role.Console) |> deviceEnumerator.GetDefaultAudioEndpoint
printfn "Default Capture Device: %s" device.FriendlyName
// AudioClient取得
let client = device.AudioClient
// 初期化
(
AudioClientShareMode.Shared,
AudioClientStreamFlags.EventCallback,
client.DefaultDevicePeriod,
client.DefaultDevicePeriod,
(48000, 16, 2) |> NAudio.Wave.WaveFormat,
System.Guid.Empty
) |> client.Initialize
// バッファイベントを登録する
let frameEventWaitHandle = (System.IntPtr.Zero, false, false, System.IntPtr.Zero) |> NativeMethods.CreateEvent
frameEventWaitHandle |> client.SetEventHandle
// バッファサイズを取得する
let bufsize = client.BufferSize
// AudioCaptureClient取得
let captureClient = client.AudioCaptureClient
// キャプチャ開始
() |> client.Start
let mutable stop = false
async{
// Enterキーが押されたら終了
() |> stdin.ReadLine |> ignore
printfn "enter key pressed"
stop <- true
} |> Async.StartAsTask |> ignore
while not stop do
// バッファがいっぱいになるまで待つ
(frameEventWaitHandle, -1) |> NativeMethods.WaitForSingleObject |> ignore
// バッファ取得
let mutable numFrameToRead = 0
let mutable bufferFlags = AudioClientBufferFlags.None
let p = captureClient.GetBuffer(&numFrameToRead, &bufferFlags)
match bufferFlags with
| AudioClientBufferFlags.None ->
printfn "numFrameToRead: %d" numFrameToRead
//////////////
// 何かする //
//////////////
| _ -> ()
// バッファ解放
numFrameToRead |> captureClient.ReleaseBuffer
done
// キャプチャ停止
() |> client.Stop
// 後始末
frameEventWaitHandle |> NativeMethods.CloseHandle |> ignore
() |> client.Dispose
() |> device.Dispose
() |> deviceEnumerator.Dispose
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment