Golang绑定bass.dll的实现与使用
Golang绑定bass.dll的实现与使用 我正在为bass.dll编写绑定(https://github.com/lexesv/gobass.dll),遇到了一些困难。
我无法封装这些函数:
typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user);
HRECORD BASSDEF(BASS_RecordStart)(DWORD freq, DWORD chans, DWORD flags, RECORDPROC *proc, void *user);
我尝试了:
func RecordStart(freq int, chans int, flags int, proc RecordCallback) (int, error) {
h := C.BASS_RecordStart(C.DWORD(freq), C.DWORD(chans), C.DWORD(flags), (*C.RECORDPROC)(unsafe.Pointer(&proc)), nil)
if h != 0 {
return int(h), nil
} else {
return 0, errMsg(int(C.BASS_ErrorGetCode()))
}
}
type RecordCallback = func(handle C.HRECORD, buffer *C.char, length C.DWORD, user *C.char) bool
但在编译示例时,我遇到了错误: ./record.go:15: cannot use MyRecordCallback (type func(C.HRECORD, *C.char, C.DWORD, *C.char) bool) as type func(bass.C.HRECORD, *bass.C.char, bass.C.DWORD, *bass.C.char) bool in argument to bass.RecordStart
func main() {
fmt.Println(bass.RecordInit(-1))
fmt.Println(bass.RecordStart(44100, 2, 0, MyRecordCallback))
select {}
}
func MyRecordCallback(handle C.HRECORD, buffer *C.char, length C.DWORD, user *C.char) bool {
fmt.Println("...")
return true
}
请帮助我解决如何正确封装回调函数的问题。
更多关于Golang绑定bass.dll的实现与使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang绑定bass.dll的实现与使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中封装C回调函数时,需要确保回调函数的签名与C函数期望的签名完全匹配。问题在于Go回调函数类型定义中的C类型与调用时使用的类型不一致。
以下是正确的实现方式:
package main
/*
#include "bass.h"
*/
import "C"
import (
"fmt"
"unsafe"
)
// 定义回调函数类型
type RecordCallback func(handle C.HRECORD, buffer unsafe.Pointer, length C.DWORD, user unsafe.Pointer) C.BOOL
// 全局变量存储回调函数引用
var recordCallback RecordCallback
// 导出给C调用的回调函数
//export goRecordProc
func goRecordProc(handle C.HRECORD, buffer unsafe.Pointer, length C.DWORD, user unsafe.Pointer) C.BOOL {
if recordCallback != nil {
return recordCallback(handle, buffer, length, user)
}
return C.BOOL(1)
}
func RecordStart(freq int, chans int, flags int, proc RecordCallback) (int, error) {
// 保存回调函数引用
recordCallback = proc
h := C.BASS_RecordStart(
C.DWORD(freq),
C.DWORD(chans),
C.DWORD(flags),
(C.RECORDPROC)(C.goRecordProc),
nil,
)
if h != 0 {
return int(h), nil
}
return 0, fmt.Errorf("BASS error: %d", C.BASS_ErrorGetCode())
}
func RecordInit(device int) bool {
return C.BASS_RecordInit(C.int(device)) != 0
}
使用示例:
package main
/*
#include "bass.h"
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
fmt.Println(RecordInit(-1))
fmt.Println(RecordStart(44100, 2, 0, MyRecordCallback))
select {}
}
func MyRecordCallback(handle C.HRECORD, buffer unsafe.Pointer, length C.DWORD, user unsafe.Pointer) C.BOOL {
fmt.Printf("Record callback: handle=%v, length=%d\n", handle, length)
return C.BOOL(1)
}
关键点说明:
- 使用
//export指令导出Go函数供C调用 - 回调函数返回类型使用
C.BOOL而不是bool - 参数类型使用
unsafe.Pointer来处理C的void*类型 - 通过全局变量保存回调函数引用,避免被垃圾回收
- 确保所有C类型在Go中的定义一致
编译时需要确保CGO正确配置,回调函数能够被C代码正确调用。这种方法可以避免类型不匹配的错误,并确保回调函数在整个录音过程中保持有效。

