Skip to content

Commit e453a56

Browse files
committed
connected swift to rust; implemented basic NowPlaying API
1 parent 28de474 commit e453a56

File tree

6 files changed

+143
-7
lines changed

6 files changed

+143
-7
lines changed

build.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,37 @@
1-
fn main() {}
1+
use std::process::Command;
2+
use std::env;
3+
4+
#[cfg(target_os = "macos")]
5+
fn main() {
6+
7+
// Path to your Swift source file
8+
let swift_file = "src/macos/nowplaying.swift";
9+
10+
// Output directory for compiled library
11+
let out_dir = env::var("OUT_DIR").unwrap();
12+
let lib_path = format!("{}/libswiftlib.a", out_dir);
13+
14+
// Compile Swift into a static library
15+
let status = Command::new("swiftc")
16+
.args(&[
17+
"-static",
18+
"-emit-library",
19+
"-framework",
20+
"MediaPlayer",
21+
"-framework",
22+
"AVFoundation",
23+
"-o",
24+
&lib_path,
25+
swift_file])
26+
.status()
27+
.expect("Failed to compile Swift code");
28+
29+
if !status.success() {
30+
panic!("Swift compilation failed");
31+
}
32+
33+
// Tell cargo to link the library
34+
println!("cargo:rustc-link-search=native={}", out_dir);
35+
println!("cargo:rustc-link-lib=static=swiftlib");
36+
37+
}

examples/tmp.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
use system_media::call_swift;
4+
5+
fn main() {
6+
println!("Hello world.");
7+
call_swift();
8+
}

src/lib.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
1-
pub fn add(a: u64, b: u64) -> u64 {
2-
a + b
1+
2+
3+
#[unsafe(no_mangle)]
4+
pub extern "C" fn rust_hello() {
5+
println!("Hello from Rust!");
6+
}
7+
8+
unsafe extern "C" {
9+
fn hello_world();
310
}
411

12+
13+
14+
use std::thread;
15+
use std::time::Duration;
16+
17+
pub fn call_swift() {
18+
unsafe {
19+
hello_world();
20+
}
21+
22+
thread::sleep(Duration::from_secs(10));
23+
}
24+
25+
26+
27+
528
#[cfg(test)]
629
mod tests {
730
use super::*;
831

932
#[test]
10-
fn it_works() {
11-
let result = add(2, 2);
12-
assert_eq!(result, 4);
13-
}
33+
fn it_works() {}
1434
}

src/macos/mod.rs

Whitespace-only changes.

src/macos/nowplaying.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import Foundation
2+
import MediaPlayer
3+
import AVFoundation
4+
5+
// Tell Swift this function exists somewhere at runtime
6+
@_silgen_name("rust_hello")
7+
public func rustHello()
8+
9+
@_cdecl("hello_world")
10+
public func startNowPlayingSession() {
11+
// Get the shared MPNowPlayingInfoCenter
12+
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
13+
14+
// Set up remote command targets BEFORE setting the info
15+
setupRemoteCommandTargets()
16+
17+
// Create now playing info dictionary
18+
var nowPlayingInfo = [String: Any]()
19+
20+
// Set basic metadata
21+
nowPlayingInfo[MPMediaItemPropertyTitle] = "Your Song Title"
22+
nowPlayingInfo[MPMediaItemPropertyArtist] = "Your Artist Name"
23+
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = "Your Album Name"
24+
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = 180.0
25+
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = 0.0
26+
// This is crucial - set to 1.0 to indicate "playing" state
27+
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
28+
// Add media type
29+
nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue
30+
31+
// Set the now playing info
32+
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
33+
34+
print("Now Playing session started")
35+
print("NowPlaying info set: \(nowPlayingInfo)")
36+
37+
// Keep the process alive so the Now Playing info persists
38+
print("Keeping process alive... Press Ctrl+C to exit")
39+
RunLoop.main.run()
40+
}
41+
42+
private func setupRemoteCommandTargets() {
43+
let commandCenter = MPRemoteCommandCenter.shared()
44+
45+
// Play command
46+
commandCenter.playCommand.addTarget { event in
47+
// Handle play action
48+
print("Play command received")
49+
return .success
50+
}
51+
52+
// Pause command
53+
commandCenter.pauseCommand.addTarget { event in
54+
// Handle pause action
55+
print("Pause command received")
56+
return .success
57+
}
58+
59+
// Next track command
60+
commandCenter.nextTrackCommand.addTarget { event in
61+
// Handle next track action
62+
print("Next track command received")
63+
return .success
64+
}
65+
66+
// Previous track command
67+
commandCenter.previousTrackCommand.addTarget { event in
68+
// Handle previous track action
69+
print("Previous track command received")
70+
return .success
71+
}
72+
}

src/session.rs

Whitespace-only changes.

0 commit comments

Comments
 (0)