malgo

repository·master·Indexed 19 days ago

https://github.com/gen2brain/malgo

Go bindings for the miniaudio C library, providing cross-platform audio playback and recording capabilities. It supports a wide range of platforms and backends, including WASAPI, DirectSound, and WinMM on Windows; PulseAudio, ALSA, and JACK on Linux; CoreAudio on macOS/iOS; and OpenSL|ES and AAudio on Android. The library allows for detailed configuration of audio contexts, device settings, resampling, and full-duplex I/O via callbacks.

Tokens
7.2K
Snippets
19
Records
28
Agent score
64%

What's inside malgo

  1. Install malgo via Go

    master

    To use malgo in your Go project, install the package using go get. Note that malgo requires cgo to function. On Windows and macOS, no additional linking is required, while on Linux and BSD systems, it links against -ldl.

    go get -u github.com/gen2brain/malgo
  2. Define audio processing callbacks with DeviceCallbacks

    master

    The DeviceCallbacks struct is used during InitDevice to define how the application responds to audio events.

    • Data (DataProc): A function called for full-duplex I/O. It receives pOutputSample (for playback), pInputSamples (for capture), and the framecount.
      • If the device is playback-only, pInputSamples will be nil.
      • If the device is capture-only, pOutputSample will be nil.
      • The slices provided are byte slices ([]byte) representing the raw audio data.
    • Stop (StopProc): A function called when the device has stopped.
    type DataProc func(pOutputSample, pInputSamples []byte, framecount uint32)
    type StopProc func()
    
    type DeviceCallbacks struct {
    	Data DataProc
    	Stop StopProc
    }
  3. Configure the malgo Context

    master

    The ContextConfig struct allows you to customize the behavior of the audio context, including thread priority, memory allocation callbacks, and backend-specific settings.

    Backend-Specific Configurations

    • Alsa: AlsaContextConfig provides UseVerboseDeviceEnumeration.
    • PulseAudio: PulseContextConfig allows setting PApplicationName, PServerName, and TryAutoSpawn (to autospawn the daemon).
    • CoreAudio: CoreAudioConfig manages SessionCategory and SessionCategoryOptions.
    • Jack: JackContextConfig allows setting PClientName and TryStartServer.

    Global Settings

    • ThreadPriority: Sets the priority for the audio threads.
    • AllocationCallbacks: Allows providing custom OnMalloc, OnRealloc, and OnFree functions.
    • LogCallback: A LogProc function to handle logging.
  4. Supported platforms and audio backends

    master

    malgo supports a wide range of platforms and their respective audio backends:

    • Windows: WASAPI, DirectSound, WinMM
    • Linux: PulseAudio, ALSA, JACK
    • FreeBSD/NetBSD/OpenBSD: OSS/audio(4)/sndio
    • macOS/iOS: CoreAudio
    • Android: OpenSL|ES, AAudio
  5. Set a logging callback for a Context

    master

    You can intercept internal malgo logs by providing a LogProc function to SetLogProc. A LogProc is a function with the signature func(message string).

    To stop logging, call SetLogProc(nil).

    ctx.SetLogProc(func(message string) {
        fmt.Printf("malgo log: %s\n", message)
    })
  6. Handle errors using the Result type

    master

    The Result type is an int32 that implements the Go error interface. It wraps miniaudio result codes. When an operation returns a Result that is not MA_SUCCESS, you can call its .Error() method to retrieve a descriptive error string prefixed with miniaudio: .

    To check if an operation was successful, compare the returned Result against ErrGeneric (which represents MA_ERROR) or check if it matches the success state (though in practice, most users check if the result is non-zero or use the provided error constants).

    // Example of how a Result might be used
    res := someMalgoFunction()
    if res != 0 { // Assuming 0 is success
        fmt.Println("Error occurred:", res.Error())
    }
  7. Control device playback and capture with Start, Stop, and Uninit

    master

    Once a Device is initialized, you can control its lifecycle using the following methods:

    • Start(): Activates the device. For playback devices, this begins audio output. For capture devices, this begins recording. Note that for playback, Start() will wait until an initial chunk of audio data is retrieved from your Data callback to ensure the buffer is not empty before playback begins.
    • Stop(): Puts the device to sleep without uninitializing it. This is useful if you want to pause audio and resume later using Start(). This method waits for the backend to stop properly.
    • Uninit(): Completely shuts down the device and releases its resources. This explicitly calls Stop() internally. You do not need to call Stop() manually before Uninit(), but it is safe to do so.
    err := device.Start()
    if err != nil {
    	// handle error
    }
    
    // ... later ...
    
    err = device.Stop()
    
    // ... when finished ...
    
    device.Uninit()
  8. Retrieve audio devices from a Context

    master

    You can query a Context to find available audio hardware using Devices or DeviceInfo.

    List all devices

    Use Devices(kind DeviceType) to get a slice of DeviceInfo for either Capture or Playback devices.

    Get specific device info

    Use DeviceInfo(kind DeviceType, id DeviceID, mode ShareMode) to retrieve detailed information about a specific device identified by its DeviceID and requested ShareMode.

    // List all playback devices
    devices, err := ctx.Devices(malgo.Playback)
    if err != nil {
        // handle error
    }
    
    for _, device := range devices {
        fmt.Printf("Device: %s\n", device.Name)
    }
  9. Calculate sample size in bytes with SampleSizeInBytes

    master

    Use SampleSizeInBytes(format FormatType) to determine how many bytes a single sample occupies for a specific audio format. This is useful when manually managing audio buffers or calculating buffer sizes based on the FormatType being used.

    // Example usage (assuming FormatType is defined elsewhere in the package)
    bytes := malgo.SampleSizeInBytes(malgo.FormatS16)
  10. Initialize a default DeviceConfig

    master

    Use DefaultDeviceConfig(deviceType DeviceType) to create a DeviceConfig populated with the library's default settings for a specific device type (e.g., playback or capture). This is the recommended starting point for configuring audio devices.

    // Example: Initialize a default playback configuration
    config := malgo.DefaultDeviceConfig(malgo.DeviceTypePlayback)
  11. Inspect device properties and negotiated formats

    master

    After initialization, you can query the Device to see the requested and negotiated audio parameters. This is critical because audio backends (like ALSA) may perform internal resampling or format conversion, meaning the actual hardware settings might differ from your requested DeviceConfig.

    Requested Formats

    • SampleRate(): The requested sample rate.
    • PlaybackFormat(): The requested playback format.
    • CaptureFormat(): The requested capture format.
    • PlaybackChannels(): The requested number of playback channels.
    • CaptureChannels(): The requested number of capture channels.

    Negotiated (Internal) Formats

    Use these methods to see what the audio backend is actually using:

    • PlaybackInternalSampleRate(): The actual sample rate used for playback.
    • CaptureInternalSampleRate(): The actual sample rate used for capture.
    • PlaybackInternalFormat(): The actual sample format used for playback.
    • CaptureInternalFormat(): The actual sample format used for capture.
    • PlaybackInternalChannels(): The actual number of playback channels.
    • CaptureInternalChannels(): The actual number of capture channels.

    Status

    • IsStarted(): Returns true if the device is currently active.