Extend MPMedia implementation to handle 'seek'

This commit is contained in:
zackslash
2023-10-20 18:04:05 +01:00
parent 6aeaf07611
commit cc85b79f79
3 changed files with 53 additions and 13 deletions
+19 -2
View File
@@ -16,6 +16,7 @@ import (
)
import (
"fmt"
"log"
"unsafe"
@@ -26,7 +27,7 @@ import (
// os_remote_command_callback is called by Objective-C when incoming OS media commands are received.
//
//export os_remote_command_callback
func os_remote_command_callback(command C.Command) {
func os_remote_command_callback(command C.Command, value C.int) {
switch command {
case C.PLAY:
mpMediaEventRecipient.OnCommandPlay()
@@ -40,6 +41,8 @@ func os_remote_command_callback(command C.Command) {
mpMediaEventRecipient.OnCommandPreviousTrack()
case C.NEXT_TRACK:
mpMediaEventRecipient.OnCommandNextTrack()
case C.SEEK:
mpMediaEventRecipient.OnCommandSeek(int(value))
default:
log.Printf("unknown OS command received: %v", command)
}
@@ -85,7 +88,9 @@ func NewMPMediaHandler(player *player.Player, playbackManager *PlaybackManager)
cArtURL := C.CString(artURL)
defer C.free(unsafe.Pointer(cArtURL))
C.set_os_now_playing_info(cTitle, cArtist, cArtURL)
cTrackDuration := C.double(track.Duration)
C.set_os_now_playing_info(cTitle, cArtist, cArtURL, cTrackDuration)
}
})
@@ -101,6 +106,10 @@ func NewMPMediaHandler(player *player.Player, playbackManager *PlaybackManager)
C.set_os_playback_state_paused()
})
mp.player.OnSeek(func() {
C.update_os_now_playing_info_position(C.double(mp.player.GetStatus().TimePos))
})
return mp
}
@@ -159,3 +168,11 @@ func (mp *MPMediaHandler) OnCommandPreviousTrack() {
}
mp.player.SeekBackOrPrevious()
}
// MPMediaHandler instance received OS command to 'seek'
func (mp *MPMediaHandler) OnCommandSeek(positionSeconds int) {
if mp == nil || mp.player == nil {
return
}
mp.player.Seek(fmt.Sprintf("%d", positionSeconds), player.SeekAbsolute)
}
+6 -3
View File
@@ -20,7 +20,8 @@ typedef enum {
STOP,
TOGGLE,
NEXT_TRACK,
PREVIOUS_TRACK
PREVIOUS_TRACK,
SEEK
} Command;
/**
@@ -30,15 +31,17 @@ void register_os_remote_commands();
/**
* Go-backed callback to static function that is called when OS remote commands are received.
* If a value is anticipated with the specified command, the 'value' argument will be non-zero.
*/
void os_remote_command_callback(Command command);
void os_remote_command_callback(Command command, int value);
/**
* 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 set_os_now_playing_info(const char *title, const char *artist, const char *coverArtFileURL);
void set_os_now_playing_info(const char *title, const char *artist, const char *coverArtFileURL, double trackDuration);
void update_os_now_playing_info_position(double positionSeconds);
/**
* Setter functions for updating the global playback state.
+28 -8
View File
@@ -8,32 +8,40 @@
void register_os_remote_commands() {
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(PLAY);
os_remote_command_callback(PLAY, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.pauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(PAUSE);
os_remote_command_callback(PAUSE, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(TOGGLE);
os_remote_command_callback(TOGGLE, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.stopCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(STOP);
os_remote_command_callback(STOP, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.nextTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(NEXT_TRACK);
os_remote_command_callback(NEXT_TRACK, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.previousTrackCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
os_remote_command_callback(PREVIOUS_TRACK);
os_remote_command_callback(PREVIOUS_TRACK, 0);
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
MPChangePlaybackPositionCommandEvent *positionChangeEvent = (MPChangePlaybackPositionCommandEvent *)event;
double posSecDouble = positionChangeEvent.positionTime;
int posSeconds = (int)posSecDouble;
os_remote_command_callback(SEEK, posSeconds);
return MPRemoteCommandHandlerStatusSuccess;
}];
}
@@ -41,7 +49,7 @@ void register_os_remote_commands() {
/**
* C bridge setting "Now Playing" information on macOS for media playback using the native APIs.
*/
void set_os_now_playing_info(const char *title, const char *artist, const char *coverArtFileURL) {
void set_os_now_playing_info(const char *title, const char *artist, const char *coverArtFileURL, double trackDuration) {
NSString *coverArtLocationString = [NSString stringWithUTF8String:coverArtFileURL];
NSURL *coverArtURL = [NSURL URLWithString:coverArtLocationString];
NSImage *coverArtImage = [[NSImage alloc] initWithContentsOfURL:coverArtURL];
@@ -54,12 +62,24 @@ void set_os_now_playing_info(const char *title, const char *artist, const char *
NSDictionary *nowPlayingInfo = @{
MPMediaItemPropertyTitle: [NSString stringWithUTF8String:title],
MPMediaItemPropertyArtist: [NSString stringWithUTF8String:artist],
MPMediaItemPropertyArtwork: coverArt
MPMediaItemPropertyArtwork: coverArt,
MPMediaItemPropertyPlaybackDuration: @(trackDuration) // Expects 'NSNumber'
};
infoCenter.nowPlayingInfo = nowPlayingInfo;
}
/**
* C bridge updating the OS playback position.
* creates a mutable copy of the immutable dictionary and writes it back with updated position.
*/
void update_os_now_playing_info_position(double positionSeconds) {
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *updatedInfo = [infoCenter.nowPlayingInfo mutableCopy];
updatedInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(positionSeconds);
infoCenter.nowPlayingInfo = [updatedInfo copy];
}
/**
* C bridge setting the OS playback state to 'playing'.
*/