mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
player: Implement playback
This commit is contained in:
parent
9489aaf2ee
commit
c378305465
6 changed files with 335 additions and 31 deletions
196
Cargo.lock
generated
196
Cargo.lock
generated
|
|
@ -49,6 +49,12 @@ version = "1.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic_refcell"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -140,6 +146,12 @@ version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fallible-iterator"
|
name = "fallible-iterator"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -162,6 +174,12 @@ dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fragile"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
|
|
@ -458,6 +476,125 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b369a1eb2f7db49920d3d590bd988c5fb56dbf2347e1efb60307fe953546ee5d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"glib",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"itertools",
|
||||||
|
"libc",
|
||||||
|
"muldiv",
|
||||||
|
"num-integer",
|
||||||
|
"num-rational",
|
||||||
|
"option-operations",
|
||||||
|
"paste",
|
||||||
|
"pretty-hex",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-base"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fe38a6d5c1e516ce3fd6069e972a540d315448ed69fdadad739e6c6c6eb2a01"
|
||||||
|
dependencies = [
|
||||||
|
"atomic_refcell",
|
||||||
|
"cfg-if",
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-base-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-base-sys"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4ca701f9078fe115b29b24c80910b577f9cb5b039182f050dbadf5933594b64"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-player"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e68dc9772932f6133a9517742918b13ab5414db1f47e19daebc3027a1c3d20d2"
|
||||||
|
dependencies = [
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-player-sys",
|
||||||
|
"gstreamer-video",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-player-sys"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5ef4d00b43d0aa94e9a518e6ef4a4c504b4b855304a0a5f4ed1493d5e5ca66c"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"gstreamer-video-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-sys"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f86bf9de67a6ab7af67ac11588f4939e984a936030437219f269fe969d79ad8c"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-video"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01b4d3141362b3d44a684e697d2bc55fea73d023315449cda83f0f4324531d64"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-channel",
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-base",
|
||||||
|
"gstreamer-video-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-video-sys"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09cdc36baab839921b05d2468524da649f373dccc5f966c75e564029dc135b1c"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gstreamer-base-sys",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4"
|
name = "gtk4"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|
@ -576,6 +713,15 @@ dependencies = [
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.64"
|
version = "0.3.64"
|
||||||
|
|
@ -683,12 +829,20 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "muldiv"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "musicus"
|
name = "musicus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"fragile",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
|
"gstreamer-player",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -710,6 +864,27 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
|
@ -754,6 +929,15 @@ version = "1.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-operations"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0"
|
||||||
|
dependencies = [
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
@ -785,6 +969,12 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
|
@ -809,6 +999,12 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty-hex"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
adw = { package = "libadwaita", version = "0.5", features = ["v1_4"] }
|
adw = { package = "libadwaita", version = "0.5", features = ["v1_4"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
fragile = "2"
|
||||||
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
||||||
|
gstreamer-player = "0.21"
|
||||||
gtk = { package = "gtk4", version = "0.7", features = ["v4_12", "blueprint"] }
|
gtk = { package = "gtk4", version = "0.7", features = ["v4_12", "blueprint"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"--socket=fallback-x11",
|
"--socket=fallback-x11",
|
||||||
"--device=dri",
|
"--device=dri",
|
||||||
"--socket=wayland",
|
"--socket=wayland",
|
||||||
|
"--socket=pulseaudio",
|
||||||
"--filesystem=host"
|
"--filesystem=host"
|
||||||
],
|
],
|
||||||
"build-options": {
|
"build-options": {
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,12 @@ use self::{application::MusicusApplication, window::MusicusWindow};
|
||||||
|
|
||||||
use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR};
|
use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR};
|
||||||
use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
|
use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
|
||||||
|
use gstreamer_player::gst;
|
||||||
use gtk::{gio, glib, prelude::*};
|
use gtk::{gio, glib, prelude::*};
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
fn main() -> glib::ExitCode {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
gst::init().expect("Failed to initialize GStreamer!");
|
||||||
|
|
||||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
|
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
|
||||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
|
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
|
||||||
|
|
|
||||||
133
src/player.rs
133
src/player.rs
|
|
@ -1,5 +1,12 @@
|
||||||
use crate::playlist_item::PlaylistItem;
|
use crate::playlist_item::PlaylistItem;
|
||||||
use gtk::{gio, glib, glib::Properties, prelude::*, subclass::prelude::*};
|
use fragile::Fragile;
|
||||||
|
use gstreamer_player::gst;
|
||||||
|
use gtk::{
|
||||||
|
gio,
|
||||||
|
glib::{self, Properties},
|
||||||
|
prelude::*,
|
||||||
|
subclass::prelude::*,
|
||||||
|
};
|
||||||
use std::cell::{Cell, OnceCell};
|
use std::cell::{Cell, OnceCell};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -17,34 +24,48 @@ mod imp {
|
||||||
#[property(get, set = Self::set_current_index)]
|
#[property(get, set = Self::set_current_index)]
|
||||||
pub current_index: Cell<u32>,
|
pub current_index: Cell<u32>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub current_time: Cell<u32>,
|
pub duration_ms: Cell<u64>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub remaining_time: Cell<u32>,
|
pub current_time_ms: Cell<u64>,
|
||||||
#[property(get, set = Self::set_position)]
|
#[property(get, set = Self::set_position)]
|
||||||
pub position: Cell<f64>,
|
pub position: Cell<f64>,
|
||||||
|
#[property(get, construct_only)]
|
||||||
|
pub player: OnceCell<gstreamer_player::Player>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MusicusPlayer {
|
impl MusicusPlayer {
|
||||||
pub fn set_current_index(&self, index: u32) {
|
pub fn set_current_index(&self, index: u32) {
|
||||||
let playlist = self.playlist.get().unwrap();
|
let playlist = self.playlist.get().unwrap();
|
||||||
|
|
||||||
if let Some(item) = playlist.item(self.current_index.get()) {
|
|
||||||
item.downcast::<PlaylistItem>()
|
|
||||||
.unwrap()
|
|
||||||
.set_is_playing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.current_index.set(index);
|
|
||||||
|
|
||||||
if let Some(item) = playlist.item(index) {
|
if let Some(item) = playlist.item(index) {
|
||||||
item.downcast::<PlaylistItem>()
|
if let Some(old_item) = playlist.item(self.current_index.get()) {
|
||||||
.unwrap()
|
old_item.downcast::<PlaylistItem>()
|
||||||
.set_is_playing(true);
|
.unwrap()
|
||||||
|
.set_is_playing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = item.downcast::<PlaylistItem>().unwrap();
|
||||||
|
let uri = glib::filename_to_uri(&item.path(), None)
|
||||||
|
.expect("track path should be parsable as an URI");
|
||||||
|
|
||||||
|
let player = self.player.get().unwrap();
|
||||||
|
player.set_uri(Some(&uri));
|
||||||
|
if self.playing.get() {
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_index.set(index);
|
||||||
|
item.set_is_playing(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_position(&self, position: f64) {
|
pub fn set_position(&self, position: f64) {
|
||||||
self.position.set(position);
|
self.player
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.seek(gst::ClockTime::from_mseconds(
|
||||||
|
(position * self.duration_ms.get() as f64) as u64,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +76,63 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for MusicusPlayer {}
|
impl ObjectImpl for MusicusPlayer {
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let player = self.player.get().unwrap();
|
||||||
|
|
||||||
|
let mut config = player.config();
|
||||||
|
config.set_position_update_interval(250);
|
||||||
|
player.set_config(config).unwrap();
|
||||||
|
player.set_video_track_enabled(false);
|
||||||
|
|
||||||
|
let obj = Fragile::new(self.obj().to_owned());
|
||||||
|
player.connect_end_of_stream(move |_| {
|
||||||
|
obj.get().next();
|
||||||
|
});
|
||||||
|
|
||||||
|
let obj = Fragile::new(self.obj().to_owned());
|
||||||
|
player.connect_position_updated(move |_, current_time| {
|
||||||
|
if let Some(current_time) = current_time {
|
||||||
|
let obj = obj.get();
|
||||||
|
let imp = obj.imp();
|
||||||
|
|
||||||
|
let current_time_ms = current_time.mseconds();
|
||||||
|
let duration_ms = imp.duration_ms.get();
|
||||||
|
let mut position = current_time_ms as f64 / duration_ms as f64;
|
||||||
|
if position > 1.0 {
|
||||||
|
position = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
imp.current_time_ms.set(current_time_ms);
|
||||||
|
obj.notify_current_time_ms();
|
||||||
|
|
||||||
|
imp.position.set(position);
|
||||||
|
obj.notify_position();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let obj = Fragile::new(self.obj().to_owned());
|
||||||
|
player.connect_duration_changed(move |_, duration| {
|
||||||
|
if let Some(duration) = duration {
|
||||||
|
let obj = obj.get();
|
||||||
|
let imp = obj.imp();
|
||||||
|
|
||||||
|
let duration_ms = duration.mseconds();
|
||||||
|
|
||||||
|
imp.duration_ms.set(duration_ms);
|
||||||
|
obj.notify_duration_ms();
|
||||||
|
|
||||||
|
imp.current_time_ms.set(0);
|
||||||
|
obj.notify_current_time_ms();
|
||||||
|
|
||||||
|
imp.position.set(0.0);
|
||||||
|
obj.notify_position();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
|
|
@ -64,14 +141,22 @@ glib::wrapper! {
|
||||||
|
|
||||||
impl MusicusPlayer {
|
impl MusicusPlayer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let player = gstreamer_player::Player::new(
|
||||||
|
None::<gstreamer_player::PlayerVideoRenderer>,
|
||||||
|
Some(gstreamer_player::PlayerGMainContextSignalDispatcher::new(
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
glib::Object::builder()
|
glib::Object::builder()
|
||||||
.property("active", false)
|
.property("active", false)
|
||||||
.property("playing", false)
|
.property("playing", false)
|
||||||
.property("playlist", gio::ListStore::new::<PlaylistItem>())
|
.property("playlist", gio::ListStore::new::<PlaylistItem>())
|
||||||
.property("current-index", 0u32)
|
.property("current-index", 0u32)
|
||||||
.property("current-time", 0u32)
|
.property("current-time-ms", 0u64)
|
||||||
.property("remaining-time", 10000u32)
|
.property("duration-ms", 60_000u64)
|
||||||
.property("position", 0.0)
|
.property("position", 0.0)
|
||||||
|
.property("player", player)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,15 +167,21 @@ impl MusicusPlayer {
|
||||||
playlist.append(&track);
|
playlist.append(&track);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_active(true);
|
if !self.active() && playlist.n_items() > 0 {
|
||||||
|
self.set_active(true);
|
||||||
|
self.set_current_index(0);
|
||||||
|
self.play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn play(&self) {
|
pub fn play(&self) {
|
||||||
self.set_playing(true)
|
self.player().play();
|
||||||
|
self.set_playing(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pause(&self) {
|
pub fn pause(&self) {
|
||||||
self.set_playing(false)
|
self.player().pause();
|
||||||
|
self.set_playing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_item(&self) -> Option<PlaylistItem> {
|
pub fn current_item(&self) -> Option<PlaylistItem> {
|
||||||
|
|
|
||||||
|
|
@ -111,17 +111,17 @@ mod imp {
|
||||||
.playlist()
|
.playlist()
|
||||||
.connect_items_changed(clone!(@weak obj => move |_, _, _, _| obj.imp().update()));
|
.connect_items_changed(clone!(@weak obj => move |_, _, _, _| obj.imp().update()));
|
||||||
|
|
||||||
player
|
player.connect_current_time_ms_notify(clone!(@weak obj => move |player| {
|
||||||
.bind_property("current-time", &self.current_time_label.get(), "label")
|
let imp = obj.imp();
|
||||||
.transform_to(|_, t: u32| Some(format!("{:0>2}:{:0>2}", t / 60, t % 60)))
|
imp.current_time_label.set_label(&format_time(player.current_time_ms()));
|
||||||
.sync_create()
|
imp.remaining_time_label.set_label(&format_time(player.duration_ms() - player.current_time_ms()));
|
||||||
.build();
|
}));
|
||||||
|
|
||||||
player
|
player.connect_duration_ms_notify(clone!(@weak obj => move |player| {
|
||||||
.bind_property("remaining-time", &self.remaining_time_label.get(), "label")
|
let imp = obj.imp();
|
||||||
.transform_to(|_, t: u32| Some(format!("{:0>2}:{:0>2}", t / 60, t % 60)))
|
imp.current_time_label.set_label(&format_time(player.current_time_ms()));
|
||||||
.sync_create()
|
imp.remaining_time_label.set_label(&format_time(player.duration_ms() - player.current_time_ms()));
|
||||||
.build();
|
}));
|
||||||
|
|
||||||
player
|
player
|
||||||
.bind_property("position", &self.slider.adjustment(), "value")
|
.bind_property("position", &self.slider.adjustment(), "value")
|
||||||
|
|
@ -187,3 +187,15 @@ impl PlayerBar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_time(time_ms: u64) -> String {
|
||||||
|
let s = time_ms / 1000;
|
||||||
|
let (m, s) = (s / 60, s % 60);
|
||||||
|
let (h, m) = (m / 60, m % 60);
|
||||||
|
|
||||||
|
if h > 0 {
|
||||||
|
format!("{h:0>2}:{m:0>2}:{s:0>2}")
|
||||||
|
} else {
|
||||||
|
format!("{m:0>2}:{s:0>2}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue