Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sdroege/gst-plugin-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume@desmottes.be>2021-12-29 18:54:29 +0300
committerGuillaume Desmottes <guillaume.desmottes@onestream.live>2023-03-05 16:35:04 +0300
commit93503c0ca9ab0d4383ce8fe3f003139f5d269a23 (patch)
tree261e6f99f07a8846e88b14602bcb56043915c715 /audio
parentcd177dee869f1fe165cdabefc31cb672d584e5b6 (diff)
spotify: move Settings to common module
Will be used to implement the lyrics source element. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1095>
Diffstat (limited to 'audio')
-rw-r--r--audio/spotify/src/common.rs171
-rw-r--r--audio/spotify/src/lib.rs1
-rw-r--r--audio/spotify/src/spotifyaudiosrc/imp.rs188
3 files changed, 198 insertions, 162 deletions
diff --git a/audio/spotify/src/common.rs b/audio/spotify/src/common.rs
new file mode 100644
index 00000000..ae2bd176
--- /dev/null
+++ b/audio/spotify/src/common.rs
@@ -0,0 +1,171 @@
+// Copyright (C) 2021 Guillaume Desmottes <guillaume@desmottes.be>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use anyhow::bail;
+
+use gst::glib;
+use gst::prelude::*;
+
+use librespot::core::{
+ cache::Cache, config::SessionConfig, session::Session, spotify_id::SpotifyId,
+};
+use librespot::discovery::Credentials;
+
+#[derive(Default, Debug, Clone)]
+pub struct Settings {
+ username: String,
+ password: String,
+ cache_credentials: String,
+ cache_files: String,
+ cache_max_size: u64,
+ pub track: String,
+}
+
+impl Settings {
+ pub fn properties() -> Vec<glib::ParamSpec> {
+ vec![glib::ParamSpecString::builder("username")
+ .nick("Username")
+ .blurb("Spotify device username from https://www.spotify.com/us/account/set-device-password/")
+ .default_value(Some(""))
+ .mutable_ready()
+ .build(),
+ glib::ParamSpecString::builder("password")
+ .nick("Password")
+ .blurb("Spotify device password from https://www.spotify.com/us/account/set-device-password/")
+ .default_value(Some(""))
+ .mutable_ready()
+ .build(),
+ glib::ParamSpecString::builder("cache-credentials")
+ .nick("Credentials cache")
+ .blurb("Directory where to cache Spotify credentials")
+ .default_value(Some(""))
+ .mutable_ready()
+ .build(),
+ glib::ParamSpecString::builder("cache-files")
+ .nick("Files cache")
+ .blurb("Directory where to cache downloaded files from Spotify")
+ .default_value(Some(""))
+ .mutable_ready()
+ .build(),
+ glib::ParamSpecUInt64::builder("cache-max-size")
+ .nick("Cache max size")
+ .blurb("The max allowed size of the cache, in bytes, or 0 to disable the cache limit")
+ .default_value(0)
+ .mutable_ready()
+ .build(),
+ glib::ParamSpecString::builder("track")
+ .nick("Spotify URI")
+ .blurb("Spotify track URI, in the form 'spotify:track:$SPOTIFY_ID'")
+ .default_value(Some(""))
+ .mutable_ready()
+ .build(),
+ ]
+ }
+
+ pub fn set_property(&mut self, value: &glib::Value, pspec: &glib::ParamSpec) {
+ match pspec.name() {
+ "username" => {
+ self.username = value.get().expect("type checked upstream");
+ }
+ "password" => {
+ self.password = value.get().expect("type checked upstream");
+ }
+ "cache-credentials" => {
+ self.cache_credentials = value.get().expect("type checked upstream");
+ }
+ "cache-files" => {
+ self.cache_files = value.get().expect("type checked upstream");
+ }
+ "cache-max-size" => {
+ self.cache_max_size = value.get().expect("type checked upstream");
+ }
+ "track" => {
+ self.track = value.get().expect("type checked upstream");
+ }
+ _ => unimplemented!(),
+ }
+ }
+
+ pub fn property(&self, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "username" => self.username.to_value(),
+ "password" => self.password.to_value(),
+ "cache-credentials" => self.cache_credentials.to_value(),
+ "cache-files" => self.cache_files.to_value(),
+ "cache-max-size" => self.cache_max_size.to_value(),
+ "track" => self.track.to_value(),
+ _ => unimplemented!(),
+ }
+ }
+
+ pub async fn connect_session<T>(
+ &self,
+ src: T,
+ cat: &gst::DebugCategory,
+ ) -> anyhow::Result<Session>
+ where
+ T: glib::IsA<glib::Object>,
+ {
+ let credentials_cache = if self.cache_credentials.is_empty() {
+ None
+ } else {
+ Some(&self.cache_credentials)
+ };
+
+ let files_cache = if self.cache_files.is_empty() {
+ None
+ } else {
+ Some(&self.cache_files)
+ };
+
+ let max_size = if self.cache_max_size != 0 {
+ Some(self.cache_max_size)
+ } else {
+ None
+ };
+
+ let cache = Cache::new(credentials_cache, None, files_cache, max_size)?;
+
+ let credentials = match cache.credentials() {
+ Some(cached_cred) => {
+ gst::debug!(cat, obj: &src, "reuse credentials from cache",);
+ cached_cred
+ }
+ None => {
+ gst::debug!(cat, obj: &src, "credentials not in cache",);
+
+ if self.username.is_empty() {
+ bail!("username is not set and credentials are not in cache");
+ }
+ if self.password.is_empty() {
+ bail!("password is not set and credentials are not in cache");
+ }
+
+ let cred = Credentials::with_password(&self.username, &self.password);
+ cache.save_credentials(&cred);
+ cred
+ }
+ };
+
+ let (session, _credentials) =
+ Session::connect(SessionConfig::default(), credentials, Some(cache), false).await?;
+
+ Ok(session)
+ }
+
+ pub fn track_id(&self) -> anyhow::Result<SpotifyId> {
+ if self.track.is_empty() {
+ bail!("track is not set");
+ }
+ let track = SpotifyId::from_uri(&self.track).map_err(|_| {
+ anyhow::anyhow!("failed to create Spotify URI from track {}", self.track)
+ })?;
+
+ Ok(track)
+ }
+}
diff --git a/audio/spotify/src/lib.rs b/audio/spotify/src/lib.rs
index cfce28a5..f650ab78 100644
--- a/audio/spotify/src/lib.rs
+++ b/audio/spotify/src/lib.rs
@@ -14,6 +14,7 @@
*/
use gst::glib;
+mod common;
mod spotifyaudiosrc;
fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
diff --git a/audio/spotify/src/spotifyaudiosrc/imp.rs b/audio/spotify/src/spotifyaudiosrc/imp.rs
index f15ada69..fcaab88f 100644
--- a/audio/spotify/src/spotifyaudiosrc/imp.rs
+++ b/audio/spotify/src/spotifyaudiosrc/imp.rs
@@ -8,7 +8,6 @@
use std::sync::{mpsc, Arc, Mutex, MutexGuard};
-use anyhow::bail;
use futures::future::{AbortHandle, Abortable, Aborted};
use once_cell::sync::Lazy;
use tokio::{runtime, task::JoinHandle};
@@ -18,10 +17,6 @@ use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_base::subclass::{base_src::CreateSuccess, prelude::*};
-use librespot::core::{
- cache::Cache, config::SessionConfig, session::Session, spotify_id::SpotifyId,
-};
-use librespot::discovery::Credentials;
use librespot::playback::{
audio_backend::{Sink, SinkResult},
config::PlayerConfig,
@@ -67,12 +62,7 @@ struct State {
#[derive(Default)]
struct Settings {
- username: String,
- password: String,
- cache_credentials: String,
- cache_files: String,
- cache_max_size: u64,
- track: String,
+ common: crate::common::Settings,
bitrate: Bitrate,
}
@@ -99,120 +89,39 @@ impl ObjectSubclass for SpotifyAudioSrc {
impl ObjectImpl for SpotifyAudioSrc {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ let mut props = crate::common::Settings::properties();
let default = Settings::default();
- vec![glib::ParamSpecString::builder("username")
- .nick("Username")
- .blurb("Spotify device username from https://www.spotify.com/us/account/set-device-password/")
- .default_value(Some(default.username.as_str()))
- .mutable_ready()
- .build(),
- glib::ParamSpecString::builder("password")
- .nick("Password")
- .blurb("Spotify device password from https://www.spotify.com/us/account/set-device-password/")
- .default_value(Some(default.password.as_str()))
- .mutable_ready()
- .build(),
- glib::ParamSpecString::builder("cache-credentials")
- .nick("Credentials cache")
- .blurb("Directory where to cache Spotify credentials")
- .default_value(Some(default.cache_credentials.as_str()))
- .mutable_ready()
- .build(),
- glib::ParamSpecString::builder("cache-files")
- .nick("Files cache")
- .blurb("Directory where to cache downloaded files from Spotify")
- .default_value(Some(default.cache_files.as_str()))
+ props.push(
+ glib::ParamSpecEnum::builder_with_default::<Bitrate>("bitrate", default.bitrate)
+ .nick("Spotify bitrate")
+ .blurb("Spotify audio bitrate in kbit/s")
.mutable_ready()
.build(),
- glib::ParamSpecUInt64::builder("cache-max-size")
- .nick("Cache max size")
- .blurb("The max allowed size of the cache, in bytes, or 0 to disable the cache limit")
- .default_value(default.cache_max_size)
- .mutable_ready()
- .build(),
- glib::ParamSpecString::builder("track")
- .nick("Spotify URI")
- .blurb("Spotify track URI, in the form 'spotify:track:$SPOTIFY_ID'")
- .default_value(Some(default.track.as_str()))
- .mutable_ready()
- .build(),
- glib::ParamSpecEnum::builder_with_default::<Bitrate>("bitrate", default.bitrate)
- .nick("Spotify bitrate")
- .blurb("Spotify audio bitrate in kbit/s")
- .mutable_ready()
- .build()
- ]
+ );
+ props
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
+ let mut settings = self.settings.lock().unwrap();
+
match pspec.name() {
- "username" => {
- let mut settings = self.settings.lock().unwrap();
- settings.username = value.get().expect("type checked upstream");
- }
- "password" => {
- let mut settings = self.settings.lock().unwrap();
- settings.password = value.get().expect("type checked upstream");
- }
- "cache-credentials" => {
- let mut settings = self.settings.lock().unwrap();
- settings.cache_credentials = value.get().expect("type checked upstream");
- }
- "cache-files" => {
- let mut settings = self.settings.lock().unwrap();
- settings.cache_files = value.get().expect("type checked upstream");
- }
- "cache-max-size" => {
- let mut settings = self.settings.lock().unwrap();
- settings.cache_max_size = value.get().expect("type checked upstream");
- }
- "track" => {
- let mut settings = self.settings.lock().unwrap();
- settings.track = value.get().expect("type checked upstream");
- }
"bitrate" => {
- let mut settings = self.settings.lock().unwrap();
settings.bitrate = value.get().expect("type checked upstream");
}
- _ => unimplemented!(),
+ _ => settings.common.set_property(value, pspec),
}
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ let settings = self.settings.lock().unwrap();
+
match pspec.name() {
- "username" => {
- let settings = self.settings.lock().unwrap();
- settings.username.to_value()
- }
- "password" => {
- let settings = self.settings.lock().unwrap();
- settings.password.to_value()
- }
- "cache-credentials" => {
- let settings = self.settings.lock().unwrap();
- settings.cache_credentials.to_value()
- }
- "cache-files" => {
- let settings = self.settings.lock().unwrap();
- settings.cache_files.to_value()
- }
- "cache-max-size" => {
- let settings = self.settings.lock().unwrap();
- settings.cache_max_size.to_value()
- }
- "track" => {
- let settings = self.settings.lock().unwrap();
- settings.track.to_value()
- }
- "bitrate" => {
- let settings = self.settings.lock().unwrap();
- settings.bitrate.to_value()
- }
- _ => unimplemented!(),
+ "bitrate" => settings.bitrate.to_value(),
+ _ => settings.common.property(pspec),
}
}
}
@@ -389,10 +298,10 @@ impl URIHandlerImpl for SpotifyAudioSrc {
fn uri(&self) -> Option<String> {
let settings = self.settings.lock().unwrap();
- if settings.track.is_empty() {
+ if settings.common.track.is_empty() {
None
} else {
- Some(settings.track.clone())
+ Some(settings.common.track.clone())
}
}
@@ -451,63 +360,23 @@ impl SpotifyAudioSrc {
}
}
- let (credentials, cache, track, bitrate) = {
- let settings = self.settings.lock().unwrap();
-
- let credentials_cache = if settings.cache_credentials.is_empty() {
- None
- } else {
- Some(&settings.cache_credentials)
- };
-
- let files_cache = if settings.cache_files.is_empty() {
- None
- } else {
- Some(&settings.cache_files)
- };
-
- let max_size = if settings.cache_max_size != 0 {
- Some(settings.cache_max_size)
- } else {
- None
- };
-
- let cache = Cache::new(credentials_cache, None, files_cache, max_size)?;
-
- let credentials = match cache.credentials() {
- Some(cached_cred) => {
- gst::debug!(CAT, imp: self, "reuse credentials from cache",);
- cached_cred
- }
- None => {
- gst::debug!(CAT, imp: self, "credentials not in cache",);
+ let src = self.obj();
- if settings.username.is_empty() {
- bail!("username is not set and credentials are not in cache");
- }
- if settings.password.is_empty() {
- bail!("password is not set and credentials are not in cache");
- }
+ let (session, track, bitrate) = {
+ let (common, bitrate) = {
+ let settings = self.settings.lock().unwrap();
+ let bitrate = settings.bitrate.into();
- let cred = Credentials::with_password(&settings.username, &settings.password);
- cache.save_credentials(&cred);
- cred
- }
+ (settings.common.clone(), bitrate)
};
- if settings.track.is_empty() {
- bail!("track is not set")
- }
-
- let bitrate = settings.bitrate.into();
+ let session = common.connect_session(src.clone(), &CAT).await?;
+ let track = common.track_id()?;
gst::debug!(CAT, imp: self, "Requesting bitrate {:?}", bitrate);
- (credentials, cache, settings.track.clone(), bitrate)
+ (session, track, bitrate)
};
- let (session, _credentials) =
- Session::connect(SessionConfig::default(), credentials, Some(cache), false).await?;
-
let player_config = PlayerConfig {
passthrough: true,
bitrate,
@@ -523,11 +392,6 @@ impl SpotifyAudioSrc {
Box::new(BufferSink { sender })
});
- let track = match SpotifyId::from_uri(&track) {
- Ok(track) => track,
- Err(_) => bail!("Failed to create Spotify URI from track"),
- };
-
player.load(track, true, 0);
let player_channel_handle = RUNTIME.spawn(async move {