golang跨平台低层级音频播放插件库Oto的使用

Golang跨平台低层级音频播放插件库Oto的使用

Oto是一个低层级的音频播放库,支持多种平台。以下是关于如何使用Oto的详细介绍和示例代码。

支持的平台

  • Windows (不需要Cgo)
  • macOS (不需要Cgo)
  • Linux
  • FreeBSD
  • OpenBSD
  • Android
  • iOS
  • WebAssembly
  • Nintendo Switch
  • Xbox

前提条件

在某些平台上,您需要在路径中安装Go可以使用的C/C++编译器。

macOS

Oto需要AudioToolbox.framework,但会自动链接。

iOS

Oto需要以下框架:

  • AVFoundation.framework
  • AudioToolbox.framework

将它们添加到Xcode项目的"Linked Frameworks and Libraries"中。

Linux

需要安装ALSA。在Ubuntu或Debian上运行:

apt install libasound2-dev

在基于RedHat的Linux发行版上运行:

dnf install alsa-lib-devel

使用方法

Oto的两个主要组件是ContextPlayers。上下文处理与操作系统和音频驱动程序的交互,因此程序中只能有一个上下文。

从内存播放音频

以下是一个加载并播放MP3文件的示例:

package main

import (
    "bytes"
    "time"
    "os"

    "github.com/ebitengine/oto/v3"
    "github.com/hajimehoshi/go-mp3"
)

func main() {
    // 读取MP3文件到内存
    fileBytes, err := os.ReadFile("./my-file.mp3")
    if err != nil {
        panic("reading my-file.mp3 failed: " + err.Error())
    }

    // 将纯字节转换为可用于MP3解码器的读取器对象
    fileBytesReader := bytes.NewReader(fileBytes)

    // 解码文件
    decodedMp3, err := mp3.NewDecoder(fileBytesReader)
    if err != nil {
        panic("mp3.NewDecoder failed: " + err.Error())
    }

    // 准备Oto上下文(将使用默认音频设备)
    op := &oto.NewContextOptions{}

    // 通常为44100或48000。其他值可能导致Oto失真
    op.SampleRate = 44100

    // 声道数(1为单声道,2为立体声)
    op.ChannelCount = 2

    // 源格式。go-mp3的格式是有符号16位整数
    op.Format = oto.FormatSignedInt16LE

    // 记住程序中不应创建多个上下文
    otoCtx, readyChan, err := oto.NewContext(op)
    if err != nil {
        panic("oto.NewContext failed: " + err.Error())
    }
    // 等待硬件音频设备准备就绪
    <-readyChan

    // 创建一个新的播放器(默认暂停)
    player := otoCtx.NewPlayer(decodedMp3)
    
    // 开始播放音频(异步)
    player.Play()

    // 可以等待音频播放完成
    for player.IsPlaying() {
        time.Sleep(time.Millisecond)
    }

    // 播放完成后可以关闭播放器
    err = player.Close()
    if err != nil {
        panic("player.Close failed: " + err.Error())
    }
}

通过文件流播放音频

上面的示例将整个文件加载到内存中然后播放。对于较小的文件很好,但对于长歌曲可能会占用太多内存。这时可以使用文件流:

package main

import (
    "os"
    "time"

    "github.com/ebitengine/oto/v3"
    "github.com/hajimehoshi/go-mp3"
)

func main() {
    // 打开文件进行读取。在播放完成前不要关闭!
    file, err := os.Open("./my-file.mp3")
    if err != nil {
        panic("opening my-file.mp3 failed: " + err.Error())
    }

    // 解码文件。这个过程是在文件播放时进行的
    decodedMp3, err := mp3.NewDecoder(file)
    if err != nil {
        panic("mp3.NewDecoder failed: " + err.Error())
    }

    // 其余部分相同...

    // 播放完成后关闭文件
    file.Close()
}

高级用法

播放器有自己的内部音频数据缓冲区,所以当从io.Reader读取了200字节时,并不意味着它们都已从音频设备播放。

可以使用Player.UnplayedBufferSize()获取缓冲区中未播放的数据量。

也可以通过类型断言设置播放器的底层缓冲区大小:

myPlayer.(oto.BufferSizeSetter).SetBufferSize(newBufferSize)

交叉编译

交叉编译到macOS或Windows很简单,只需设置GOOS=darwinGOOS=windows

