core/audio: Move audio_load() out of the audio namespace

And add the on_load() audio operation.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-12-15 10:23:15 -05:00
parent e0c89556ed
commit e5c3d8f02e
9 changed files with 138 additions and 98 deletions

View File

@ -11,43 +11,52 @@ extern "C" {
static struct file audio_file; static struct file audio_file;
static GstElement *audio_player = NULL; static struct track *audio_track = NULL;
static GstElement *audio_player = NULL;
static struct audio_ops *audio_ops = NULL;
static bool _pause_enabled = false; static bool _pause_enabled = false;
static unsigned int _pause_count = 0; static unsigned int _pause_count = 0;
static struct track *cur_track = NULL;
static AudioDriver *cur_driver = NULL; static AudioDriver *cur_driver = NULL;
static void save_state() static void __audio_save()
{ {
file_open(&audio_file, OPEN_WRITE); file_open(&audio_file, OPEN_WRITE);
file_writef(&audio_file, "%u\n", cur_track->tr_dbe.dbe_index); file_writef(&audio_file, "%u\n", audio_track->tr_dbe.dbe_index);
file_close(&audio_file); file_close(&audio_file);
} }
static void _load_track(struct track *track, bool start_playback) static bool __audio_load(struct track *track, GstState state)
{ {
cur_track = track; gchar *path, *uri;
if (!track)
return;
cur_driver->load(track); if (!track)
if (start_playback) return false;
audio :: play();
else path = track_path(track);
audio :: pause(); uri = gst_filename_to_uri(path, NULL);
save_state(); audio_track = track;
gst_element_set_state(audio_player, GST_STATE_NULL);
g_object_set(G_OBJECT(audio_player), "uri", uri, NULL);
gst_element_set_state(audio_player, state);
audio_ops->on_load(track, state);
__audio_save();
g_free(uri);
g_free(path);
return true;
} }
static bool continue_playback() static GstState continue_playback()
{ {
bool ret = true; GstState ret = GST_STATE_PLAYING;
if (_pause_enabled) { if (_pause_enabled) {
if (_pause_count == 0) { if (_pause_count == 0) {
ret = false; ret = GST_STATE_PAUSED;
_pause_enabled = false; _pause_enabled = false;
} else } else
_pause_count--; _pause_count--;
@ -72,31 +81,32 @@ void AudioDriver :: eos()
{ {
struct track *track; struct track *track;
if (cur_track) { if (audio_track) {
track_played(cur_track); track_played(audio_track);
queue_updated(collection_get_queue(), cur_track); queue_updated(collection_get_queue(), audio_track);
} }
track = tempq_next(); track = tempq_next();
if (!track) if (!track)
track = queue_next(collection_get_queue()); track = queue_next(collection_get_queue());
_load_track(track, continue_playback()); __audio_load(track, continue_playback());
} }
void audio_init(int *argc, char ***argv) void audio_init(int *argc, char ***argv, struct audio_ops *ops)
{ {
unsigned int track; unsigned int track;
gst_init(argc, argv); gst_init(argc, argv);
audio_player = gst_element_factory_make("playbin", "ocarina_player"); audio_player = gst_element_factory_make("playbin", "ocarina_player");
audio_ops = ops;
file_init(&audio_file, "cur_track", 0); file_init(&audio_file, "cur_track", 0);
if (file_open(&audio_file, OPEN_READ)) { if (file_open(&audio_file, OPEN_READ)) {
file_readf(&audio_file, "%u", &track); file_readf(&audio_file, "%u", &track);
file_close(&audio_file); file_close(&audio_file);
audio :: load_track(track_get(track)); audio_load(track_get(track));
} }
} }
@ -104,26 +114,40 @@ void audio_deinit()
{ {
gst_element_set_state(audio_player, GST_STATE_NULL); gst_element_set_state(audio_player, GST_STATE_NULL);
gst_object_unref(audio_player); gst_object_unref(audio_player);
audio_player = NULL; audio_player = NULL;
audio_track = NULL;
gst_deinit(); 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;
}
void audio :: play() void audio :: play()
{ {
if (cur_track) if (audio_track)
cur_driver->play(); cur_driver->play();
} }
void audio :: pause() void audio :: pause()
{ {
if (cur_track) if (audio_track)
cur_driver->pause(); cur_driver->pause();
} }
void audio :: seek_to(int64_t pos) void audio :: seek_to(int64_t pos)
{ {
if (cur_track) if (audio_track)
cur_driver->seek_to(pos); cur_driver->seek_to(pos);
} }
@ -135,14 +159,14 @@ void audio :: stop()
int64_t audio :: position() int64_t audio :: position()
{ {
if (cur_track) if (audio_track)
return cur_driver->position(); return cur_driver->position();
return 0; return 0;
} }
int64_t audio :: duration() int64_t audio :: duration()
{ {
if (cur_track) if (audio_track)
return cur_driver->duration(); return cur_driver->duration();
return 0; return 0;
} }
@ -152,28 +176,20 @@ void audio :: next()
struct track *track = tempq_next(); struct track *track = tempq_next();
if (!track) if (!track)
track = queue_next(collection_get_queue()); track = queue_next(collection_get_queue());
_load_track(track, cur_driver->is_playing()); if (__audio_load(track, cur_driver->is_playing() ? GST_STATE_PLAYING :
if (cur_track) GST_STATE_PAUSED))
history_add(cur_track); history_add(audio_track);
} }
void audio :: prev() void audio :: prev()
{ {
_load_track(history_prev(), cur_driver->is_playing()); __audio_load(history_prev(), cur_driver->is_playing() ?
} GST_STATE_PLAYING : GST_STATE_PAUSED);
void audio :: load_track(struct track *track)
{
if (!track || track == cur_track)
return;
_load_track(track, cur_driver->is_playing());
history_add(cur_track);
} }
struct track *audio :: current_track() struct track *audio :: current_track()
{ {
return cur_track; return audio_track;
} }
void audio :: pause_after(bool enabled, unsigned int n) void audio :: pause_after(bool enabled, unsigned int n)

View File

@ -21,7 +21,7 @@ void core :: init(int *argc, char ***argv, struct core_init_data *init)
collection_init(init->collection_ops); collection_init(init->collection_ops);
history_init(init->history_ops); history_init(init->history_ops);
tempq_init(init->tempq_ops); tempq_init(init->tempq_ops);
audio_init(argc, argv); audio_init(argc, argv, init->audio_ops);
} }
void core :: deinit() void core :: deinit()

View File

@ -53,38 +53,29 @@ static void set_markup(Gtk::Label *label, const std::string &size,
Glib::Markup::escape_text(text) + "</span>"); Glib::Markup::escape_text(text) + "</span>");
} }
static void on_load(struct track *track, GstState state)
{
gchar *str = g_strdup_printf("From: %s", track->tr_album->al_name);
set_markup(o_album, "x-large", str);
g_free(str);
str = g_strdup_printf("By: %s", track->tr_artist->ar_name);
set_markup(o_artist, "x-large", str);
g_free(str);
set_markup(o_title, "xx-large", track->tr_title);
str = string_sec2str(track->tr_length);
o_duration->set_text(str);
g_free(str);
plist :: track_loaded(track);
}
class GSTDriver : public AudioDriver class GSTDriver : public AudioDriver
{ {
public: public:
void load(struct track *track)
{
gchar *path = track_path(track);
gchar *uri = gst_filename_to_uri(path, NULL);
gchar *len = string_sec2str(track->tr_length);
gchar *str;
gst_change_state(GST_STATE_NULL);
g_object_set(G_OBJECT(audio_get_player()), "uri", uri, NULL);
g_free(uri);
str = g_strdup_printf("From: %s", track->tr_album->al_name);
set_markup(o_album, "x-large", str);
g_free(str);
str = g_strdup_printf("By: %s", track->tr_artist->ar_name);
set_markup(o_artist, "x-large", str);
g_free(str);
set_markup(o_title, "xx-large", track->tr_title);
o_duration->set_text(len);
g_free(path);
g_free(len);
plist :: track_loaded(track);
}
void play() void play()
{ {
if (gst_change_state(GST_STATE_PLAYING)) { if (gst_change_state(GST_STATE_PLAYING)) {
@ -142,6 +133,10 @@ public:
static GSTDriver *gst_driver; static GSTDriver *gst_driver;
struct audio_ops audio_ops = {
on_load,
};
static int parse_gst_error(GstMessage *error) static int parse_gst_error(GstMessage *error)
{ {

View File

@ -18,6 +18,7 @@ struct core_init_data init_data = {
&history_ops, &history_ops,
&playlist_ops, &playlist_ops,
&tempq_ops, &tempq_ops,
&audio_ops,
}; };
namespace gui namespace gui
@ -64,6 +65,7 @@ int main(int argc, char **argv)
gst :: init_pre(); gst :: init_pre();
core :: init(&argc, &argv, &init_data); core :: init(&argc, &argv, &init_data);
gst :: init();
plist :: init(); plist :: init();
manager :: init(); manager :: init();
init_tabs(); init_tabs();

View File

@ -56,7 +56,7 @@ void QueueModel::on_row_changed(unsigned int row)
void QueueModel::on_path_selected(const Gtk::TreePath &path) void QueueModel::on_path_selected(const Gtk::TreePath &path)
{ {
audio :: load_track(track_get(path_to_id(path))); audio_load(track_get(path_to_id(path)));
queue_selected(_queue, path[0]); queue_selected(_queue, path[0]);
audio :: play(); audio :: play();
} }

View File

@ -12,6 +12,12 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
struct audio_ops {
/* Called when a track is loaded. */
void (*on_load)(struct track *, GstState);
};
/** /**
* The audio driver class gives us an interface for using multiple * The audio driver class gives us an interface for using multiple
* audio frameworks for audio playback. * audio frameworks for audio playback.
@ -25,13 +31,6 @@ public:
virtual ~AudioDriver(); /**< AudioDriver destructor. */ virtual ~AudioDriver(); /**< AudioDriver destructor. */
/**
* Loads an audio file for playback.
*
* @param track The Track to load.
*/
virtual void load(struct track *track) = 0;
/** /**
* Called to begin playback on the currently loaded track. * Called to begin playback on the currently loaded track.
*/ */
@ -112,13 +111,6 @@ namespace audio
void next(); /**< Find and load the next track that should be played. */ void next(); /**< Find and load the next track that should be played. */
void prev(); /**< Call the deck :: previous() function and load the result. */ void prev(); /**< Call the deck :: previous() function and load the result. */
/**
* Load a specific track for playback.
*
* @param track The track that should be loaded.
*/
void load_track(struct track *track);
/** /**
* @return A pointer to the currently playing track object. * @return A pointer to the currently playing track object.
*/ */
@ -156,11 +148,14 @@ namespace audio
/* Called to initialize the audio manager. */ /* Called to initialize the audio manager. */
void audio_init(int *, char ***); void audio_init(int *, char ***, struct audio_ops *);
/* Called to deinitialize the audio manager. */ /* Called to deinitialize the audio manager. */
void audio_deinit(); void audio_deinit();
/* Called to load a track for playback. */
bool audio_load(struct track *);
GstElement *audio_get_player(); GstElement *audio_get_player();
#endif /* OCARINA_CORE_AUDIO_H */ #endif /* OCARINA_CORE_AUDIO_H */

View File

@ -12,6 +12,7 @@ struct core_init_data {
struct queue_ops *history_ops; struct queue_ops *history_ops;
struct queue_ops *playlist_ops; struct queue_ops *playlist_ops;
struct queue_ops *tempq_ops; struct queue_ops *tempq_ops;
struct audio_ops *audio_ops;
}; };
/** /**

View File

@ -34,6 +34,7 @@ extern struct queue_ops collection_ops;
extern struct queue_ops history_ops; extern struct queue_ops history_ops;
extern struct queue_ops playlist_ops; extern struct queue_ops playlist_ops;
extern struct queue_ops tempq_ops; extern struct queue_ops tempq_ops;
extern struct audio_ops audio_ops;
void on_pq_created(queue *, unsigned int); void on_pq_created(queue *, unsigned int);
void post_init_queue_tabs(); void post_init_queue_tabs();

View File

@ -4,11 +4,14 @@
#include <core/audio.h> #include <core/audio.h>
extern "C" { extern "C" {
#include <core/collection.h> #include <core/collection.h>
#include <core/history.h>
#include <core/idle.h>
} }
#include <core/core.h> #include <core/core.h>
#include "test.h" #include "test.h"
struct track *TRACK_NULL = NULL; struct track *TRACK_NULL = NULL;
static unsigned int load_count = 0;
class TestDriver : public AudioDriver class TestDriver : public AudioDriver
@ -22,13 +25,6 @@ public:
TestDriver() : playing(false), cur_pos(0), cur_duration(0) {} TestDriver() : playing(false), cur_pos(0), cur_duration(0) {}
~TestDriver() {}; ~TestDriver() {};
void load(struct track *track)
{
cur_file = track_path(track);
playing = false;
cur_pos = 0;
}
void play() { playing = true; } void play() { playing = true; }
void pause() { playing = false; } void pause() { playing = false; }
@ -39,26 +35,59 @@ public:
int64_t duration() { return cur_duration; } int64_t duration() { return cur_duration; }
} driver; } driver;
static void test_audio_load(struct track *track, GstState state)
{
load_count++;
}
static struct audio_ops test_audio_ops = {
test_audio_load,
};
static struct core_init_data test_init_data = { static struct core_init_data test_init_data = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
&test_audio_ops,
}; };
static void test_init() static void test_init()
{ {
test_equal(audio_get_player(), NULL);
test_equal(audio :: current_track(), NULL); test_equal(audio :: current_track(), NULL);
test_equal(audio_get_player(), NULL); test_equal(audio_get_player(), NULL);
core :: init(NULL, NULL, &test_init_data); core :: init(NULL, NULL, &test_init_data);
test_equal(audio_load(NULL), false);
test_equal(audio :: current_track(), NULL);
collection_add("tests/Music/Hyrule Symphony");
while (idle_run_task()) {};
test_equal(audio :: current_track(), NULL); test_equal(audio :: current_track(), NULL);
test_not_equal(audio_get_player(), NULL); test_not_equal(audio_get_player(), NULL);
} }
static void test_playback()
{
test_equal(audio_load(track_get(0)), true);
test_equal(load_count, 1);
test_equal(audio :: current_track(), track_get(0));
test_equal(queue_size(history_get_queue()), 1);
test_equal(audio_load(NULL), false);
test_equal(load_count, 1);
test_equal(audio :: current_track(), track_get(0));
test_equal(queue_size(history_get_queue()), 1);
test_equal(audio_load(track_get(0)), false);
test_equal(load_count, 1);
test_equal(queue_size(history_get_queue()), 1);
}
static void test_deinit() static void test_deinit()
{ {
core :: deinit(); core :: deinit();
@ -107,7 +136,7 @@ void test_init2()
struct track *track; struct track *track;
test_cp_data_dir(); test_cp_data_dir();
audio_init(NULL, NULL); audio_init(NULL, NULL, &test_audio_ops);
track = audio :: current_track(); track = audio :: current_track();
test_equal(track, TRACK_NULL); test_equal(track, TRACK_NULL);
@ -158,17 +187,17 @@ void test_track_controls()
audio :: next(); audio :: next();
test_equal(driver->is_playing(), true); test_equal(driver->is_playing(), true);
audio :: load_track(track); audio_load(track);
test_not_equal(audio :: current_track(), track); test_not_equal(audio :: current_track(), track);
track = track_get(0); track = track_get(0);
audio :: seek_to(4242); audio :: seek_to(4242);
audio :: load_track(track); audio_load(track);
test_equal(driver->is_playing(), true); test_equal(driver->is_playing(), true);
test_equal(audio :: position(), (long)0); test_equal(audio :: position(), (long)0);
audio :: seek_to(4242); audio :: seek_to(4242);
audio :: load_track(track); audio_load(track);
test_equal(driver->is_playing(), true); test_equal(driver->is_playing(), true);
test_equal(audio :: position(), (long)4242); test_equal(audio :: position(), (long)4242);
@ -212,6 +241,7 @@ void test_autopause()
DECLARE_UNIT_TESTS( DECLARE_UNIT_TESTS(
UNIT_TEST("Audio Initialization", test_init), UNIT_TEST("Audio Initialization", test_init),
UNIT_TEST("Audio Playback", test_playback),
UNIT_TEST("Audio Deinitialization", test_deinit), UNIT_TEST("Audio Deinitialization", test_deinit),
UNIT_TEST("Test Audio Pre-Init", test_pre_init), UNIT_TEST("Test Audio Pre-Init", test_pre_init),
UNIT_TEST("Test Audio Init 2", test_init2), UNIT_TEST("Test Audio Init 2", test_init2),