2013-12-24 20:17:44 -05:00
|
|
|
/*
|
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
|
|
|
#include <audio.h>
|
2014-01-22 22:31:42 -05:00
|
|
|
#include <callback.h>
|
2013-12-24 20:17:44 -05:00
|
|
|
#include <deck.h>
|
|
|
|
#include <library.h>
|
|
|
|
|
2014-01-22 22:31:42 -05:00
|
|
|
#include <sstream>
|
2013-12-24 20:17:44 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
static GstElement *ocarina_player;
|
2013-12-25 14:35:33 -05:00
|
|
|
|
2013-12-24 20:17:44 -05:00
|
|
|
static bool track_loaded = false;
|
2013-12-24 22:07:23 -05:00
|
|
|
static unsigned int cur_trackid = 0;
|
2013-12-24 20:17:44 -05:00
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
static bool o_pause_enabled = false;
|
|
|
|
static unsigned int o_pause_count = 0;
|
|
|
|
static bool o_should_pause = false;
|
|
|
|
|
2014-01-04 13:57:51 -05:00
|
|
|
static Playqueue o_recently_played(PQ_ENABLED);
|
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
static void parse_error(GstMessage *error)
|
|
|
|
{
|
|
|
|
GError *err;
|
|
|
|
gchar *debug;
|
2014-01-29 22:45:01 -05:00
|
|
|
library :: Song song;
|
2013-12-25 14:35:33 -05:00
|
|
|
|
2014-01-29 22:45:01 -05:00
|
|
|
library :: lookup(cur_trackid, &song);
|
2013-12-25 14:35:33 -05:00
|
|
|
gst_message_parse_error(error, &err, &debug);
|
2014-01-29 22:45:01 -05:00
|
|
|
g_print("Error playing file: %s\n", song.track->primary_key.c_str());
|
2013-12-25 14:35:33 -05:00
|
|
|
g_print("Error: %s\n", err->message);
|
|
|
|
g_error_free(err);
|
|
|
|
g_free(debug);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_pause_count()
|
|
|
|
{
|
|
|
|
if (o_pause_enabled == false)
|
|
|
|
return;
|
|
|
|
else if (o_pause_count == 0) {
|
|
|
|
o_should_pause = true;
|
|
|
|
o_pause_enabled = false;
|
2014-01-24 16:22:55 -05:00
|
|
|
get_callbacks()->on_pause();
|
2013-12-25 14:35:33 -05:00
|
|
|
} else
|
|
|
|
o_pause_count--;
|
2014-01-24 09:20:08 -05:00
|
|
|
get_callbacks()->on_pause_count_changed(o_pause_enabled, o_pause_count);
|
2013-12-25 14:35:33 -05:00
|
|
|
}
|
|
|
|
|
2013-12-24 20:17:44 -05:00
|
|
|
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
|
|
|
|
{
|
2013-12-25 14:35:33 -05:00
|
|
|
switch (GST_MESSAGE_TYPE(message)) {
|
|
|
|
case GST_MESSAGE_ERROR:
|
|
|
|
parse_error(message);
|
|
|
|
audio :: next();
|
2014-01-29 22:45:01 -05:00
|
|
|
audio :: play();
|
2013-12-25 14:35:33 -05:00
|
|
|
break;
|
|
|
|
case GST_MESSAGE_EOS:
|
|
|
|
handle_pause_count();
|
2014-01-29 22:45:01 -05:00
|
|
|
library :: track_played(cur_trackid);
|
2013-12-25 14:35:33 -05:00
|
|
|
audio :: next();
|
2014-01-24 16:22:55 -05:00
|
|
|
audio :: seek_to(0);
|
2013-12-25 14:35:33 -05:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-12-24 20:17:44 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool change_state(GstState state)
|
|
|
|
{
|
|
|
|
GstStateChangeReturn ret;
|
|
|
|
|
|
|
|
ret = gst_element_set_state(GST_ELEMENT(ocarina_player), state);
|
|
|
|
switch (ret) {
|
|
|
|
case GST_STATE_CHANGE_SUCCESS:
|
|
|
|
case GST_STATE_CHANGE_ASYNC:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool load_song(library :: Song &song)
|
|
|
|
{
|
|
|
|
GstState state;
|
2014-01-29 23:13:51 -05:00
|
|
|
gchar *escaped, *uri;
|
2013-12-24 20:17:44 -05:00
|
|
|
std::string filepath = song.library->root_path + "/" + song.track->filepath;
|
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
if (o_should_pause == true) {
|
|
|
|
state = GST_STATE_PAUSED;
|
|
|
|
o_should_pause = false;
|
|
|
|
} else {
|
|
|
|
gst_element_get_state(GST_ELEMENT(ocarina_player), &state,
|
|
|
|
NULL, GST_CLOCK_TIME_NONE);
|
|
|
|
}
|
2013-12-24 20:17:44 -05:00
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
change_state(GST_STATE_NULL);
|
2014-01-29 23:13:51 -05:00
|
|
|
escaped = g_markup_escape_text(filepath.c_str(), filepath.size());
|
|
|
|
uri = gst_filename_to_uri(escaped, NULL);
|
|
|
|
g_object_set(G_OBJECT(ocarina_player), "uri", uri, NULL);
|
2013-12-24 20:17:44 -05:00
|
|
|
g_free(escaped);
|
2014-01-29 23:13:51 -05:00
|
|
|
g_free(uri);
|
2013-12-24 20:17:44 -05:00
|
|
|
|
2014-01-22 22:31:42 -05:00
|
|
|
get_callbacks()->on_track_loaded(song);
|
2013-12-24 20:17:44 -05:00
|
|
|
return change_state(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio :: init(int *argc, char ***argv)
|
|
|
|
{
|
|
|
|
GstBus *bus;
|
|
|
|
|
2014-01-04 13:57:51 -05:00
|
|
|
o_recently_played.set_flag(PQ_REPEAT);
|
2014-01-26 14:49:07 -05:00
|
|
|
o_recently_played.set_flag(PQ_NEVER_SORT);
|
2014-01-25 13:21:57 -05:00
|
|
|
o_recently_played.set_flag(PQ_DISABLE_CHANGED_SIZE);
|
2013-12-24 20:17:44 -05:00
|
|
|
gst_init(argc, argv);
|
|
|
|
|
|
|
|
ocarina_player = gst_element_factory_make("playbin", "ocarina_player");
|
|
|
|
bus = gst_pipeline_get_bus(GST_PIPELINE(ocarina_player));
|
|
|
|
|
|
|
|
gst_bus_add_watch(bus, on_message, NULL);
|
|
|
|
}
|
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
void audio :: quit()
|
|
|
|
{
|
2014-01-22 19:27:36 -05:00
|
|
|
change_state(GST_STATE_NULL);
|
2013-12-25 14:35:33 -05:00
|
|
|
gst_deinit();
|
|
|
|
}
|
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
void audio :: play()
|
2013-12-24 20:17:44 -05:00
|
|
|
{
|
|
|
|
if (track_loaded == false)
|
2014-01-04 13:09:44 -05:00
|
|
|
return;
|
2014-01-22 22:31:42 -05:00
|
|
|
if (change_state(GST_STATE_PLAYING))
|
|
|
|
get_callbacks()->on_play();
|
2013-12-24 20:17:44 -05:00
|
|
|
}
|
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
void audio :: pause()
|
2013-12-24 20:17:44 -05:00
|
|
|
{
|
|
|
|
if (track_loaded == false)
|
2014-01-04 13:09:44 -05:00
|
|
|
return;
|
2014-01-22 22:31:42 -05:00
|
|
|
if (change_state(GST_STATE_PAUSED))
|
|
|
|
get_callbacks()->on_pause();
|
2013-12-24 20:17:44 -05:00
|
|
|
}
|
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
void audio :: stop()
|
2013-12-24 20:17:44 -05:00
|
|
|
{
|
2014-01-04 13:09:44 -05:00
|
|
|
pause();
|
|
|
|
seek_to(0);
|
2013-12-24 22:07:23 -05:00
|
|
|
}
|
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
void audio :: seek_to(long pos)
|
2013-12-24 22:07:23 -05:00
|
|
|
{
|
|
|
|
bool ret;
|
2013-12-24 20:17:44 -05:00
|
|
|
if (track_loaded == false)
|
2014-01-04 13:09:44 -05:00
|
|
|
return;
|
2013-12-24 22:07:23 -05:00
|
|
|
ret = gst_element_seek_simple(GST_ELEMENT(ocarina_player),
|
2013-12-24 20:17:44 -05:00
|
|
|
GST_FORMAT_TIME,
|
|
|
|
GST_SEEK_FLAG_FLUSH,
|
|
|
|
pos);
|
2014-01-04 13:09:44 -05:00
|
|
|
if (!ret)
|
|
|
|
throw -E_AUDIO;
|
2013-12-24 20:17:44 -05:00
|
|
|
}
|
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
void audio :: next()
|
2013-12-24 20:17:44 -05:00
|
|
|
{
|
|
|
|
library :: Song song;
|
2014-01-04 13:09:44 -05:00
|
|
|
unsigned int id;
|
2013-12-24 22:07:23 -05:00
|
|
|
|
2014-01-04 13:09:44 -05:00
|
|
|
track_loaded = false;
|
|
|
|
id = deck :: next();
|
|
|
|
library :: lookup(id, &song);
|
|
|
|
load_song(song);
|
|
|
|
track_loaded = true;
|
2014-01-04 13:57:51 -05:00
|
|
|
|
|
|
|
cur_trackid = id;
|
|
|
|
o_recently_played.add_front(id);
|
2014-01-29 22:11:03 -05:00
|
|
|
o_recently_played.set_cur(0);
|
2014-01-04 13:57:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void audio :: previous()
|
|
|
|
{
|
|
|
|
library :: Song song;
|
|
|
|
unsigned int id;
|
|
|
|
|
|
|
|
id = o_recently_played.next();
|
|
|
|
if (id == cur_trackid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
library :: lookup(id, &song);
|
|
|
|
load_song(song);
|
|
|
|
cur_trackid = id;
|
2013-12-24 20:17:44 -05:00
|
|
|
}
|
2013-12-24 22:07:23 -05:00
|
|
|
|
2014-01-26 12:42:13 -05:00
|
|
|
void audio :: load_trackid(unsigned int track_id)
|
|
|
|
{
|
|
|
|
library :: Song song;
|
|
|
|
|
|
|
|
if (track_id == cur_trackid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
track_loaded = false;
|
|
|
|
library :: lookup(track_id, &song);
|
|
|
|
load_song(song);
|
|
|
|
track_loaded = true;
|
|
|
|
|
|
|
|
cur_trackid = track_id;
|
|
|
|
o_recently_played.add_front(track_id);
|
2014-01-29 22:11:03 -05:00
|
|
|
o_recently_played.set_cur(0);
|
2014-01-26 12:42:13 -05:00
|
|
|
}
|
|
|
|
|
2013-12-24 22:07:23 -05:00
|
|
|
unsigned int audio :: current_trackid()
|
|
|
|
{
|
|
|
|
if (track_loaded == false)
|
2014-01-04 13:09:44 -05:00
|
|
|
throw -E_EXIST;
|
2013-12-24 22:07:23 -05:00
|
|
|
return cur_trackid;
|
|
|
|
}
|
|
|
|
|
2014-01-24 20:30:25 -05:00
|
|
|
Playqueue *audio :: get_recent_pq()
|
|
|
|
{
|
|
|
|
return &o_recently_played;
|
|
|
|
}
|
|
|
|
|
2013-12-24 22:07:23 -05:00
|
|
|
long audio :: position()
|
|
|
|
{
|
|
|
|
long position;
|
|
|
|
|
|
|
|
if (track_loaded == false)
|
|
|
|
return 0;
|
|
|
|
if (!gst_element_query_position(GST_ELEMENT(ocarina_player), GST_FORMAT_TIME, &position))
|
|
|
|
return 0;
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
2014-01-22 22:31:42 -05:00
|
|
|
std::string audio :: position_str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
long cur = position() / GST_SECOND;
|
|
|
|
unsigned int minutes = cur / 60;
|
|
|
|
unsigned int seconds = cur % 60;
|
|
|
|
|
|
|
|
ss << minutes << ":";
|
|
|
|
if (seconds < 10)
|
|
|
|
ss << "0";
|
|
|
|
ss << seconds;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2013-12-24 22:07:23 -05:00
|
|
|
long audio :: duration()
|
|
|
|
{
|
|
|
|
long duration;
|
|
|
|
|
|
|
|
if (track_loaded == false)
|
|
|
|
return 0;
|
|
|
|
if (!gst_element_query_duration(ocarina_player, GST_FORMAT_TIME, &duration))
|
|
|
|
return 0;
|
|
|
|
return duration;
|
|
|
|
}
|
2013-12-25 14:35:33 -05:00
|
|
|
|
|
|
|
void audio :: pause_after(bool enabled, unsigned int n)
|
|
|
|
{
|
2014-01-24 09:20:08 -05:00
|
|
|
if (n > o_pause_count)
|
|
|
|
enabled = true;
|
|
|
|
|
2013-12-25 14:35:33 -05:00
|
|
|
o_pause_enabled = enabled;
|
|
|
|
o_pause_count = n;
|
2014-01-24 09:20:08 -05:00
|
|
|
get_callbacks()->on_pause_count_changed(enabled, n);
|
2013-12-25 14:35:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool audio :: pause_enabled()
|
|
|
|
{
|
|
|
|
return o_pause_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int audio :: pause_count()
|
|
|
|
{
|
|
|
|
return o_pause_count;
|
|
|
|
}
|