Skip to content

Commit 6e8d381

Browse files
committed
complete basics for macos
1 parent e453a56 commit 6e8d381

File tree

7 files changed

+325
-67
lines changed

7 files changed

+325
-67
lines changed

build.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ fn main() {
2929
if !status.success() {
3030
panic!("Swift compilation failed");
3131
}
32-
33-
// Tell cargo to link the library
32+
3433
println!("cargo:rustc-link-search=native={}", out_dir);
3534
println!("cargo:rustc-link-lib=static=swiftlib");
3635

examples/basic.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
use system_media::MediaSession;
4+
5+
fn main() {
6+
println!("Now Playing session started");
7+
println!("Keeping process alive... Press Ctrl+C to exit");
8+
let mut session = MediaSession::new();
9+
session.set_title("Hello!");
10+
session.start();
11+
}

examples/tmp.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/lib.rs

Lines changed: 130 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,146 @@
1+
#[cfg(target_os = "macos")]
2+
mod macos;
3+
#[cfg(not(any(
4+
target_os = "macos"
5+
)))]
6+
mod null;
17

8+
pub trait MediaBackend {
9+
fn set_title(&self, title: &str);
10+
fn set_artist(&self, artist: &str);
11+
fn set_album(&self, album: &str);
12+
fn set_genre(&self, genre: &str);
13+
fn set_media_type(&self, media_type: MediaType);
14+
fn set_playback_duration(&self, duration: f64);
15+
fn set_elapsed_duration(&self, duration: f64);
16+
fn set_playback_rate(&self, rate: f64);
17+
fn start_session(&self);
18+
fn stop_session(&self);
19+
}
20+
21+
// Defines the type of media being presented
22+
#[derive(Clone, Copy, PartialEq)]
23+
pub enum MediaType {
24+
Audio,
25+
Video
26+
}
227

3-
#[unsafe(no_mangle)]
4-
pub extern "C" fn rust_hello() {
5-
println!("Hello from Rust!");
28+
pub struct Metadata {
29+
title: String,
30+
artist: String,
31+
album: String,
32+
genre: String,
33+
media_type: MediaType,
34+
duration: f64,
35+
playback_rate: f64,
636
}
737

8-
unsafe extern "C" {
9-
fn hello_world();
38+
pub struct MediaSession {
39+
backend: Box<dyn MediaBackend>,
40+
metadata: Metadata,
1041
}
1142

43+
impl MediaSession {
1244

45+
pub fn new() -> Self {
46+
#[cfg(target_os = "macos")]
47+
let backend = Box::new(macos::NowPlayingBackend::new());
1348

14-
use std::thread;
15-
use std::time::Duration;
49+
#[cfg(not(any(
50+
target_os = "macos"
51+
)))]
52+
let backend = Box::new(null::NullBackend::new());
1653

17-
pub fn call_swift() {
18-
unsafe {
19-
hello_world();
54+
Self {
55+
backend,
56+
metadata: Metadata {
57+
title: "".to_string(),
58+
artist: "".to_string(),
59+
album: "".to_string(),
60+
genre: "".to_string(),
61+
media_type: MediaType::Audio,
62+
duration: 0.0f64,
63+
playback_rate: 0.0f64,
64+
},
65+
}
2066
}
2167

22-
thread::sleep(Duration::from_secs(10));
23-
}
68+
pub fn set_title(&mut self, title: &str) {
69+
self.metadata.title = title.to_string();
70+
self.backend.set_title(title);
71+
}
72+
73+
pub fn title(&self) -> &str {
74+
&self.metadata.title
75+
}
76+
77+
pub fn set_artist(&mut self, artist: &str) {
78+
self.metadata.artist = artist.to_string();
79+
self.backend.set_artist(artist);
80+
}
81+
82+
pub fn artist(&self) -> &str {
83+
&self.metadata.artist
84+
}
85+
86+
pub fn set_album(&mut self, album: &str) {
87+
self.metadata.album = album.to_string();
88+
self.backend.set_album(album);
89+
}
90+
91+
pub fn album(&self) -> &str {
92+
&self.metadata.album
93+
}
94+
95+
pub fn set_genre(&mut self, genre: &str) {
96+
self.metadata.genre = genre.to_string();
97+
self.backend.set_album(genre);
98+
}
99+
100+
pub fn genre(&self) -> &str {
101+
&self.metadata.genre
102+
}
103+
104+
pub fn set_media_type(&mut self, media_type: MediaType) {
105+
self.metadata.media_type = media_type;
106+
self.backend.set_media_type(media_type);
107+
}
108+
109+
pub fn media_type(&self) -> MediaType {
110+
self.metadata.media_type
111+
}
112+
113+
pub fn set_playback_duration(&mut self, duration: f64) {
114+
self.metadata.duration = duration;
115+
self.backend.set_playback_duration(duration);
116+
}
117+
118+
pub fn duration(&self) -> f64 {
119+
self.metadata.duration
120+
}
121+
122+
pub fn set_elapsed_duration(&self, duration: f64) {
123+
self.backend.set_elapsed_duration(duration);
124+
}
125+
126+
pub fn set_playback_rate(&mut self, rate: f64) {
127+
self.metadata.playback_rate = rate;
128+
self.backend.set_playback_rate(rate);
129+
}
130+
131+
pub fn playback_rate(&self) -> f64 {
132+
self.metadata.playback_rate
133+
}
24134