要为其他平台交叉编译,请确保安装了目标架构的库,并设置CGO_ENABLED=1,因为Go在交叉编译时默认禁用Cgo。


更多关于golang跨平台低层级音频播放插件库Oto的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨平台低层级音频播放插件库Oto的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Oto - Go语言跨平台低级音频播放库

Oto是一个Go语言的跨平台低级音频播放库,它提供了简单的API来播放原始音频数据。Oto支持Windows、macOS、Linux、iOS、Android和WebAssembly平台。

主要特点

  • 跨平台支持
  • 简单易用的API
  • 低延迟音频播放
  • 支持多种采样率和声道配置

安装

go get -u github.com/hajimehoshi/oto

基本使用示例

下面是一个简单的示例,演示如何使用Oto播放440Hz的正弦波:

package main

import (
	"math"
	"time"

	"github.com/hajimehoshi/oto"
)

const (
	sampleRate   = 44100 // 采样率
	channelCount = 2     // 立体声
	bitDepth     = 2     // 16位音频
)

func main() {
	// 初始化Oto播放器
	player, err := oto.NewPlayer(sampleRate, channelCount, bitDepth, 4096)
	if err != nil {
		panic(err)
	}
	defer player.Close()

	// 生成440Hz正弦波
	duration := time.Second * 3
	freq := 440.0 // 频率(Hz)
	amplitude := 0.5

	// 计算总样本数
	numSamples := int(sampleRate * duration.Seconds())
	data := make([]byte, numSamples*channelCount*bitDepth)

	for i := 0; i < numSamples; i++ {
		// 计算正弦波值
		val := math.Sin(2 * math.Pi * freq * float64(i) / sampleRate)
		val *= amplitude

		// 转换为16位PCM
		sample := int16(val * math.MaxInt16)

		// 填充左右声道
		for c := 0; c < channelCount; c++ {
			offset := (i*channelCount + c) * bitDepth
			data[offset] = byte(sample)
			data[offset+1] = byte(sample >> 8)
		}
	}

	// 播放音频
	if _, err := player.Write(data); err != nil {
		panic(err)
	}

	// 等待播放完成
	time.Sleep(duration)
}

高级用法

实时音频流

Oto也支持实时音频流播放:

package main

import (
	"math"
	"time"

	"github.com/hajimehoshi/oto"
)

const (
	sampleRate   = 44100
	channelCount = 2
	bitDepth     = 2
	bufferSize   = 4096
)

func main() {
	// 初始化播放器
	player, err := oto.NewPlayer(sampleRate, channelCount, bitDepth, bufferSize)
	if err != nil {
		panic(err)
	}
	defer player.Close()

	// 实时生成并播放音频
	freq := 440.0
	amplitude := 0.5
	phase := 0.0

	buf := make([]byte, bufferSize)
	samplesPerBuffer := bufferSize / (channelCount * bitDepth)

	for {
		// 填充缓冲区
		for i := 0; i < samplesPerBuffer; i++ {
			// 计算正弦波值
			val := math.Sin(2 * math.Pi * phase)
			val *= amplitude
			phase += freq / sampleRate

			// 转换为16位PCM
			sample := int16(val * math.MaxInt16)

			// 填充左右声道
			for c := 0; c < channelCount; c++ {
				offset := (i*channelCount + c) * bitDepth
				buf[offset] = byte(sample)
				buf[offset+1] = byte(sample >> 8)
			}
		}

		// 播放缓冲区数据
		if _, err := player.Write(buf); err != nil {
			panic(err)
		}
	}
}

控制播放

// 暂停播放(通过停止写入数据)
// Oto本身没有暂停功能,需要自己管理状态

// 停止播放
player.Close()

// 检查是否正在播放(通过检查是否还有数据可写)

注意事项

  1. Oto是一个低级音频库,不提供高级功能如音频格式解码、混音等
  2. 在移动设备上使用时需要处理权限问题
  3. WebAssembly版本可能需要特殊处理
  4. 音频数据必须是原始PCM格式

性能优化建议

  1. 使用适当大小的缓冲区(太小会增加CPU负载,太大会增加延迟)
  2. 预生成静态音频数据
  3. 对于实时音频,考虑使用goroutine分离生成和播放逻辑

Oto是一个简单而强大的音频播放库,适合需要直接控制音频数据或构建音频处理应用的Go开发者。对于更高级的音频需求,可能需要结合其他库如go-audio或beep使用。

回到顶部