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:
parent
edc4a2f4ee
commit
1cacbf51e7
16
DESIGN
16
DESIGN
|
@ -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.
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
#include <error.h>
|
||||
#include <queue.h>
|
||||
|
||||
extern "C" {
|
||||
#include <gst/gst.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace audio
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
||||
|
|
127
lib/audio.cpp
127
lib/audio.cpp
|
@ -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)
|
||||
|
|
128
lib/driver.cpp
128
lib/driver.cpp
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue