record

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2025 License: Apache-2.0 Imports: 12 Imported by: 0

README

go-record

Go Reference Build Status

A library to capture and render audio using WASAPI.

Overview

This project provides functionalities to capture and render audio using WASAPI. It includes functions to list audio devices, capture audio from a specified device, and render audio to a specified device.

Example

The following is an example of a main function that captures and renders audio:

package main

import (
    "context"
    "log/slog"
    "os"
    "os/signal"
    "sync"

    "github.com/soockee/go-record"
)

type AppConfig struct {
    CaptureDevice string
    OutputDevice  string
}

func main() {
    h := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    })
    slog.SetDefault(slog.New(h))

    config := AppConfig{
        CaptureDevice: "Analogue 1 + 2 (Focusrite USB Audio)",
        OutputDevice:  "Speakers (Focusrite USB Audio)",
    }

    ctx, cancel := setupSignalHandling()
    defer cancel()
    runTasks(ctx, cancel, config)
}

func runTasks(ctx context.Context, cancel context.CancelFunc, config AppConfig) {
    audiostream := record.NewAudioStream()

    tasks := []struct {
        Name string
        Task func(context.Context) error
    }{
        {"Audio Capture Stream", func(ctx context.Context) error {
            return record.Capture(audiostream, config.CaptureDevice, ctx)
        }},
        {"Audio Rendering", func(ctx context.Context) error {
            return record.Render(audiostream, config.OutputDevice, ctx)
        }},
    }

    var wg sync.WaitGroup

    for _, task := range tasks {
        wg.Add(1)
        go func(taskName string, taskFunc func(context.Context) error) {
            defer wg.Done()
            if err := taskFunc(ctx); err != nil {
                slog.Error("Task Event", slog.String("task", taskName), slog.Any("msg", err))
                cancel()
            } else {
                slog.Info("Task completed successfully", slog.String("task", taskName))
            }
        }(task.Name, task.Task)
    }

    wg.Wait()
}

func setupSignalHandling() (context.Context, context.CancelFunc) {
    ctx, cancel := context.WithCancel(context.Background())

    // Catch OS signals like Ctrl+C
    signalChan := make(chan os.Signal, 1)
    signal.Notify(signalChan, os.Interrupt)

    go func() {
        <-signalChan
        slog.Info("SIGINT received, shutting down...")
        cancel()
    }()

    return ctx, cancel
}

Platforms

  • Windows

Prerequisite

Windows

No additional prerequisites are required.

Usage

Capturing Audio

The following is an example of capturing audio from a specified device:

package main

import (
    "context"
    "log"

    "github.com/soockee/go-record"
)

func main() {
    stream := record.NewAudioStream()
    ctx := context.Background()
    err := record.Capture(stream, "Microphone (Realtek High Definition Audio)", ctx)
    if err != nil {
        log.Fatal(err)
    }
}
Rendering Audio

The following is an example of rendering audio to a specified device:

package main

import (
    "context"
    "log"

    "github.com/soockee/go-record"
)

func main() {
    stream := record.NewAudioStream()
    ctx := context.Background()
    err := record.Render(stream, "Speakers (Realtek High Definition Audio)", ctx)
    if err != nil {
        log.Fatal(err)
    }
}
Listing Devices

The following is an example of listing all active render devices:

package main

import (
    "fmt"

    "github.com/moutend/go-wca/pkg/wca"
    "github.com/soockee/go-record"
)

func main() {
    mmde := wca.NewIMMDeviceEnumerator()
    devices := record.ListDevices(mmde, record.ERender, record.DEVICE_STATE_ACTIVE)
    for _, device := range devices {
        fmt.Println(device.Name.String())
    }
}
Finding a Device by Name

The following is an example of finding a device by its name:

package main

import (
    "fmt"
    "log"

    "github.com/moutend/go-wca/pkg/wca"
    "github.com/soockee/go-record"
)

func main() {
    mmde := wca.NewIMMDeviceEnumerator()
    device, err := record.FindDeviceByName(mmde, "Speakers (Realtek High Definition Audio)", record.ERender, record.DEVICE_STATE_ACTIVE)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(device.Name.String())
}

Functions

Capture

The Capture function captures audio from a specified device and exposes it as a stream.

func Capture(stream *AudioStream, deviceName string, ctx context.Context) error
  • stream: The AudioStream object to which the captured audio will be written.
  • deviceName: The name of the audio device to capture from.
  • ctx: The context to control the capture process.
Render

The Render function renders audio to a specified device from a provided audio stream.

func Render(stream *AudioStream, deviceName string, ctx context.Context) error
  • stream: The AudioStream object from which the audio will be read.
  • deviceName: The name of the audio device to render to.
  • ctx: The context to control the rendering process.
ListDevices

The ListDevices function lists all audio devices of a specified type and state.

func ListDevices(mmde *wca.IMMDeviceEnumerator, deviceType DeviceType, deviceState DeviceState) []*Device
  • mmde: The device enumerator object.
  • deviceType: The type of devices to list (e.g., ERender, ECapture).
  • deviceState: The state of devices to list (e.g., DEVICE_STATE_ACTIVE).
FindDeviceByName

The FindDeviceByName function finds an audio device by its name.

func FindDeviceByName(mmde *wca.IMMDeviceEnumerator, deviceName string, deviceType DeviceType, deviceState DeviceState) (*Device, error)
  • mmde: The device enumerator object.
  • deviceName: The name of the device to find.
  • deviceType: The type of device to find (e.g., ERender, ECapture).
  • deviceState: The state of the device to find (e.g., DEVICE_STATE_ACTIVE).

Documentation

Index

Constants

View Source
const (
	// EDataFlow enum
	ERender              DeviceType = 0
	ECapture             DeviceType = 1
	EAll                 DeviceType = 2
	EDataFlow_enum_count DeviceType = 3
	// DeviceState enum
	DEVICE_STATE_ACTIVE     DeviceState = 0x00000001
	DEVICE_STATE_DISABLED   DeviceState = 0x00000002
	DEVICE_STATE_NOTPRESENT DeviceState = 0x00000004
	DEVICE_STATE_UNPLUGGED  DeviceState = 0x00000008
	DEVICE_STATEMASK_ALL    DeviceState = 0x0000000f
)

Variables

This section is empty.

Functions

func Capture

func Capture(stream *AudioStream, deviceName string, ctx context.Context) error

Capture captures audio and exposes it as a stream

func GetFormat

func GetFormat(deviceName string) (wca.WAVEFORMATEX, error)

func Render

func Render(stream *AudioStream, deviceName string, ctx context.Context) error

func SetupAudioClient

func SetupAudioClient(deviceName string) (*wca.IAudioClient2, error)

Types

type AudioClientOpt

type AudioClientOpt struct {
	DeviceName string
	WaveFmt    wave.WaveFmt
	Wfx        *wca.WAVEFORMATEX
	Ctx        context.Context
}

type AudioStream

type AudioStream struct {
	// contains filtered or unexported fields
}

func NewAudioStream

func NewAudioStream() *AudioStream

NewAudioStream creates a new AudioStream

func (*AudioStream) Close

func (s *AudioStream) Close()

Close closes the stream and signals that it is done

func (*AudioStream) Done

func (s *AudioStream) Done() <-chan struct{}

Done returns a channel that is closed when the stream is closed

func (*AudioStream) Read

func (s *AudioStream) Read() []byte

Read reads data from the stream

func (*AudioStream) Ready

func (s *AudioStream) Ready() <-chan struct{}

Ready returns a channel that is closed when the Fmt is set

func (*AudioStream) Reset

func (s *AudioStream) Reset()

func (*AudioStream) Start

func (s *AudioStream) Start()

Start signals that the stream is ready

func (*AudioStream) Write

func (s *AudioStream) Write(data []byte)

Write appends data to the stream

type Device

type Device struct {
	Name   wca.PROPVARIANT
	Device *wca.IMMDevice
}

func FindDeviceByName

func FindDeviceByName(mmde *wca.IMMDeviceEnumerator, deviceName string, deviceType DeviceType, deviceState DeviceState) (*Device, error)

func ListDevices

func ListDevices(mmde *wca.IMMDeviceEnumerator, deviceType DeviceType, deviceState DeviceState) []*Device

ListDevies lists all audio devices, they need to be released after use

type DeviceState

type DeviceState uint32

type DeviceType

type DeviceType uint32

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL