/* * Copyright 2013 (c) Anna Schumaker. */ #include #include #include #include #include #include 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; }