135+
pub fn start(&self) {
136+
self.backend.start_session();
137+
}
138+
139+
pub fn stop(&self) {
140+
self.backend.stop_session();
141+
}
25142

143+
}
26144

27145

28146
#[cfg(test)]

src/macos/mod.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use std::ffi::CString;
2+
use crate::{MediaBackend, MediaType};
3+
// Swift functions called by Rust
4+
unsafe extern "C" {
5+
fn swift_set_metadata_title(title: *mut i8);
6+
fn swift_set_metadata_artist(artist: *mut i8);
7+
fn swift_set_metadata_album(album: *mut i8);
8+
fn swift_set_metadata_genre(genre: *mut i8);
9+
fn swift_set_metadata_media_type(id: i64);
10+
fn swift_set_playback_duration(seconds: f64);
11+
fn swift_set_elapsed_duration(seconds: f64);
12+
fn swift_set_playback_rate(rate: f64);
13+
fn swift_start_session();
14+
}
15+
16+
// Rust functions called by Swift
17+
// TODO: Add hooks for SystemMedia events.
18+
#[unsafe(no_mangle)]
19+
pub unsafe extern "C" fn rust_resume_playback_command() { }
20+
#[unsafe(no_mangle)]
21+
pub unsafe extern "C" fn rust_pause_playback_command() { }
22+
#[unsafe(no_mangle)]
23+
pub unsafe extern "C" fn rust_next_track_playback_command() { }
24+
#[unsafe(no_mangle)]
25+
pub unsafe extern "C" fn rust_previous_track_playback_command() { }
26+
27+
fn str_to_raw(s: &str) -> *mut i8 {
28+
let c_string = CString::new(s).expect("CString::new() failed. ");
29+
c_string.into_raw()
30+
}
31+
32+
pub struct NowPlayingBackend;
33+
34+
impl NowPlayingBackend {
35+
pub fn new() -> Self { Self }
36+
}
37+
38+
impl MediaBackend for NowPlayingBackend {
39+
fn set_title(&self, title: &str) {
40+
unsafe {
41+
swift_set_metadata_title(str_to_raw(title));
42+
}
43+
}
44+
45+
fn set_artist(&self, artist: &str) {
46+
unsafe {
47+
swift_set_metadata_artist(str_to_raw(artist));
48+
}
49+
}
50+
51+
fn set_album(&self, album: &str) {
52+
unsafe {
53+
swift_set_metadata_album(str_to_raw(album));
54+
}
55+
}
56+
57+
fn set_genre(&self, genre: &str) {
58+
unsafe {
59+
swift_set_metadata_genre(str_to_raw(genre));
60+
}
61+
}
62+
63+
fn set_media_type(&self, media_type: MediaType) {
64+
unsafe {
65+
if media_type == MediaType::Audio {
66+
swift_set_metadata_media_type(0);
67+
} else {
68+
swift_set_metadata_media_type(1);
69+
}
70+
}
71+
}
72+
73+
fn set_playback_duration(&self, duration: f64) {
74+
unsafe {
75+
swift_set_playback_duration(duration);
76+
}
77+
}
78+
79+
fn set_elapsed_duration(&self, duration: f64) {
80+
unsafe {
81+
swift_set_elapsed_duration(duration);
82+
}
83+
}
84+
85+
fn set_playback_rate(&self, rate: f64) {
86+
unsafe {
87+
swift_set_playback_rate(rate);
88+
}
89+
}
90+
91+
fn start_session(&self) {
92+
unsafe {
93+
swift_start_session();
94+
}
95+
}
96+
97+
fn stop_session(&self) {
98+
println!("How do we stop a session?");
99+
}
100+
}

0 commit comments

Comments
 (0)