252 lines
4.5 KiB
C++
252 lines
4.5 KiB
C++
/**
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
*/
|
|
#include <core/audio.h>
|
|
extern "C" {
|
|
#include <core/collection.h>
|
|
#include <core/history.h>
|
|
#include <core/tempq.h>
|
|
#include <core/string.h>
|
|
}
|
|
|
|
|
|
static struct file audio_file;
|
|
static struct track *audio_track = NULL;
|
|
static GstElement *audio_player = NULL;
|
|
static struct audio_ops *audio_ops = NULL;
|
|
|
|
static bool _pause_enabled = false;
|
|
static unsigned int _pause_count = 0;
|
|
|
|
static AudioDriver *cur_driver = NULL;
|
|
|
|
|
|
static void __audio_save()
|
|
{
|
|
file_open(&audio_file, OPEN_WRITE);
|
|
file_writef(&audio_file, "%u\n", audio_track->tr_dbe.dbe_index);
|
|
file_close(&audio_file);
|
|
}
|
|
|
|
static GstState __audio_cur_state()
|
|
{
|
|
GstState cur;
|
|
gst_element_get_state(audio_player, &cur, NULL, GST_CLOCK_TIME_NONE);
|
|
return cur;
|
|
}
|
|
|
|
static bool __audio_change_state(GstState state)
|
|
{
|
|
GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
|
|
if (__audio_cur_state() != state)
|
|
ret = gst_element_set_state(audio_player, state);
|
|
return ret != GST_STATE_CHANGE_FAILURE;
|
|
}
|
|
|
|
static bool __audio_load(struct track *track, GstState state)
|
|
{
|
|
gchar *path, *uri;
|
|
|
|
if (!track)
|
|
return false;
|
|
|
|
path = track_path(track);
|
|
uri = gst_filename_to_uri(path, NULL);
|
|
audio_track = track;
|
|
|
|
gst_element_set_state(audio_player, GST_STATE_NULL);
|
|
g_object_set(G_OBJECT(audio_player), "uri", uri, NULL);
|
|
__audio_change_state(state);
|
|
audio_ops->on_load(track, state);
|
|
|
|
__audio_save();
|
|
g_free(uri);
|
|
g_free(path);
|
|
return true;
|
|
}
|
|
|
|
static GstState continue_playback()
|
|
{
|
|
GstState ret = GST_STATE_PLAYING;
|
|
|
|
if (_pause_enabled) {
|
|
if (_pause_count == 0) {
|
|
ret = GST_STATE_PAUSED;
|
|
_pause_enabled = false;
|
|
} else
|
|
_pause_count--;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
AudioDriver :: AudioDriver()
|
|
{
|
|
cur_driver = this;
|
|
}
|
|
|
|
AudioDriver :: ~AudioDriver()
|
|
{
|
|
cur_driver = NULL;
|
|
}
|
|
|
|
void AudioDriver :: eos()
|
|
{
|
|
struct track *track;
|
|
|
|
if (audio_track) {
|
|
track_played(audio_track);
|
|
queue_updated(collection_get_queue(), audio_track);
|
|
}
|
|
|
|
track = tempq_next();
|
|
if (!track)
|
|
track = queue_next(collection_get_queue());
|
|
__audio_load(track, continue_playback());
|
|
}
|
|
|
|
|
|
|
|
void audio_init(int *argc, char ***argv, struct audio_ops *ops)
|
|
{
|
|
unsigned int track;
|
|
|
|
gst_init(argc, argv);
|
|
audio_player = gst_element_factory_make("playbin", "ocarina_player");
|
|
audio_ops = ops;
|
|
|
|
file_init(&audio_file, "cur_track", 0);
|
|
if (file_open(&audio_file, OPEN_READ)) {
|
|
file_readf(&audio_file, "%u", &track);
|
|
file_close(&audio_file);
|
|
audio_load(track_get(track));
|
|
}
|
|
}
|
|
|
|
void audio_deinit()
|
|
{
|
|
gst_element_set_state(audio_player, GST_STATE_NULL);
|
|
gst_object_unref(audio_player);
|
|
|
|
audio_player = NULL;
|
|
audio_track = NULL;
|
|
|
|
gst_deinit();
|
|
}
|
|
|
|
bool audio_load(struct track *track)
|
|
{
|
|
if (track == audio_track)
|
|
return false;
|
|
if (__audio_load(track, cur_driver->is_playing() ? GST_STATE_PLAYING :
|
|
GST_STATE_PAUSED)) {
|
|
history_add(audio_track);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool audio_play()
|
|
{
|
|
if (!audio_track)
|
|
return false;
|
|
return __audio_change_state(GST_STATE_PLAYING);
|
|
}
|
|
|
|
bool audio_pause()
|
|
{
|
|
if (!audio_track)
|
|
return false;
|
|
return __audio_change_state(GST_STATE_PAUSED);
|
|
}
|
|
|
|
bool audio_seek(gint64 offset)
|
|
{
|
|
if (!audio_track)
|
|
return false;
|
|
return gst_element_seek_simple(audio_player,
|
|
GST_FORMAT_TIME,
|
|
GST_SEEK_FLAG_FLUSH,
|
|
offset);
|
|
}
|
|
|
|
void audio :: stop()
|
|
{
|
|
audio_pause();
|
|
audio_seek(0);
|
|
}
|
|
|
|
gint64 audio_position()
|
|
{
|
|
gint64 position;
|
|
if (gst_element_query_position(audio_player,
|
|
GST_FORMAT_TIME,
|
|
&position))
|
|
return position;
|
|
return 0;
|
|
}
|
|
|
|
int64_t audio_duration()
|
|
{
|
|
gint64 duration;
|
|
if (gst_element_query_duration(audio_player,
|
|
GST_FORMAT_TIME,
|
|
&duration))
|
|
return duration;
|
|
if (audio_track)
|
|
return audio_track->tr_length * GST_SECOND;
|
|
return 0;
|
|
}
|
|
|
|
void audio :: next()
|
|
{
|
|
struct track *track = tempq_next();
|
|
if (!track)
|
|
track = queue_next(collection_get_queue());
|
|
if (__audio_load(track, cur_driver->is_playing() ? GST_STATE_PLAYING :
|
|
GST_STATE_PAUSED))
|
|
history_add(audio_track);
|
|
}
|
|
|
|
void audio :: prev()
|
|
{
|
|
__audio_load(history_prev(), cur_driver->is_playing() ?
|
|
GST_STATE_PLAYING : GST_STATE_PAUSED);
|
|
}
|
|
|
|
struct track *audio :: current_track()
|
|
{
|
|
return audio_track;
|
|
}
|
|
|
|
void audio :: pause_after(bool enabled, unsigned int n)
|
|
{
|
|
if (n > _pause_count)
|
|
enabled = true;
|
|
|
|
_pause_enabled = enabled;
|
|
_pause_count = n;
|
|
}
|
|
|
|
bool audio :: pause_enabled()
|
|
{
|
|
return _pause_enabled;
|
|
}
|
|
|
|
unsigned int audio :: pause_count()
|
|
{
|
|
return _pause_count;
|
|
}
|
|
|
|
AudioDriver *audio :: get_driver()
|
|
{
|
|
return cur_driver;
|
|
}
|
|
|
|
GstElement *audio_get_player()
|
|
{
|
|
return audio_player;
|
|
}
|