1 Star 1 Fork 0

wulala乌啦啦 / hwpack

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
context.go 4.50 KB
一键复制 编辑 原始数据 按行查看 历史
wulala乌啦啦 提交于 2021-08-14 14:59 . 增加音频播放的接口
// Copyright 2019 The Oto Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package oto
import (
"errors"
"io"
"sync"
"time"
"gitee.com/wulalade/hwpack/music/oto/internal/mux"
)
// Context is the main object in Oto. It interacts with the audio drivers.
//
// To play sound with Oto, first create a context. Then use the context to create
// an arbitrary number of players. Then use the players to play sound.
//
// There can only be one context at any time. Closing a context and opening a new one is allowed.
type Context struct {
driverWriter *driverWriter
mux *mux.Mux
errCh chan error
}
var (
theContext *Context
contextM sync.Mutex
)
var errClosed = errors.New("closed")
// NewContext creates a new context, that creates and holds ready-to-use Player objects.
//
// The sampleRate argument specifies the number of samples that should be played during one second.
// Usual numbers are 44100 or 48000.
//
// The channelNum argument specifies the number of channels. One channel is mono playback. Two
// channels are stereo playback. No other values are supported.
//
// The bitDepthInBytes argument specifies the number of bytes per sample per channel. The usual value
// is 2. Only values 1 and 2 are supported.
//
// The bufferSizeInBytes argument specifies the size of the buffer of the Context. This means, how
// many bytes can Context remember before actually playing them. Bigger buffer can reduce the number
// of Player's Write calls, thus reducing CPU time. Smaller buffer enables more precise timing. The
// longest delay between when samples were written and when they started playing is equal to the size
// of the buffer.
func NewContext(sampleRate, channelNum, bitDepthInBytes, bufferSizeInBytes int) (*Context, error) {
contextM.Lock()
defer contextM.Unlock()
if theContext != nil {
panic("oto: NewContext can be called only once")
}
d, err := newDriver(sampleRate, channelNum, bitDepthInBytes, bufferSizeInBytes)
if err != nil {
return nil, err
}
dw := &driverWriter{
driver: d,
bufferSize: bufferSizeInBytes,
bytesPerSecond: sampleRate * channelNum * bitDepthInBytes,
}
c := &Context{
driverWriter: dw,
mux: mux.New(channelNum, bitDepthInBytes),
errCh: make(chan error),
}
theContext = c
go func() {
if _, err := io.Copy(c.driverWriter, c.mux); err != nil {
c.errCh <- err
}
close(c.errCh)
}()
return c, nil
}
// NewPlayer creates a new, ready-to-use Player belonging to the Context.
func (c *Context) NewPlayer() *Player {
p := newPlayer(c)
c.mux.AddSource(p.r)
return p
}
// Close closes the Context and its Players and frees any resources associated with it. The Context is no longer
// usable after calling Close.
func (c *Context) Close() error {
contextM.Lock()
theContext = nil
contextM.Unlock()
if err := c.driverWriter.Close(); err != nil {
return err
}
if err := c.mux.Close(); err != nil {
return err
}
return <-c.errCh
}
type tryWriteCloser interface {
io.Closer
TryWrite([]byte) (int, error)
}
type driverWriter struct {
driver tryWriteCloser
bufferSize int
bytesPerSecond int
m sync.Mutex
}
func (d *driverWriter) Write(buf []byte) (int, error) {
d.m.Lock()
defer d.m.Unlock()
written := 0
for len(buf) > 0 {
if d.driver == nil {
return written, errClosed
}
n, err := d.driver.TryWrite(buf)
written += n
if err != nil {
return written, err
}
buf = buf[n:]
// When not all buf is written, the underlying buffer is full.
// Mitigate the busy loop by sleeping (#10).
if len(buf) > 0 {
t := time.Second * time.Duration(d.bufferSize) / time.Duration(d.bytesPerSecond) / 8
time.Sleep(t)
}
}
return written, nil
}
func (d *driverWriter) Close() error {
d.m.Lock()
defer d.m.Unlock()
// Close should be wait until the buffer data is consumed (#36).
// This is the simplest (but ugly) fix.
// TODO: Implement player's Close to wait the buffer played.
time.Sleep(time.Second * time.Duration(d.bufferSize) / time.Duration(d.bytesPerSecond))
return d.driver.Close()
}
1
https://gitee.com/wulalade/hwpack.git
git@gitee.com:wulalade/hwpack.git
wulalade
hwpack
hwpack
d22efa2ac7c9

搜索帮助