ocarina/lib/audio.cpp

289 lines
5.4 KiB
C++
Raw Normal View History

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <audio.h>
#include <callback.h>
#include <deck.h>
#include <library.h>
#include <sstream>
#include <string.h>
static GstElement *ocarina_player;
static bool player_playing = false;
static bool track_loaded = false;
static unsigned int cur_trackid = 0;
static bool o_pause_enabled = false;
static unsigned int o_pause_count = 0;
static bool o_should_pause = false;
static Playqueue o_recently_played(PQ_ENABLED);
static void parse_error(GstMessage *error)
{
GError *err;
gchar *debug;
library :: Song song;
library :: lookup(cur_trackid, &song);
gst_message_parse_error(error, &err, &debug);
g_print("Error playing file: %s\n", song.track->primary_key().c_str());
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;
get_callbacks()->on_pause();
} else
o_pause_count--;
get_callbacks()->on_pause_count_changed(o_pause_enabled, o_pause_count);
}
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
{
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
parse_error(message);
audio :: next();
audio :: play();
break;
case GST_MESSAGE_EOS:
handle_pause_count();
library :: track_played(cur_trackid);
audio :: next();
audio :: seek_to(0);
default:
break;
}
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:
player_playing = (state == GST_STATE_PLAYING);
return true;
default:
player_playing = false;
return false;
}
}
static bool load_song(library :: Song &song)
{
GstState state;
gchar *uri;
std::string filepath = song.library->root_path + "/" + song.track->filepath;
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);
}
change_state(GST_STATE_NULL);
uri = gst_filename_to_uri(filepath.c_str(), NULL);
g_object_set(G_OBJECT(ocarina_player), "uri", uri, NULL);
g_free(uri);
get_callbacks()->on_track_loaded(song);
return change_state(state);
}
void audio :: init(int *argc, char ***argv)
{
GstBus *bus;
o_recently_played.set_flag(PQ_REPEAT);
o_recently_played.set_flag(PQ_NEVER_SORT);
o_recently_played.set_flag(PQ_DISABLE_CHANGED_SIZE);
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);
}
void audio :: quit()
{
change_state(GST_STATE_NULL);
gst_deinit();
}
void audio :: play()
{
if (track_loaded == false)
return;
if (change_state(GST_STATE_PLAYING))
get_callbacks()->on_play();
}
void audio :: pause()
{
if (track_loaded == false)
return;
if (change_state(GST_STATE_PAUSED))
get_callbacks()->on_pause();
}
void audio :: toggle_play()
{
if (player_playing == true)
pause();
else
play();
}
void audio :: stop()
{
pause();
seek_to(0);
}
void audio :: seek_to(long pos)
{
bool ret;
if (track_loaded == false)
return;
ret = gst_element_seek_simple(GST_ELEMENT(ocarina_player),
GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
pos);
if (!ret)
throw -E_AUDIO;
}
void audio :: next()
{
library :: Song song;
unsigned int id;
track_loaded = false;
id = deck :: next();
library :: lookup(id, &song);
load_song(song);
track_loaded = true;
cur_trackid = id;
o_recently_played.del_track(id);
o_recently_played.add_front(id);
o_recently_played.set_cur(0);
}
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;
}
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.del_track(track_id);
o_recently_played.add_front(track_id);
o_recently_played.set_cur(0);
}
unsigned int audio :: current_trackid()
{
if (track_loaded == false)
throw -E_EXIST;
return cur_trackid;
}
Playqueue *audio :: get_recent_pq()
{
return &o_recently_played;
}
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;
}
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();
}
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;
}
void audio :: pause_after(bool enabled, unsigned int n)
{
if (n > o_pause_count)
enabled = true;
o_pause_enabled = enabled;
o_pause_count = n;
get_callbacks()->on_pause_count_changed(enabled, n);
}
bool audio :: pause_enabled()
{
return o_pause_enabled;
}
unsigned int audio :: pause_count()
{
return o_pause_count;
}