From 01288e1a86b04581910ac88165f3cdfe5b4672fd Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 1 Feb 2012 08:29:25 -0500 Subject: [PATCH] Libsaria: Make alsa controls its own thing I created a new preference for "Using ALSA" that people can set if they want to use extra alsa features. This should allow the UI to provide a dropdown list of outputs that users can select. Once a UI is in place, users can play music either on their computer speakers or pipe it out to their blu ray players (or other device). Signed-off-by: Bryan Schumaker --- PKGBUILD | 2 +- Sconstruct | 1 + include/libsaria/audio.h | 8 ++++ libsaria/audio/alsa.cpp | 91 ++++++++++++++++++++++++++++++++++++++++ libsaria/audio/audio.cpp | 44 ++++++++++++++++--- libsaria/audio/audio.h | 12 ++++++ libsaria/libsaria.cpp | 2 +- 7 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 libsaria/audio/alsa.cpp diff --git a/PKGBUILD b/PKGBUILD index beeb6713..5e7a3cae 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -6,7 +6,7 @@ pkgdesc="A simple GTK and gstreamer based music player." url="http://www.ocarinaproject.net/" arch=('x86_64' 'i686') license=('SimPL') -depends=('gtk2' 'gstreamer0.10-base' 'taglib') +depends=('gtk2' 'gstreamer0.10-base' 'gstreamer0.10-base-plugins' 'taglib') optdepends=('gstreamer0.10-good-plugins' 'gstreamer0.10-bad-plugins' 'gstreamer0.10-ugly-plugins') makedepends=('scons') conflicts=() diff --git a/Sconstruct b/Sconstruct index 3f5600b9..994c7e67 100644 --- a/Sconstruct +++ b/Sconstruct @@ -26,6 +26,7 @@ env.Append(CPPPATH = "include") env.ParseConfig('pkg-config --cflags --libs gtk+-2.0') env.ParseConfig('pkg-config --cflags --libs gstreamer-0.10') +env.ParseConfig('pkg-config --cflags --libs gstreamer-interfaces-0.10') env.ParseConfig('pkg-config --cflags --libs taglib') def version_h(target, source, env): diff --git a/include/libsaria/audio.h b/include/libsaria/audio.h index 495eda0e..0159847d 100644 --- a/include/libsaria/audio.h +++ b/include/libsaria/audio.h @@ -5,6 +5,7 @@ extern "C" { #include } +#include #include using namespace std; @@ -13,8 +14,15 @@ namespace libsaria namespace audio { void init(int, char**); + void swap(); string get_current_file(); + /* Alsa controls */ + void use_alsa(bool); + bool using_alsa(); + list *get_alsa_devices(); + void set_device(string &); + /* Playback control functions */ void load_file(string); void load(string); diff --git a/libsaria/audio/alsa.cpp b/libsaria/audio/alsa.cpp new file mode 100644 index 00000000..09c2aea0 --- /dev/null +++ b/libsaria/audio/alsa.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2012 Bryan Schumaker. +#include +#include +#include +#include +#include "audio.h" + +#include +using namespace std; + +static GstElement *alsa = NULL; +static list devices; + +static void probe_devices() +{ + GValueArray *array; + GValue *value; + + devices.clear(); + array = gst_property_probe_probe_and_get_values_name(GST_PROPERTY_PROBE(alsa), "device"); + + devices.push_back("default"); + for (unsigned int i = 0; i < array->n_values; i++) { + value = g_value_array_get_nth(array, i); + devices.push_back(g_value_get_string(value)); + } +} + +static void set_alsa_device(string device) +{ + g_object_set(G_OBJECT(alsa), "device", device.c_str(), NULL); +} + +static void add_alsa() +{ + println("Adding ALSA"); + alsa = gst_element_factory_make("alsasink", "alsa"); + probe_devices(); + set_audio_sink(alsa); +} + +static void remove_alsa() +{ + println("Removing ALSA"); + set_alsa_device("default"); + /* Removing the sink will also deallocate it */ + set_audio_sink(NULL); +} + +namespace libsaria +{ + + void audio::use_alsa(bool use) + { + struct StoredAudioState state; + save_audio_state(&state); + + if (use == true) + add_alsa(); + else + remove_alsa(); + + load_audio_state(&state); + prefs::set("alsa", use); + } + + bool audio::using_alsa() + { + return prefs::get_bool("alsa"); + } + + void audio::init_alsa() + { + use_alsa(using_alsa()); + } + + list *audio::get_alsa_devices() + { + return &devices; + } + + void audio::set_device(string &device) + { + struct StoredAudioState state; + + save_audio_state(&state); + g_object_set(G_OBJECT(alsa), "device", device.c_str(), NULL); + load_audio_state(&state); + } + +}; /* Namespace: libsaria */ diff --git a/libsaria/audio/audio.cpp b/libsaria/audio/audio.cpp index 031c8620..16be306d 100644 --- a/libsaria/audio/audio.cpp +++ b/libsaria/audio/audio.cpp @@ -7,8 +7,8 @@ #include "audio.h" GstElement *player = NULL; -GstElement *alsa = NULL; GstBus *bus = NULL; +static bool restoring_state = false; static void parse_error(GstMessage *error) { @@ -28,7 +28,8 @@ static void notify_audio_changed() libsaria::audio::pause(); libsaria::set_pause_after(false); } - trigger_callback(TRACK_LOADED); + if (restoring_state == false) + trigger_callback(TRACK_LOADED); } static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data) @@ -59,6 +60,40 @@ static void audio_changed(GstElement *playbin, gpointer data) notify_audio_changed(); } +/* + * Set sink to NULL to use the default sink + */ +void set_audio_sink(GstElement *sink) +{ + g_object_set(G_OBJECT(player), "audio-sink", sink, NULL); +} + +void save_audio_state(struct StoredAudioState *state) +{ + state->cur_file = libsaria::audio::get_current_file(); + state->position = libsaria::audio::position(); + state->was_playing = libsaria::audio::is_playing(); +} + +void load_audio_state(struct StoredAudioState *state) +{ + restoring_state = true; + + libsaria::audio::load(state->cur_file); + if (state->was_playing == true) + libsaria::audio::play(); + else + libsaria::audio::pause(); + /* + * Wait for async play() or pause() to finish, otherwise + * the seek won't succeed + */ + gst_element_get_state(GST_ELEMENT(player), NULL, NULL, GST_CLOCK_TIME_NONE); + libsaria::audio::seek_to(state->position); + + restoring_state = false; +} + namespace libsaria { @@ -68,18 +103,15 @@ namespace libsaria gst_init(&argc, &argv); player = gst_element_factory_make("playbin2", "player"); - alsa = gst_element_factory_make("alsasink", "alsa"); bus = gst_pipeline_get_bus(GST_PIPELINE(player)); gst_bus_add_watch(bus, on_message, NULL); - /* Without this gapless playback won't work */ - g_object_set(G_OBJECT(player), "audio-sink", alsa, NULL); - g_signal_connect(player, "about-to-finish", G_CALLBACK(about_to_finish), NULL); g_signal_connect(player, "audio-changed", G_CALLBACK(audio_changed), NULL); init_volume(); + init_alsa(); } }; diff --git a/libsaria/audio/audio.h b/libsaria/audio/audio.h index 036965a1..3ac022ac 100644 --- a/libsaria/audio/audio.h +++ b/libsaria/audio/audio.h @@ -11,13 +11,25 @@ extern "C" { extern GstElement *player; extern GstBus *bus; +struct StoredAudioState +{ + string cur_file; + double position; + bool was_playing; +}; + void load_file(GstElement *, string); +void set_audio_sink(GstElement *); +void save_audio_state(struct StoredAudioState *); +void load_audio_state(struct StoredAudioState *); + namespace libsaria { namespace audio { void init_volume(); + void init_alsa(); } } diff --git a/libsaria/libsaria.cpp b/libsaria/libsaria.cpp index f7e1f028..380a01eb 100644 --- a/libsaria/libsaria.cpp +++ b/libsaria/libsaria.cpp @@ -18,12 +18,12 @@ namespace libsaria { srand( time(NULL) ); println("Initializing libsaria"); + libsaria::prefs::load(); audio::init(argc, argv); println("saria dir: %s", get_saria_dir().c_str()); make_saria_dir(); libsaria::library::load(); libsaria::queue::load(); - libsaria::prefs::load(); } void quit()