driver: Move Gst code into the GstDriver

This would have to happen eventually.  Might as well do it now!

I also updated the TestDriver test to match the changes I had to make.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2014-05-31 20:52:40 -04:00
parent edc4a2f4ee
commit 1cacbf51e7
6 changed files with 200 additions and 129 deletions

16
DESIGN
View File

@ -1313,11 +1313,12 @@ Audio Driver:
public: public:
Driver(); Driver();
~Driver(); ~Driver();
virtual void init(int *, char ***, void (*)()) = 0; virtual void init(int *, char ***, void (*)(), void (*)()) = 0;
virtual void load(const std::string &) = 0; virtual void load(const std::string &) = 0;
virtual void play() = 0; virtual void play() = 0;
virtual void pause() = 0; virtual void pause() = 0;
virtual void is_playing() = 0;
virtual void seek_to(long) = 0; virtual void seek_to(long) = 0;
virtual long position() = 0; virtual long position() = 0;
@ -1333,18 +1334,25 @@ Audio Driver:
In the GSTDriver case, call gst_deinit() to avoid memory leak In the GSTDriver case, call gst_deinit() to avoid memory leak
false positives. false positives.
void Driver :: init(int argc, char **argv, void (*eos_cb)()); void Driver :: init(int argc, char **argv, void (*eos_cb)(),
void (*error_cb)());
The GSTDriver will use this function to set up the playbin2. The GSTDriver will use this function to set up the playbin2.
When an end-of-stream message is received, call eos_cb(). When an end-of-stream message is received, call eos_cb().
If there is an error, call error_cb();
void Driver :: load(const std::string &file); void Driver :: load(const std::string &file);
Load file for playback, but do not begin playback yet. Load file for playback, but do not begin playback yet.
void Driver :: play(); void Driver :: play();
Start playback. Start playback. Return true if the state change operation
succeeds, false otherwise.
void Driver :: pause(); void Driver :: pause();
Pause playback. Pause playback. Return true if the state change operation
succeeds, false otherwise.
bool Driver :: is_playing();
Return true if the player is currently playing, false otherwise.
void Driver :: seek_to(long pos); void Driver :: seek_to(long pos);
Change playback position in the current track in nanoseconds. Change playback position in the current track in nanoseconds.

View File

@ -7,10 +7,6 @@
#include <error.h> #include <error.h>
#include <queue.h> #include <queue.h>
extern "C" {
#include <gst/gst.h>
}
#include <string> #include <string>
namespace audio namespace audio

View File

@ -7,15 +7,17 @@
class Driver { class Driver {
protected: protected:
void (*on_eos)(); void (*on_eos)();
void (*on_error)();
public: public:
Driver(); Driver();
~Driver(); ~Driver();
virtual void init(int *, char ***, void (*)()) = 0; virtual void init(int *, char ***, void (*)(), void (*)()) = 0;
virtual void load(const std::string &) = 0; virtual void load(const std::string &) = 0;
virtual void play() = 0; virtual bool play() = 0;
virtual void pause() = 0; virtual bool pause() = 0;
virtual bool is_playing() = 0;
virtual void seek_to(long) = 0; virtual void seek_to(long) = 0;
virtual long position() = 0; virtual long position() = 0;
@ -34,38 +36,50 @@ public:
TestDriver(); TestDriver();
~TestDriver(); ~TestDriver();
void init(int *, char ***, void (*)()); void init(int *, char ***, void (*)(), void (*)());
void load(const std::string &); void load(const std::string &);
void play(); bool play();
void pause(); bool pause();
bool is_playing();
void seek_to(long); void seek_to(long);
long position(); long position();
long duration(); long duration();
void eos(); void eos();
void error();
}; };
#else /* CONFIG_TEST */ #else /* !CONFIG_TEST */
#include <gst/gst.h>
class GSTDriver : public Driver class GSTDriver : public Driver
{ {
private:
GstElement *player;
std::string cur_file;
bool change_state(GstState state);
public: public:
GSTDriver(); GSTDriver();
~GSTDriver(); ~GSTDriver();
void init(int *, char ***, void (*)()); void init(int *, char ***, void (*)(), void (*)());
void load(const std::string &); void load(const std::string &);
void play(); bool play();
void pause(); bool pause();
bool is_playing();
void seek_to(long); void seek_to(long);
long position(); long position();
long duration(); long duration();
void on_message(GstMessage *);
}; };
#endif /* CONFIG_TEST */ #endif /* CONFIG_TEST */
namespace driver namespace driver
{ {

View File

@ -4,13 +4,12 @@
#include <audio.h> #include <audio.h>
#include <callback.h> #include <callback.h>
#include <deck.h> #include <deck.h>
#include <driver.h>
#include <library.h> #include <library.h>
#include <sstream> #include <sstream>
#include <string.h> #include <string.h>
static GstElement *ocarina_player;
static bool player_playing = false; static bool player_playing = false;
static bool track_loaded = false; static bool track_loaded = false;
static unsigned int cur_trackid = 0; static unsigned int cur_trackid = 0;
@ -22,19 +21,6 @@ static bool o_should_pause = false;
static File f_cur_track("cur_track", 0); static File f_cur_track("cur_track", 0);
static void parse_error(GstMessage *error)
{
GError *err;
gchar *debug;
Track *track = tagdb :: lookup(cur_trackid);
gst_message_parse_error(error, &err, &debug);
g_print("Error playing file: %s\n", track->path().c_str());
g_print("Error: %s\n", err->message);
g_error_free(err);
g_free(debug);
}
static void handle_pause_count() static void handle_pause_count()
{ {
if (o_pause_enabled == false) if (o_pause_enabled == false)
@ -48,45 +34,24 @@ static void handle_pause_count()
get_callbacks()->on_pause_count_changed(o_pause_enabled, 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) static void on_error()
{
audio :: next();
audio :: play();
}
static void on_eos()
{ {
Track *track; Track *track;
switch (GST_MESSAGE_TYPE(message)) { handle_pause_count();
case GST_MESSAGE_ERROR: track = tagdb :: lookup(cur_trackid);
parse_error(message); if (track) {
audio :: next(); track->played();
audio :: play(); library :: get_queue()->updated(track);
break;
case GST_MESSAGE_EOS:
handle_pause_count();
track = tagdb :: lookup(cur_trackid);
if (track) {
track->played();
library :: get_queue()->updated(track);
}
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;
} }
audio :: next();
audio :: seek_to(0);
} }
static void save_state() static void save_state()
@ -98,37 +63,25 @@ static void save_state()
static bool load_song(Track *track) static bool load_song(Track *track)
{ {
GstState state; bool start_playback;
gchar *uri;
std::string filepath = track->path();
if (o_should_pause == true) { if (o_should_pause)
state = GST_STATE_PAUSED; start_playback = false;
o_should_pause = false; else
} else { start_playback = driver :: get_driver()->is_playing();
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);
driver :: get_driver()->load(track->path());
get_callbacks()->on_track_loaded(track); get_callbacks()->on_track_loaded(track);
return change_state(state);
if (start_playback)
return driver :: get_driver()->play();
else
return driver :: get_driver()->pause();
} }
void audio :: init(int *argc, char ***argv) void audio :: init(int *argc, char ***argv)
{ {
GstBus *bus; driver :: get_driver()->init(argc, argv, on_eos, on_error);
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 :: load_state() void audio :: load_state()
@ -144,15 +97,13 @@ void audio :: load_state()
void audio :: quit() void audio :: quit()
{ {
change_state(GST_STATE_NULL);
gst_deinit();
} }
void audio :: play() void audio :: play()
{ {
if (track_loaded == false) if (track_loaded == false)
return; return;
if (change_state(GST_STATE_PLAYING)) if (driver :: get_driver()->play())
get_callbacks()->on_play(); get_callbacks()->on_play();
} }
@ -160,7 +111,7 @@ void audio :: pause()
{ {
if (track_loaded == false) if (track_loaded == false)
return; return;
if (change_state(GST_STATE_PAUSED)) if (driver :: get_driver()->pause())
get_callbacks()->on_pause(); get_callbacks()->on_pause();
} }
@ -180,15 +131,9 @@ void audio :: stop()
void audio :: seek_to(long pos) void audio :: seek_to(long pos)
{ {
bool ret;
if (track_loaded == false) if (track_loaded == false)
return; return;
ret = gst_element_seek_simple(GST_ELEMENT(ocarina_player), driver :: get_driver()->seek_to(pos);
GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
pos);
if (!ret)
throw -E_AUDIO;
} }
void audio :: next() void audio :: next()
@ -245,13 +190,9 @@ unsigned int audio :: current_trackid()
long audio :: position() long audio :: position()
{ {
long position;
if (track_loaded == false) if (track_loaded == false)
return 0; return 0;
if (!gst_element_query_position(GST_ELEMENT(ocarina_player), GST_FORMAT_TIME, &position)) return driver :: get_driver()->position();
return 0;
return position;
} }
std::string audio :: position_str() std::string audio :: position_str()
@ -270,13 +211,9 @@ std::string audio :: position_str()
long audio :: duration() long audio :: duration()
{ {
long duration;
if (track_loaded == false) if (track_loaded == false)
return 0; return 0;
if (!gst_element_query_duration(ocarina_player, GST_FORMAT_TIME, &duration)) return driver :: get_driver()->duration();
return 0;
return duration;
} }
void audio :: pause_after(bool enabled, unsigned int n) void audio :: pause_after(bool enabled, unsigned int n)

View File

@ -13,30 +13,134 @@ Driver :: ~Driver() {}
TestDriver :: TestDriver() : playing(false), cur_pos(0), cur_duration(0) {} TestDriver :: TestDriver() : playing(false), cur_pos(0), cur_duration(0) {}
TestDriver :: ~TestDriver() {} TestDriver :: ~TestDriver() {}
void TestDriver :: init(int *argc, char ***argv, void (*eos_cb)()) { on_eos = eos_cb; } void TestDriver :: init(int *argc, char ***argv, void (*eos_cb)(), void (*error_cb)())
{ on_eos = eos_cb; on_error = error_cb; }
void TestDriver :: load(const std::string &file) { cur_file = file; } void TestDriver :: load(const std::string &file) { cur_file = file; }
void TestDriver :: play() { playing = true; } bool TestDriver :: play() { playing = true; return true; }
void TestDriver :: pause() { playing = false; } bool TestDriver :: pause() { playing = false; return true; }
bool TestDriver :: is_playing() { return playing; }
void TestDriver :: seek_to(long pos) { cur_pos = pos; } void TestDriver :: seek_to(long pos) { cur_pos = pos; }
long TestDriver :: position() { return cur_pos; } long TestDriver :: position() { return cur_pos; }
long TestDriver :: duration() { return cur_duration; } long TestDriver :: duration() { return cur_duration; }
void TestDriver :: eos() { on_eos(); } void TestDriver :: eos() { on_eos(); }
void TestDriver :: error() { on_error(); }
#else /* CONFIG_TEST */ #else /* CONFIG_TEST */
static gboolean on_gst_message(GstBus *bus, GstMessage *message, gpointer data)
{
GSTDriver *driver = (GSTDriver *)data;
driver->on_message(message);
return TRUE;
}
static void parse_gst_error(GstMessage *error, const std::string filepath)
{
GError *err;
gchar *debug;
gst_message_parse_error(error, &err, &debug);
g_print("Error playing file: %s\n", filepath.c_str());
g_print("Error: %s\n", err->message);
g_error_free(err);
g_free(debug);
}
GSTDriver :: GSTDriver() {} GSTDriver :: GSTDriver() {}
GSTDriver :: ~GSTDriver() {}
void GSTDriver :: init(int argc, char **argv, void (*eos_cb)()) { } GSTDriver :: ~GSTDriver()
void GSTDriver :: load(const std::string &file) { } {
void GSTDriver :: play() { } change_state(GST_STATE_NULL);
void GSTDriver :: pause() { } gst_deinit();
}
void GSTDriver :: seek_to(long pos) { } bool GSTDriver :: change_state(GstState state)
long GSTDriver :: position() { return 0; } {
long GSTDriver :: duration() { return 0; } GstStateChangeReturn ret = gst_element_set_state(player, state);
switch (ret) {
case GST_STATE_CHANGE_SUCCESS:
case GST_STATE_CHANGE_ASYNC:
return true;
default:
return false;
}
}
void GSTDriver :: init(int *argc, char ***argv, void (*eos_cb)(), void (*error_cb)())
{
GstBus *bus;
on_eos = eos_cb;
on_error = error_cb;
gst_init(argc, argv);
player = gst_element_factory_make("playbin", "ocarina_player");
bus = gst_pipeline_get_bus(GST_PIPELINE(player));
gst_bus_add_watch(bus, on_gst_message, this);
}
void GSTDriver :: load(const std::string &filepath)
{
gchar *uri;
cur_file = filepath;
change_state(GST_STATE_NULL);
uri = gst_filename_to_uri(filepath.c_str(), NULL);
g_object_set(G_OBJECT(player), "uri", uri, NULL);
g_free(uri);
}
bool GSTDriver :: play()
{
return change_state(GST_STATE_PLAYING);
}
bool GSTDriver :: pause()
{
return change_state(GST_STATE_PAUSED);
}
bool GSTDriver :: is_playing()
{
GstState state;
gst_element_get_state(player, &state, NULL, GST_CLOCK_TIME_NONE);
return state == GST_STATE_PLAYING;
}
void GSTDriver :: seek_to(long pos)
{
gst_element_seek_simple(player, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, pos);
}
long GSTDriver :: position()
{
long position;
if (gst_element_query_position(player, GST_FORMAT_TIME, &position))
return position;
return 0;
}
long GSTDriver :: duration()
{
long duration;
if (gst_element_query_duration(player, GST_FORMAT_TIME, &duration))
return duration;
return 0;
}
void GSTDriver :: on_message(GstMessage *message)
{
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
parse_gst_error(message, cur_file);
on_error();
default:
break;
}
}
#endif /* CONFIG_TEST */ #endif /* CONFIG_TEST */

View File

@ -6,12 +6,18 @@
static TestDriver *DRIVER_NULL = NULL; static TestDriver *DRIVER_NULL = NULL;
static unsigned int eos_count = 0; static unsigned int eos_count = 0;
static unsigned int error_count = 0;
void on_eos() void on_eos()
{ {
eos_count++; eos_count++;
} }
void on_error()
{
error_count++;
}
void test_driver() void test_driver()
{ {
TestDriver *driver = (TestDriver *)driver :: get_driver(); TestDriver *driver = (TestDriver *)driver :: get_driver();
@ -19,15 +25,18 @@ void test_driver()
test_not_equal(driver, DRIVER_NULL); test_not_equal(driver, DRIVER_NULL);
driver->init(0, NULL, on_eos); driver->init(0, NULL, on_eos, on_error);
driver->load(file); driver->load(file);
test_equal(driver->cur_file, file); test_equal(driver->cur_file, file);
driver->play(); test_equal(driver->play(), true);
test_equal(driver->playing, true); test_equal(driver->playing, true);
driver->pause(); test_equal(driver->is_playing(), true);
test_equal(driver->pause(), true);
test_equal(driver->playing, false); test_equal(driver->playing, false);
test_equal(driver->is_playing(), false);
driver->seek_to(4242); driver->seek_to(4242);
test_equal(driver->cur_pos, (long)4242); test_equal(driver->cur_pos, (long)4242);
@ -38,6 +47,9 @@ void test_driver()
driver->eos(); driver->eos();
test_equal(eos_count, (unsigned)1); test_equal(eos_count, (unsigned)1);
driver->error();
test_equal(error_count, (unsigned)1);
} }
int main(int argc, char **argv) int main(int argc, char **argv)