247 lines
5.6 KiB
C++
247 lines
5.6 KiB
C++
/*
|
|
* Copyright 2014 (c) Anna Schumaker.
|
|
*
|
|
* The gst_init() function parses command line options passed to Ocarina
|
|
* through argv. Use the command `gst-inspect-1.0 --help-gst` to find
|
|
* what options are supported.
|
|
*/
|
|
#include <core/audio.h>
|
|
#include <gui/ocarina.h>
|
|
#include <gst/gst.h>
|
|
|
|
|
|
static GstBus *gst_bus;
|
|
static GstElement *gst_player;
|
|
|
|
static Gtk::Button *o_next;
|
|
static Gtk::Button *o_pause;
|
|
static Gtk::Button *o_play;
|
|
static Gtk::Button *o_prev;
|
|
static Gtk::Scale *o_seek;
|
|
static Gtk::Button *o_stop;
|
|
|
|
static Gtk::SpinButton *o_count;
|
|
static Gtk::CheckButton *o_enabled;
|
|
|
|
static Gtk::Label *o_album;
|
|
static Gtk::Label *o_artist;
|
|
static Gtk::Label *o_duration;
|
|
static Gtk::Label *o_position;
|
|
static Gtk::Label *o_title;
|
|
static Glib::RefPtr<Gtk::Adjustment> o_progress;
|
|
|
|
|
|
static bool gst_change_state(GstState state)
|
|
{
|
|
GstStateChangeReturn ret = gst_element_set_state(gst_player, state);
|
|
switch (ret) {
|
|
case GST_STATE_CHANGE_SUCCESS:
|
|
case GST_STATE_CHANGE_ASYNC:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void set_markup(Gtk::Label *label, const std::string &size,
|
|
const std::string &text)
|
|
{
|
|
label->set_markup("<span size='" + size + "'>" +
|
|
Glib::Markup::escape_text(text) + "</span>");
|
|
}
|
|
|
|
|
|
class GSTDriver : public AudioDriver
|
|
{
|
|
public:
|
|
void load(Track *track)
|
|
{
|
|
gchar *uri = gst_filename_to_uri(track->path().c_str(), NULL);
|
|
|
|
gst_change_state(GST_STATE_NULL);
|
|
g_object_set(G_OBJECT(gst_player), "uri", uri, NULL);
|
|
g_free(uri);
|
|
|
|
set_markup(o_album, "x-large", "From: " + track->album()->name());
|
|
set_markup(o_artist, "x-large", "By: " + track->artist()->name());
|
|
set_markup(o_title, "xx-large", track->name());
|
|
o_duration->set_text(track->length_str());
|
|
|
|
on_track_loaded(track);
|
|
}
|
|
|
|
void play()
|
|
{
|
|
if (gst_change_state(GST_STATE_PLAYING)) {
|
|
o_play->hide();
|
|
o_pause->show();
|
|
}
|
|
}
|
|
|
|
void pause()
|
|
{
|
|
if (gst_change_state(GST_STATE_PAUSED)) {
|
|
o_play->show();
|
|
o_pause->hide();
|
|
}
|
|
}
|
|
|
|
bool is_playing()
|
|
{
|
|
GstState state;
|
|
gst_element_get_state(gst_player,
|
|
&state,
|
|
NULL,
|
|
GST_CLOCK_TIME_NONE);
|
|
return state == GST_STATE_PLAYING;
|
|
}
|
|
|
|
void seek_to(long offset)
|
|
{
|
|
gst_element_seek_simple(gst_player,
|
|
GST_FORMAT_TIME,
|
|
GST_SEEK_FLAG_FLUSH,
|
|
offset);
|
|
}
|
|
|
|
long position()
|
|
{
|
|
long position;
|
|
if (gst_element_query_position(gst_player,
|
|
GST_FORMAT_TIME,
|
|
&position))
|
|
return position;
|
|
return 0;
|
|
}
|
|
|
|
long duration()
|
|
{
|
|
long duration;
|
|
if (gst_element_query_duration(gst_player,
|
|
GST_FORMAT_TIME,
|
|
&duration))
|
|
return duration;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
static GSTDriver *gst_driver;
|
|
|
|
|
|
static void parse_gst_error(GstMessage *error)
|
|
{
|
|
GError *err;
|
|
Track *track = audio :: current_track();
|
|
|
|
gst_message_parse_error(error, &err, NULL);
|
|
|
|
if (track)
|
|
g_print("Error playing file: %s\n", track->path().c_str());
|
|
g_print("Error: %s\n", err->message);
|
|
g_error_free(err);
|
|
}
|
|
|
|
static gboolean on_gst_message(GstBus *bus, GstMessage *message, gpointer data)
|
|
{
|
|
switch (GST_MESSAGE_TYPE(message)) {
|
|
case GST_MESSAGE_ERROR:
|
|
parse_gst_error(message);
|
|
audio :: next();
|
|
break;
|
|
case GST_MESSAGE_EOS:
|
|
gst_driver->eos();
|
|
o_count->set_value(audio :: pause_count());
|
|
o_enabled->set_active(audio :: pause_enabled());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void on_next()
|
|
{
|
|
audio :: next();
|
|
audio :: play();
|
|
}
|
|
|
|
static bool on_seek(Gtk::ScrollType type, double value)
|
|
{
|
|
audio :: seek_to(value);
|
|
return true;
|
|
}
|
|
|
|
static void on_pause_count()
|
|
{
|
|
o_enabled->set_active(true);
|
|
}
|
|
|
|
static void on_pause_enabled()
|
|
{
|
|
audio :: pause_after(o_enabled->get_active(), o_count->get_value());
|
|
}
|
|
|
|
static bool on_timeout()
|
|
{
|
|
o_position->set_text(audio :: position_str());
|
|
o_progress->set_upper(audio :: duration());
|
|
o_progress->set_value(audio :: position());
|
|
return true;
|
|
}
|
|
|
|
void on_toggle()
|
|
{
|
|
if (gst_driver->is_playing())
|
|
audio :: pause();
|
|
else
|
|
audio :: play();
|
|
}
|
|
|
|
|
|
void init_gst(int *argc, char ***argv)
|
|
{
|
|
gst_init(argc, argv);
|
|
|
|
gst_player = gst_element_factory_make("playbin", "ocarina_player");
|
|
gst_bus = gst_pipeline_get_bus(GST_PIPELINE(gst_player));
|
|
gst_driver = new GSTDriver();
|
|
|
|
o_next = lib :: get_widget<Gtk::Button>("o_next");
|
|
o_pause = lib :: get_widget<Gtk::Button>("o_pause");
|
|
o_play = lib :: get_widget<Gtk::Button>("o_play");
|
|
o_prev = lib :: get_widget<Gtk::Button>("o_prev");
|
|
o_seek = lib :: get_widget<Gtk::Scale>("o_seek");
|
|
o_stop = lib :: get_widget<Gtk::Button>("o_stop");
|
|
|
|
o_count = lib :: get_widget<Gtk::SpinButton>("o_pause_count");
|
|
o_enabled = lib :: get_widget<Gtk::CheckButton>("o_pause_enabled");
|
|
|
|
o_album = lib :: get_widget<Gtk::Label>("o_album");
|
|
o_artist = lib :: get_widget<Gtk::Label>("o_artist");
|
|
o_duration = lib :: get_widget<Gtk::Label>("o_duration");
|
|
o_position = lib :: get_widget<Gtk::Label>("o_position");
|
|
o_title = lib :: get_widget<Gtk::Label>("o_title");
|
|
o_progress = lib :: get_object<Gtk::Adjustment>("o_progress");
|
|
|
|
o_next->signal_clicked().connect(sigc::ptr_fun(on_next));
|
|
o_pause->signal_clicked().connect(sigc::ptr_fun(audio :: pause));
|
|
o_play->signal_clicked().connect(sigc::ptr_fun(audio :: play));
|
|
o_prev->signal_clicked().connect(sigc::ptr_fun(audio :: prev));
|
|
o_seek->signal_change_value().connect(sigc::ptr_fun(on_seek));
|
|
o_stop->signal_clicked().connect(sigc::ptr_fun(audio :: stop));
|
|
|
|
o_count->signal_changed().connect(sigc::ptr_fun(on_pause_count));
|
|
o_enabled->signal_toggled().connect(sigc::ptr_fun(on_pause_enabled));
|
|
|
|
gst_bus_add_watch(gst_bus, on_gst_message, NULL);
|
|
lib :: schedule(on_timeout, 500);
|
|
}
|
|
|
|
void quit_gst()
|
|
{
|
|
delete gst_driver;
|
|
gst_change_state(GST_STATE_NULL);
|
|
gst_deinit();
|
|
}
|