diff --git a/backend/smtc.go b/backend/smtc.go index 6df9069b..f1b56b6d 100644 --- a/backend/smtc.go +++ b/backend/smtc.go @@ -1,159 +1,159 @@ -//go:build windows - -package backend - -/* -#cgo CFLAGS: -I . -void btn_callback_cgo(int in); -void seek_callback_cgo(int in); -*/ -import "C" - -import ( - "errors" - "fmt" - "unsafe" - - "golang.org/x/sys/windows" -) - -type SMTCPlaybackState int -type SMTCButton int - -const ( - // constants from smtc.h in github.com/supersonic-app/smtc-dll - SMTCPlaybackStateStopped SMTCPlaybackState = 2 - SMTCPlaybackStatePlaying SMTCPlaybackState = 3 - SMTCPlaybackStatePaused SMTCPlaybackState = 4 - - SMTCButtonPlay SMTCButton = 0 - SMTCButtonPause SMTCButton = 1 - SMTCButtonStop SMTCButton = 2 - SMTCButtonPrevious SMTCButton = 4 - SMTCButtonNext SMTCButton = 5 -) - -type SMTC struct { - dll *windows.DLL - - onButtonPressed func(SMTCButton) - onSeek func(int) -} - -var smtcInstance *SMTC - -func InitSMTCForWindow(hwnd uintptr) (*SMTC, error) { - dll, err := windows.LoadDLL("smtc.dll") - if err != nil { - return nil, err - } - - proc, err := dll.FindProc("InitializeForWindow") - if err != nil { - return nil, err - } - - hr, _, _ := proc.Call(hwnd, uintptr(unsafe.Pointer(C.btn_callback_cgo)), uintptr(unsafe.Pointer(C.seek_callback_cgo))) - if hr < 0 { - return nil, fmt.Errorf("InitializeForWindow failed with HRESULT=%d", hr) - } - - smtcInstance = &SMTC{dll: dll} - return smtcInstance, nil -} - -func (s *SMTC) OnButtonPressed(f func(SMTCButton)) { - s.onButtonPressed = f -} - -func (s *SMTC) OnSeek(f func(millis int)) { - s.onSeek = f -} - -func (s *SMTC) Shutdown() { - if s.dll == nil { - return - } - proc, err := s.dll.FindProc("Destroy") - if err == nil { - proc.Call() - } - - s.dll.Release() - s.dll = nil - smtcInstance = nil -} - -func (s *SMTC) UpdatePlaybackState(state SMTCPlaybackState) error { - if s.dll == nil { - return errors.New("SMTC DLL not available") - } - - proc, err := s.dll.FindProc("UpdatePlaybackState") - if err != nil { - return err - } - - if hr, _, _ := proc.Call(uintptr(state)); hr < 0 { - return fmt.Errorf("UpdatePlaybackState failed with HRESULT=%d", hr) - } - return nil -} - -func (s *SMTC) UpdateMetadata(title, artist string) error { - if s.dll == nil { - return errors.New("SMTC DLL not available") - } - - utfTitle, err := windows.UTF16PtrFromString(title) - if err != nil { - return err - } - - utfArtist, err := windows.UTF16PtrFromString(artist) - if err != nil { - return err - } - - proc, err := s.dll.FindProc("UpdateMetadata") - if err != nil { - return err - } - - hr, _, _ := proc.Call(uintptr(unsafe.Pointer(utfTitle)), uintptr(unsafe.Pointer(utfArtist))) - if hr < 0 { - return fmt.Errorf("UpdateMetadata failed with HRESULT=%d", hr) - } - return nil -} - -func (s *SMTC) UpdatePosition(positionMillis, durationMillis int) error { - if s.dll == nil { - return errors.New("SMTC DLL not available") - } - - proc, err := s.dll.FindProc("UpdatePosition") - if err != nil { - return err - } - - hr, _, _ := proc.Call(uintptr(positionMillis), uintptr(durationMillis)) - if hr < 0 { - return fmt.Errorf("UpdatePosition failed with HRESULT=%d", hr) - } - return nil -} - -//export btnCallback -func btnCallback(in int) { - if smtcInstance != nil && smtcInstance.onButtonPressed != nil { - smtcInstance.onButtonPressed(SMTCButton(in)) - } -} - -//export seekCallback -func seekCallback(millis int) { - if smtcInstance != nil && smtcInstance.onSeek != nil { - smtcInstance.onSeek(millis) - } -} +//go:build windows + +package backend + +/* +#cgo CFLAGS: -I . +void btn_callback_cgo(int in); +void seek_callback_cgo(int in); +*/ +import "C" + +import ( + "errors" + "fmt" + "unsafe" + + "golang.org/x/sys/windows" +) + +type SMTCPlaybackState int +type SMTCButton int + +const ( + // constants from smtc.h in github.com/supersonic-app/smtc-dll + SMTCPlaybackStateStopped SMTCPlaybackState = 2 + SMTCPlaybackStatePlaying SMTCPlaybackState = 3 + SMTCPlaybackStatePaused SMTCPlaybackState = 4 + + SMTCButtonPlay SMTCButton = 0 + SMTCButtonPause SMTCButton = 1 + SMTCButtonStop SMTCButton = 2 + SMTCButtonPrevious SMTCButton = 4 + SMTCButtonNext SMTCButton = 5 +) + +type SMTC struct { + dll *windows.DLL + + onButtonPressed func(SMTCButton) + onSeek func(int) +} + +var smtcInstance *SMTC + +func InitSMTCForWindow(hwnd uintptr) (*SMTC, error) { + dll, err := windows.LoadDLL("smtc.dll") + if err != nil { + return nil, err + } + + proc, err := dll.FindProc("InitializeForWindow") + if err != nil { + return nil, err + } + + hr, _, _ := proc.Call(hwnd, uintptr(unsafe.Pointer(C.btn_callback_cgo)), uintptr(unsafe.Pointer(C.seek_callback_cgo))) + if hr < 0 { + return nil, fmt.Errorf("InitializeForWindow failed with HRESULT=%d", hr) + } + + smtcInstance = &SMTC{dll: dll} + return smtcInstance, nil +} + +func (s *SMTC) OnButtonPressed(f func(SMTCButton)) { + s.onButtonPressed = f +} + +func (s *SMTC) OnSeek(f func(millis int)) { + s.onSeek = f +} + +func (s *SMTC) Shutdown() { + if s.dll == nil { + return + } + proc, err := s.dll.FindProc("Destroy") + if err == nil { + proc.Call() + } + + s.dll.Release() + s.dll = nil + smtcInstance = nil +} + +func (s *SMTC) UpdatePlaybackState(state SMTCPlaybackState) error { + if s.dll == nil { + return errors.New("SMTC DLL not available") + } + + proc, err := s.dll.FindProc("UpdatePlaybackState") + if err != nil { + return err + } + + if hr, _, _ := proc.Call(uintptr(state)); hr < 0 { + return fmt.Errorf("UpdatePlaybackState failed with HRESULT=%d", hr) + } + return nil +} + +func (s *SMTC) UpdateMetadata(title, artist string) error { + if s.dll == nil { + return errors.New("SMTC DLL not available") + } + + utfTitle, err := windows.UTF16PtrFromString(title) + if err != nil { + return err + } + + utfArtist, err := windows.UTF16PtrFromString(artist) + if err != nil { + return err + } + + proc, err := s.dll.FindProc("UpdateMetadata") + if err != nil { + return err + } + + hr, _, _ := proc.Call(uintptr(unsafe.Pointer(utfTitle)), uintptr(unsafe.Pointer(utfArtist))) + if hr < 0 { + return fmt.Errorf("UpdateMetadata failed with HRESULT=%d", hr) + } + return nil +} + +func (s *SMTC) UpdatePosition(positionMillis, durationMillis int) error { + if s.dll == nil { + return errors.New("SMTC DLL not available") + } + + proc, err := s.dll.FindProc("UpdatePosition") + if err != nil { + return err + } + + hr, _, _ := proc.Call(uintptr(positionMillis), uintptr(durationMillis)) + if hr < 0 { + return fmt.Errorf("UpdatePosition failed with HRESULT=%d", hr) + } + return nil +} + +//export btnCallback +func btnCallback(in int) { + if smtcInstance != nil && smtcInstance.onButtonPressed != nil { + smtcInstance.onButtonPressed(SMTCButton(in)) + } +} + +//export seekCallback +func seekCallback(millis int) { + if smtcInstance != nil && smtcInstance.onSeek != nil { + smtcInstance.onSeek(millis) + } +} diff --git a/backend/smtc_cfuncs.go b/backend/smtc_cfuncs.go index 9c1b317c..9ccd9491 100644 --- a/backend/smtc_cfuncs.go +++ b/backend/smtc_cfuncs.go @@ -1,16 +1,16 @@ -//go:build windows - -package backend - -/* -void btn_callback_cgo(int in) { - void btnCallback(int); - btnCallback(in); -} - -void seek_callback_cgo(int in) { - void seekCallback(int); - seekCallback(in); -} -*/ -import "C" +//go:build windows + +package backend + +/* +void btn_callback_cgo(int in) { + void btnCallback(int); + btnCallback(in); +} + +void seek_callback_cgo(int in) { + void seekCallback(int); + seekCallback(in); +} +*/ +import "C" diff --git a/backend/smtc_unsupported.go b/backend/smtc_unsupported.go index 36c0ba19..6a19e8d7 100644 --- a/backend/smtc_unsupported.go +++ b/backend/smtc_unsupported.go @@ -1,32 +1,47 @@ -//go:build !windows - -package backend - -import "errors" - -type SMTCPlaybackState int - -const ( - SMTCPlaybackStateStopped SMTCPlaybackState = 0 - SMTCPlaybackStatePlaying SMTCPlaybackState = 1 - SMTCPlaybackStatePaused SMTCPlaybackState = 2 -) - -type SMTC struct{} - -var smtcUnsupportedErr = errors.New("SMTC is not supported on this platformo") - -func InitSMTCForWindow(hwnd uintptr) (*SMTC, error) { - return nil, smtcUnsupportedErr -} - -func (s *SMTC) UpdatePlaybackState(state SMTCPlaybackState) error { - return smtcUnsupportedErr -} - -func (s *SMTC) UpdateMetadata(title, artist string) error { - return smtcUnsupportedErr -} - -func (s *SMTC) Shutdown() { -} +//go:build !windows + +package backend + +import "errors" + +type SMTCPlaybackState int +type SMTCButton int + +const ( + // constants from smtc.h in github.com/supersonic-app/smtc-dll + SMTCPlaybackStateStopped SMTCPlaybackState = 2 + SMTCPlaybackStatePlaying SMTCPlaybackState = 3 + SMTCPlaybackStatePaused SMTCPlaybackState = 4 + + SMTCButtonPlay SMTCButton = 0 + SMTCButtonPause SMTCButton = 1 + SMTCButtonStop SMTCButton = 2 + SMTCButtonPrevious SMTCButton = 4 + SMTCButtonNext SMTCButton = 5 +) + +type SMTC struct{} + +var smtcUnsupportedErr = errors.New("SMTC is not supported on this platformo") + +func InitSMTCForWindow(hwnd uintptr) (*SMTC, error) { + return nil, smtcUnsupportedErr +} + +func (s *SMTC) OnButtonPressed(func(SMTCButton)) {} + +func (s *SMTC) OnSeek(f func(millis int)) {} + +func (s *SMTC) Shutdown() {} + +func (s *SMTC) UpdatePlaybackState(state SMTCPlaybackState) error { + return smtcUnsupportedErr +} + +func (s *SMTC) UpdateMetadata(title, artist string) error { + return smtcUnsupportedErr +} + +func (s *SMTC) UpdatePosition(positionMillis, durationMillis int) error { + return smtcUnsupportedErr +} diff --git a/go.mod b/go.mod index e20b4539..ab5a6851 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/supersonic-app/go-subsonic v0.0.0-20241224013245-9b2841f3711d github.com/zalando/go-keyring v0.2.1 golang.org/x/net v0.25.0 + golang.org/x/sys v0.20.0 golang.org/x/text v0.16.0 ) @@ -50,7 +51,6 @@ require ( github.com/yuin/goldmark v1.7.1 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect - golang.org/x/sys v0.20.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect )