callbacks.c | 12 ++++++++++++ stream.go | 10 +++------- diff --git a/callbacks.c b/callbacks.c index caa7c0dafce4b5902d7ec12611a26160981cc302..5645f30ddfee04b5ee6be70ab1a79834cf311cc8 100644 --- a/callbacks.c +++ b/callbacks.c @@ -6,6 +6,7 @@ // Allocate callback struct in C to ensure it's not managed by the Go GC. This // plays nice with the CGo rules and avoids any confusion. #include +#include // Defined in Go. Uses the same signature as Go, no need for proxy function. int go_readcallback(void *p, unsigned char *buf, int nbytes); @@ -15,3 +16,14 @@ // between Go and C. struct OpusFileCallbacks callbacks = { .read = go_readcallback, }; + +// Proxy function for op_open_callbacks, because it takes a void * context but +// we want to pass it non-pointer data, namely an arbitrary uintptr_t +// value. This is legal C, but go test -race (-d=checkptr) complains anyway. So +// we have this wrapper function to shush it. +// https://groups.google.com/g/golang-nuts/c/995uZyRPKlU +OggOpusFile * +my_open_callbacks(uintptr_t p, const OpusFileCallbacks *cb, int *error) +{ + return op_open_callbacks((void *)p, cb, NULL, 0, error); +} diff --git a/stream.go b/stream.go index 208a0bc9d5562d748365f6a08014ef630a423734..60f99e0ad515537a8d3684fcef9b088c5f6c7d6e 100644 --- a/stream.go +++ b/stream.go @@ -13,9 +13,11 @@ /* #cgo pkg-config: opusfile #include +#include #include extern struct OpusFileCallbacks callbacks; +OggOpusFile *my_open_callbacks(uintptr_t p, const OpusFileCallbacks *cb, int *error); */ import "C" @@ -103,13 +105,7 @@ // Save and Delete from the map around that every time a reader function is // called. streams.Save(s) defer streams.Del(s) - oggfile := C.op_open_callbacks( - // "C code may not keep a copy of a Go pointer after the call returns." - unsafe.Pointer(s.id), - &C.callbacks, - nil, - 0, - &errno) + oggfile := C.my_open_callbacks(C.uintptr_t(s.id), &C.callbacks, &errno) if errno != 0 { return StreamError(errno) }