为了账号安全,请及时绑定邮箱和手机立即绑定

如何让程序在音频播放完毕后自动退出

如何让程序在音频播放完毕后自动退出

Go
慕容森 2022-07-18 17:16:18
我正在写一个小工具,它可以播放command/terminalsox之类的音频文件。我正在为 Windows 使用bass.dllGolang syscall。这是我的代码,文件可以从评论中下载,只能在 Windows X64 上运行。package mainimport (    "fmt"    "syscall"    "time"    "unsafe")/*基于 [bass.dll](http://us2.un4seen.com/files/bass24.zip)和 [Golang syscall](https://github.com/golang/go/wiki/WindowsDLLs) 实现的命令行版播放器。*/type BassLib struct {    libBass syscall.Handle    init   uintptr    free   uintptr    streamCreateFile uintptr    channelPlay uintptr    channelPause uintptr    channelStop uintptr}func (bass *BassLib) LoadBass(bassDllPath string) bool {    bass.libBass, _ = syscall.LoadLibrary(bassDllPath)    if bass.libBass == 0 {        fmt.Println("load library result")        fmt.Println(bass.libBass)        return false    }    bass.init, _ = syscall.GetProcAddress(bass.libBass, "BASS_Init")    // BASS_init(device, freq, flags, win, clsid)    // see http://www.un4seen.com/doc/#bass/BASS_Init.html    device := 1    syscall.Syscall6(bass.init, 5, uintptr(device), uintptr(44100), uintptr(0), uintptr(0), uintptr(0), 0)    return true}func StrPtr(s string) uintptr {    // return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))    p, _ := syscall.UTF16PtrFromString(s)    return uintptr(unsafe.Pointer(p))}有一个大问题:如果未添加time.Sleep代码(bass.go第 68 行),则不会播放任何声音并快速退出。当我添加time.Sleep(time.Second * 10)代码时,音频持续时间可能超过 10 秒。有没有可能让程序在播放完音频后自动退出?
查看完整描述

3 回答

?
holdtom

TA贡献1805条经验 获得超10个赞

我认为您可以defer在播放功能完成后使用 golang 的关键字来触发退出。


你可以参考这里:围棋之旅 | 推迟 或在这里:Golang 博客 | 推迟


package main


import "fmt"


func main() {

    defer fmt.Println("world")


    fmt.Println("hello")

}


==========

$ go run main.go

hello

world


查看完整回答
反对 回复 2022-07-18
?
阿波罗的战车

TA贡献1862条经验 获得超6个赞

我强烈建议您阅读 golang.org 网站上的Effective Go(阅读时间不长,我相信您可以在一天内完成所有想法),特别注意并发部分。


Go 背后的整个想法是使并发和异步编程变得容易,它使用了多种语言结构(通道、goroutines),这些结构是专门为帮助您处理这些情况而设计的。


例如,您可以使用通道发出信号:


func main() {    

    

    // end signal

    finished := make(chan bool)

    

    // create and run a goroutine

    go func() {

       // do your bass stuff here

       ...

       

       // send a signal

       finished <- true           

    }()

    

    // wait

    <-finished

}

一种常见的模式是将通道传递给执行该工作的函数:


func main() {    

    

    // end signal

    finished := make(chan bool)

    

    // PlayFile is responsible for

    // signalling 'finished' when done

    go PlayFile(someFile, finished);

    

    // wait

    <-finished

}

或者,如果您有多个例程,您将使用WaitGroup:


func main() {


    // create the waitgroup

    var wg sync.WaitGroup


    // number of semaphores

    wg.Add(1)


    go func() {

       // notify WaitGroup when done

       // (the 'defer' keyword means

       // this call will be executed before

       // returning from the method)

       defer wg.Done()

       

       // do your bass stuff here

       ...

    }()


    wg.Wait()

}


查看完整回答
反对 回复 2022-07-18
?
当年话下

TA贡献1890条经验 获得超9个赞

BASS_ChannelGetLength可以用和BASS_ChannelGetPosition功能解决问题。


这是代码:


// +build windows


package main


import (

    "fmt"

    "syscall"

    "time"

    "unsafe"

)


/*

基于 [bass.dll](http://us2.un4seen.com/files/bass24.zip)

和 [Golang syscall](https://github.com/golang/go/wiki/WindowsDLLs)

实现的命令行版播放器。

*/


type (

    BASSErrorGetCode int32

)


const (

    BassUnicode uint32 = 0x80000000 // BASS_UNICODE

    BassSampleFloat uint32 = 256 // BASS_SAMPLE_FLOAT

    BassPosByte uint64 = 0  // BASS_POS_BYTE

)


type BassLib struct {

    libBass syscall.Handle

    init   uintptr

    free   uintptr

    streamCreateFile uintptr

    channelPlay uintptr

    channelPause uintptr

    channelStop uintptr

    channelGetLength uintptr

    channelGetPosition uintptr

    channelBytes2Seconds uintptr

}


func (bass *BassLib) LoadBass(bassDllPath string) bool {

    bass.libBass, _ = syscall.LoadLibrary(bassDllPath)

    if bass.libBass == 0 {

        fmt.Println("Load `bass.dll` library failed!")

        errCode := bass.GetBassErrorGetCode()

        fmt.Println("Bass_Init failed!")

        fmt.Println(errCode)

        return false

    }

    bass.init, _ = syscall.GetProcAddress(bass.libBass, "BASS_Init")

    // BASS_Init(device, freq, flags, win, clsid)

    // see http://www.un4seen.com/doc/#bass/BASS_Init.html

    device := 1

    r, _, _ := syscall.Syscall6(bass.init, 5, uintptr(device), uintptr(44100), uintptr(0), uintptr(0), uintptr(0), 0)

    // var ret = *(* int)(unsafe.Pointer(&r))

    if r == 0 {

        errCode := bass.GetBassErrorGetCode()

        fmt.Println("Bass_Init failed!")

        fmt.Println(errCode)

        return false

    }

    return true

}



func StrPtr(s string) uintptr {

    p, _ := syscall.UTF16PtrFromString(s)

    return uintptr(unsafe.Pointer(p))

}


func (bass *BassLib) PlayFile(filePath string) {

    bass.streamCreateFile, _ = syscall.GetProcAddress(bass.libBass, "BASS_StreamCreateFile")

    // hStream = BASS_StreamCreateFile(mem=0, &file, offset=0, length=0, flags=(A_IsUnicode ? 0x80000000 : 0x40000))

    // see http://www.un4seen.com/doc/#bass/BASS_StreamCreateFile.html

    hStream, _, _ := syscall.Syscall6(bass.streamCreateFile, 5,  uintptr(0), StrPtr(filePath), uintptr(0), uintptr(0), uintptr(BassUnicode|BassSampleFloat), 0)

    bass.channelPlay, _ = syscall.GetProcAddress(bass.libBass, "BASS_ChannelPlay")

    // BASS_ChannelPlay(hStream)

    // see http://www.un4seen.com/doc/#bass/BASS_ChannelPlay.html

    r, _, _ := syscall.Syscall(bass.channelPlay, 2, hStream, uintptr(0), 0)

    if r == 1 {

        totalDuration := bass.GetAudioByteLength(hStream)

        // currentPos := bass.GetAudioCurrentBytePosition(hStream)

        fmt.Println(totalDuration)

        // fmt.Println(currentPos)

        time.Sleep(time.Second*1)

        for {

            currentPos := bass.GetAudioCurrentBytePosition(hStream)

            if currentPos >= totalDuration {

                break

            }

        }

    } else {

        errCode := bass.GetBassErrorGetCode()

        fmt.Println("Bass_ChannelPlay failed!")

        fmt.Println(errCode)

    }

}


func (bass *BassLib) GetBassErrorGetCode() BASSErrorGetCode {

    bassErrorGetCode, _ := syscall.GetProcAddress(bass.libBass, "BASS_ErrorGetCode")

    // BASS_ErrorGetCode()

    // BASS_OK              BASSErrorGetCode = 0    // all is OK

    // BASS_ERROR_MEM       BASSErrorGetCode = 1    // memory error

    // ...

    // see http://www.un4seen.com/doc/#bass/BASS_ErrorGetCode.html

    errCode, _, _ := syscall.Syscall(bassErrorGetCode, 0, 0, 0, 0)

    var iErrCode = *(*BASSErrorGetCode)(unsafe.Pointer(&errCode))

    return iErrCode

}


func (bass *BassLib) GetAudioByteLength(handle uintptr) uintptr {

    // (QWORD) BASS_ChannelGetLength(handle=hStream, mode)

    // see http://www.un4seen.com/doc/#bass/BASS_ChannelGetLength.html

    bass.channelGetLength, _ = syscall.GetProcAddress(bass.libBass, "BASS_ChannelGetLength")

    len, _, _ := syscall.Syscall(bass.channelGetLength, 2, handle,  uintptr(BassPosByte), 0)

    return len

}



func (bass *BassLib) GetAudioCurrentBytePosition(handle uintptr) uintptr {

    // BASS_ChannelGetPosition(handle=hStream, mode)

    // see http://www.un4seen.com/doc/#bass/BASS_ChannelGetPosition.html

    bass.channelGetPosition, _ = syscall.GetProcAddress(bass.libBass, "BASS_ChannelGetPosition")

    pos, _, _ := syscall.Syscall(bass.channelGetPosition, 2, handle,  uintptr(BassPosByte), 0)

    return pos

}


func (bass *BassLib) GetChannelBytes2Seconds(handle uintptr, pos uintptr) uintptr {

    // BASS_ChannelBytes2Seconds(handle=hStream, pos)

    // see http://www.un4seen.com/doc/#bass/BASS_ChannelBytes2Seconds.html

    // bass.channelBytes2Seconds, _ = syscall.GetProcAddress(bass.libBass, "BASS_ChannelBytes2Seconds")

    len, _, _ := syscall.Syscall(bass.channelBytes2Seconds, 2, handle, pos, 0)

    return len

}





func (bass *BassLib) UnLoad() {

    if bass.libBass != 0 {

        bass.free, _ = syscall.GetProcAddress(bass.libBass, "BASS_Free")

        syscall.Syscall(bass.free, 0, 0, 0, 0)

        // BASS_Free()

        // see http://www.un4seen.com/doc/#bass/BASS_Free.html

        syscall.FreeLibrary(bass.libBass)

    }

}


func main() {

    bass := &BassLib{}

    bass.LoadBass("C:\\workspace\\play\\bass.dll")

    bass.PlayFile("C:\\workspace\\play\\sample.mp3")

    bass.UnLoad()

}

您也可以访问https://gist.github.com/ycrao/e7d1df181f870091b4a6d298d6ea2770#file-bass_play-go-L81-L91。


查看完整回答
反对 回复 2022-07-18
  • 3 回答
  • 0 关注
  • 181 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信