initial MPMedia bridge
This commit is contained in:
@@ -38,6 +38,7 @@ type App struct {
|
||||
Player *player.Player
|
||||
UpdateChecker UpdateChecker
|
||||
MPRISHandler *MPRISHandler
|
||||
MPMediaHandler *MPMediaHandler
|
||||
|
||||
// UI callbacks to be set in main
|
||||
OnReactivate func()
|
||||
@@ -110,6 +111,7 @@ func StartupApp(appName, displayAppName, appVersionTag, configFile, latestReleas
|
||||
})
|
||||
|
||||
a.setupMPRIS(displayAppName)
|
||||
a.setupMPMedia()
|
||||
|
||||
return a, nil
|
||||
}
|
||||
@@ -231,6 +233,11 @@ func (a *App) setupMPRIS(mprisAppName string) {
|
||||
a.MPRISHandler.Start()
|
||||
}
|
||||
|
||||
func (a *App) setupMPMedia() {
|
||||
a.MPMediaHandler = NewMPMediaHandler(a.Player, a.PlaybackManager)
|
||||
a.MPMediaHandler.ArtURLLookup = a.ImageManager.GetCoverArtUrl
|
||||
}
|
||||
|
||||
func (a *App) LoginToDefaultServer(string) error {
|
||||
serverCfg := a.ServerManager.GetDefaultServer()
|
||||
if serverCfg == nil {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package backend
|
||||
|
||||
/**
|
||||
* This file handles implementation of MacOS native controls via the native 'MediaPlayer' framework
|
||||
**/
|
||||
|
||||
// #cgo CFLAGS: -x objective-c
|
||||
// #cgo LDFLAGS: -framework Cocoa -framework MediaPlayer
|
||||
// #include "mpmediabridge.h"
|
||||
import (
|
||||
"C"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||
"github.com/dweymouth/supersonic/player"
|
||||
)
|
||||
|
||||
type MPMediaHandler struct {
|
||||
player *player.Player
|
||||
playbackManager *PlaybackManager
|
||||
ArtURLLookup func(trackID string) (string, error)
|
||||
}
|
||||
|
||||
func NewMPMediaHandler(player *player.Player, playbackManager *PlaybackManager) *MPMediaHandler {
|
||||
mp := &MPMediaHandler{
|
||||
player: player,
|
||||
playbackManager: playbackManager,
|
||||
}
|
||||
|
||||
mp.playbackManager.OnSongChange(func(track, _ *mediaprovider.Track) {
|
||||
if mp.ArtURLLookup != nil {
|
||||
mp.ArtURLLookup(track.CoverArtID)
|
||||
}
|
||||
|
||||
cTitle := C.CString(track.Name)
|
||||
defer C.free(unsafe.Pointer(cTitle))
|
||||
|
||||
artist := ""
|
||||
if len(track.ArtistNames) > 0 {
|
||||
artist = track.ArtistNames[0]
|
||||
}
|
||||
|
||||
cArtist := C.CString(artist)
|
||||
defer C.free(unsafe.Pointer(cArtist))
|
||||
|
||||
// TODO: pass in local URL for image (can be loaded via NSImage)
|
||||
C.setNowPlayingInfo(cTitle, cArtist)
|
||||
})
|
||||
|
||||
mp.player.OnStopped(func() {
|
||||
// TODO: media stopped playing
|
||||
fmt.Println("Stopped")
|
||||
})
|
||||
|
||||
mp.player.OnPlaying(func() {
|
||||
// TODO: media playing
|
||||
fmt.Println("Playing")
|
||||
})
|
||||
|
||||
mp.player.OnPaused(func() {
|
||||
// TODO: media paused
|
||||
fmt.Println("Paused")
|
||||
})
|
||||
|
||||
return mp
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* mpmediabridge.h
|
||||
*
|
||||
* This file provides a C bridge to the Objective-C framework for macOS media playback.
|
||||
* It offers a simplified interface to interact with the MPNowPlayingInfoCenter and other
|
||||
* related media playback functionalities in macOS without dealing directly with
|
||||
* Objective-C code.
|
||||
*/
|
||||
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <MediaPlayer/MediaPlayer.h>
|
||||
|
||||
/**
|
||||
* Updates the "Now Playing" information on macOS for media playback
|
||||
* using the MPNowPlayingInfoCenter API to set the metadata
|
||||
* for the currently playing media in the system's "Now Playing" interface.
|
||||
*/
|
||||
void setNowPlayingInfo(const char *title, const char *artist);
|
||||
@@ -0,0 +1,47 @@
|
||||
#import "mpmediabridge.h"
|
||||
|
||||
/**
|
||||
* Native Objective-C function for setting "Now Playing" information on macOS for media playback using the native APIs.
|
||||
*/
|
||||
void setNowPlayingInfoNative(const char *title, const char *artist, double trackDuration, NSImage *artworkImage, double elapsedTime) {
|
||||
|
||||
// TODO: the remove command center logic needs to move
|
||||
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
|
||||
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
|
||||
// TODO: Handle play command
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
}];
|
||||
|
||||
[commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
|
||||
// TODO: Handle pause command
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
}];
|
||||
|
||||
[commandCenter.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
|
||||
// TODO: Handle toggle command
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
}];
|
||||
|
||||
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
|
||||
|
||||
NSDictionary *nowPlayingInfo = @{
|
||||
MPMediaItemPropertyTitle: [NSString stringWithUTF8String:title],
|
||||
MPMediaItemPropertyArtist: [NSString stringWithUTF8String:artist],
|
||||
MPMediaItemPropertyPlaybackDuration: @(trackDuration),
|
||||
MPNowPlayingInfoPropertyElapsedPlaybackTime: @(elapsedTime)
|
||||
};
|
||||
|
||||
infoCenter.nowPlayingInfo = nowPlayingInfo;
|
||||
infoCenter.playbackState = MPNowPlayingPlaybackStatePlaying;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'C' bridge function for 'setNowPlayingInfoNative'
|
||||
*/
|
||||
void setNowPlayingInfo(const char *title, const char *artist) {
|
||||
const char *imagePath = "/path/to/image.png";
|
||||
double trackDuration = 300.0;
|
||||
double elapsedTime = 120.0;
|
||||
|
||||
setNowPlayingInfoNative(title, artist, trackDuration, NULL, elapsedTime);
|
||||
}
|
||||
Reference in New Issue
Block a user