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:
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 play() = 0;
virtual void pause() = 0;
virtual void is_playing() = 0;
virtual void seek_to(long) = 0;
virtual long position() = 0;
@ -1333,18 +1334,25 @@ Audio Driver:
In the GSTDriver case, call gst_deinit() to avoid memory leak
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.
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);
Load file for playback, but do not begin playback yet.
void Driver :: play();
Start playback.
Start playback. Return true if the state change operation
succeeds, false otherwise.
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);
Change playback position in the current track in nanoseconds.

View File

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

View File

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

View File

@ -4,13 +4,12 @@
#include <audio.h>
#include <callback.h>
#include <deck.h>
#include <driver.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;
@ -22,19 +21,6 @@ static bool o_should_pause = false;
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()
{
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);
}
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
static void on_error()
{
audio :: next();
audio :: play();
}
static void on_eos()
{
Track *track;
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
parse_error(message);
audio :: next();
audio :: play();
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;
handle_pause_count();
track = tagdb :: lookup(cur_trackid);
if (track) {
track->played();
library :: get_queue()->updated(track);
}
audio :: next();
audio :: seek_to(0);
}
static void save_state()
@ -98,37 +63,25 @@ static void save_state()
static bool load_song(Track *track)
{
GstState state;
gchar *uri;
std::string filepath = track->path();
bool start_playback;
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);
if (o_should_pause)
start_playback = false;
else
start_playback = driver :: get_driver()->is_playing();
driver :: get_driver()->load(track->path());
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)
{
GstBus *bus;
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);
driver :: get_driver()->init(argc, argv, on_eos, on_error);
}
void audio :: load_state()
@ -144,15 +97,13 @@ void audio :: load_state()
void audio :: quit()
{
change_state(GST_STATE_NULL);
gst_deinit();
}
void audio :: play()
{
if (track_loaded == false)
return;
if (change_state(GST_STATE_PLAYING))
if (driver :: get_driver()->play())
get_callbacks()->on_play();
}
@ -160,7 +111,7 @@ void audio :: pause()
{
if (track_loaded == false)
return;
if (change_state(GST_STATE_PAUSED))
if (driver :: get_driver()->pause())
get_callbacks()->on_pause();
}
@ -180,15 +131,9 @@ void audio :: stop()
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;
driver :: get_driver()->seek_to(pos);
}
void audio :: next()
@ -245,13 +190,9 @@ unsigned int audio :: current_trackid()
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;
return driver :: get_driver()->position();
}
std::string audio :: position_str()
@ -270,13 +211,9 @@ std::string audio :: position_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;
return driver :: get_driver()->duration();
}
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() {}
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 :: play() { playing = true; }
void TestDriver :: pause() { playing = false; }
bool TestDriver :: play() { playing = true; return true; }
bool TestDriver :: pause() { playing = false; return true; }
bool TestDriver :: is_playing() { return playing; }
void TestDriver :: seek_to(long pos) { cur_pos = pos; }
long TestDriver :: position() { return cur_pos; }
long TestDriver :: duration() { return cur_duration; }
void TestDriver :: eos() { on_eos(); }
void TestDriver :: eos() { on_eos(); }
void TestDriver :: error() { on_error(); }
#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() {}
void GSTDriver :: init(int argc, char **argv, void (*eos_cb)()) { }
void GSTDriver :: load(const std::string &file) { }
void GSTDriver :: play() { }
void GSTDriver :: pause() { }
GSTDriver :: ~GSTDriver()
{
change_state(GST_STATE_NULL);
gst_deinit();
}
void GSTDriver :: seek_to(long pos) { }
long GSTDriver :: position() { return 0; }
long GSTDriver :: duration() { return 0; }
bool GSTDriver :: change_state(GstState state)
{
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 */

View File

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