1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
package sound_effect
import (
"unsafe"
"pkg.deepin.io/lib/asound"
)
type ALSAPlayBackend struct {
pcm asound.PCM
frameSize int
}
func newALSAPlayBackend(device string, sampleSpec *SampleSpec) (pb PlayBackend, err error) {
if device == "" {
device = "default"
}
pcm, err := asound.OpenPCM(device, asound.PCMStreamPlayback, 0)
if err != nil {
return
}
defer func() {
if err != nil {
//println("call pcm.Close()")
pcm.Close()
}
}()
params, err := asound.NewPCMHwParams()
if err != nil {
return nil, err
}
defer params.Free()
// fill it in with default values
pcm.HwParamsAny(params)
channels := sampleSpec.channels
format := sampleSpec.pcmFormat
err = pcm.HwParamsSetAccess(params, asound.PCMAccessRWInterleaved)
if err != nil {
return
}
err = pcm.HwParamsSetFormat(params, format)
if err != nil {
return
}
err = pcm.HwParamsSetChannels(params, uint(channels))
if err != nil {
return
}
sampleRate := uint(sampleSpec.rate)
_, err = pcm.HwParamsSetRateNear(params, &sampleRate)
if err != nil {
return
}
bufferTime, _, err := params.GetBufferTimeMax()
if err != nil {
return
}
if bufferTime > 500000 {
bufferTime = 500000
}
periodTime := uint(0)
if bufferTime > 0 {
periodTime = bufferTime / 4
}
// set period time
if periodTime > 0 {
_, err = pcm.HwParamsSetPeriodTimeNear(params, &periodTime)
if err != nil {
return
}
}
// set buffer time
if bufferTime > 0 {
_, err = pcm.HwParamsSetBufferTimeNear(params, &bufferTime)
if err != nil {
return
}
}
err = pcm.HwParams(params)
if err != nil {
return
}
err = pcm.Prepare()
if err != nil {
return
}
frameSize := channels * sampleSpec.pcmFormat.Size(1)
return &ALSAPlayBackend{
pcm: pcm,
frameSize: frameSize,
}, nil
}
func (pb *ALSAPlayBackend) Write(data []byte) error {
frames := len(data) / pb.frameSize
_, err := pb.pcm.Writei(unsafe.Pointer(&data[0]), asound.PCMUFrames(frames))
if err == asound.ErrUnderrun {
return pb.pcm.Prepare()
}
return err
}
func (pb *ALSAPlayBackend) Drain() error {
return pb.pcm.Drain()
}
func (pb *ALSAPlayBackend) Close() error {
return pb.pcm.Close()
}
|