代码拉取完成,页面将自动刷新
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"sync"
"sync/atomic"
"time"
"github.com/gordonklaus/portaudio"
)
var input *portaudio.Stream
const sampleRate = 44100
const bufferLen = 22050
var in = make([]int16, bufferLen) // 44100是采样率,根据需要调整大小和采样率
var rdLocker = &sync.Mutex{}
var playCtrlStop chan int
var playFlag = &atomic.Bool{}
var mutexPlayer = &sync.Mutex{}
func init() {
playFlag.Store(false)
var err error
err = portaudio.Initialize()
if err != nil {
ErrPanic(err)
}
input, err = portaudio.OpenDefaultStream(1, 0, sampleRate, len(in), in)
if err != nil {
ErrPanic(err)
}
input.Start()
go func() {
for {
rdLocker.Lock()
err := input.Read()
rdLocker.Unlock()
if err != nil {
break
}
}
}()
playCtrlStop = make(chan int)
}
func startRecord(filename string, ctrl chan int8) error {
os.MkdirAll("audios", os.ModePerm)
name := filepath.Join("audios", filename)
recordFlag.Store(true)
defer recordFlag.Store(false)
writer := NewAudioFile()
err := writer.Create(name)
if err != nil {
return err
}
defer writer.Close()
rdLocker.Lock()
defer rdLocker.Unlock()
loop:
for {
err := writer.Write(in)
if err != nil {
fmt.Println("保存数据失败:", err)
return err
}
select {
case <-ctrl:
ctrl <- 1
break loop
default:
}
//println("record...")
err = input.Read() // 读取数据到缓冲区
if err != nil {
fmt.Println("读取数据失败:", err)
return err
}
}
return nil
}
func stopRecord(ctrl chan int8) error {
ctrl <- 0
<-ctrl
return nil
}
func stopPlay() {
if playFlag.Load() {
playCtrlStop <- 1
<-playCtrlStop
//println("stop ok")
}
}
func stopPlayForRecord() {
if playFlag.Load() {
playCtrlStop <- 1
<-playCtrlStop
time.Sleep(time.Millisecond * 500)
//println("stop ok")
}
}
func playAudio(filename string) error {
if playFlag.Load() {
return errors.New("Playing other audio")
}
name := filepath.Join("audios", filename)
reader := NewAudioFile()
err := reader.Open(name)
if err != nil {
return err
}
defer reader.Close()
mutexPlayer.Lock()
defer mutexPlayer.Unlock()
playFlag.Store(true)
defer playFlag.Store(false)
//打开pa播放流
out := make([]int16, bufferLen)
output, err := portaudio.OpenDefaultStream(0, 1, sampleRate, len(out), out)
if err != nil {
fmt.Println("打开输出流失败:", err)
return err
}
defer output.Close() // 关闭输出流
output.Start()
defer output.Close()
n, err := reader.Read(out)
if err != nil {
return nil
}
for {
output.Write()
d := time.Duration(float64(time.Second) * float64(n) / float64(sampleRate))
after := time.After(d)
//利用等待时间读取下一段数据,使播放效果更流畅
n, err = reader.Read(out)
select {
case <-playCtrlStop:
playCtrlStop <- 2
//println("stop play not complete")
return nil
case <-after:
//println("stop play complete:", d)
}
if err != nil {
return nil
}
}
//pa播放
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。