audio: Implement pause after N tracks feature

This patch implements the pause-after-N-tracks feature.  I also included
various improvements to the audio code.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2013-12-25 14:35:33 -05:00 committed by Anna Schumaker
parent ee9a98737a
commit c65c8b06f2
5 changed files with 220 additions and 13 deletions

View File

@ -33,6 +33,9 @@ Audio: (lib/audio.cpp)
options from the argv array as they are processed, so pass options from the argv array as they are processed, so pass
pointers to argc and argv to this function. pointers to argc and argv to this function.
void audio :: quit()
Clean up memory allocated by gstreamer.
bool audio :: play() bool audio :: play()
bool audio :: pause() bool audio :: pause()
Change the gstreamer state to either GST_STATE_PLAYING or Change the gstreamer state to either GST_STATE_PLAYING or
@ -71,12 +74,19 @@ Audio: (lib/audio.cpp)
unsigned int audio :: duration() unsigned int audio :: duration()
Return the duration of the current song in seconds. Return the duration of the current song in seconds.
void audio :: pause_after(unsigned int) void audio :: pause_after(bool enabled, unsigned int N)
Pause after N tracks, pass a negative number to disable. The Pause after N tracks. The first parameter is a bool
count will only be decremented when an end-of-stream message representing if this feature is enabled or not (true == enabled,
is received by the gstreamer pipeline. false == disabled).
The count will only be decremented when an end-of-stream message
is received by the gstreamer pipeline, and not when calling
next().
bool audio :: pause_enabled()
Return true if pausing is enabled, and false if pausing is
disabled.
unsigned int audio :: pause_count() unsigned int audio :: pause_count()
Return the number of tracks that will be played before Return the number of tracks that will be played before
playback pauses. Throw -1 if the user does not want us to playback pauses.
pause.

View File

@ -12,6 +12,7 @@ namespace audio
{ {
void init(int *, char ***); void init(int *, char ***);
void quit();
bool play(); bool play();
bool pause(); bool pause();
@ -22,6 +23,10 @@ namespace audio
bool seek_to(long); bool seek_to(long);
long position(); long position();
long duration(); long duration();
void pause_after(bool, unsigned int);
bool pause_enabled();
unsigned int pause_count();
}; };
#endif /* OCARINA_AUDIO_H */ #endif /* OCARINA_AUDIO_H */

View File

@ -8,11 +8,49 @@
#include <string.h> #include <string.h>
static GstElement *ocarina_player; static GstElement *ocarina_player;
static bool track_loaded = false; static bool track_loaded = false;
static unsigned int cur_trackid = 0; static unsigned int cur_trackid = 0;
static bool o_pause_enabled = false;
static unsigned int o_pause_count = 0;
static bool o_should_pause = false;
static void parse_error(GstMessage *error)
{
GError *err;
gchar *debug;
gst_message_parse_error(error, &err, &debug);
g_print("Error: %s\n", err->message);
g_error_free(err);
g_free(debug);
}
static void handle_pause_count()
{
if (o_pause_enabled == false)
return;
else if (o_pause_count == 0) {
o_should_pause = true;
o_pause_enabled = false;
} else
o_pause_count--;
}
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data) static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
{ {
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
parse_error(message);
audio :: next();
break;
case GST_MESSAGE_EOS:
handle_pause_count();
audio :: next();
default:
break;
}
return TRUE; return TRUE;
} }
@ -36,9 +74,15 @@ static bool load_song(library :: Song &song)
gchar *escaped; gchar *escaped;
std::string filepath = song.library->root_path + "/" + song.track->filepath; std::string filepath = song.library->root_path + "/" + song.track->filepath;
gst_element_get_state(GST_ELEMENT(ocarina_player), &state, if (o_should_pause == true) {
NULL, GST_CLOCK_TIME_NONE); 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);
escaped = gst_filename_to_uri(filepath.c_str(), NULL); escaped = gst_filename_to_uri(filepath.c_str(), NULL);
g_object_set(G_OBJECT(ocarina_player), "uri", escaped, NULL); g_object_set(G_OBJECT(ocarina_player), "uri", escaped, NULL);
g_free(escaped); g_free(escaped);
@ -58,6 +102,11 @@ void audio :: init(int *argc, char ***argv)
gst_bus_add_watch(bus, on_message, NULL); gst_bus_add_watch(bus, on_message, NULL);
} }
void audio :: quit()
{
gst_deinit();
}
bool audio :: play() bool audio :: play()
{ {
if (track_loaded == false) if (track_loaded == false)
@ -142,3 +191,19 @@ long audio :: duration()
return 0; return 0;
return duration; return duration;
} }
void audio :: pause_after(bool enabled, unsigned int n)
{
o_pause_enabled = enabled;
o_pause_count = n;
}
bool audio :: pause_enabled()
{
return o_pause_enabled;
}
unsigned int audio :: pause_count()
{
return o_pause_count;
}

View File

@ -63,11 +63,90 @@ void test_1()
check_ret("1b", audio :: play(), true); check_ret("1b", audio :: play(), true);
check_ret("1c", audio :: pause(), true); check_ret("1c", audio :: pause(), true);
check_ret("1d", audio :: seek_to(1 * GST_SECOND), true); check_ret("1d", audio :: seek_to(1 * GST_SECOND), true);
check_ret("1e", audio :: position(), 1 * GST_SECOND); check_ret("1e", audio :: stop(), true);
check_ret("1f", audio :: stop(), true); check_ret("1f", audio :: current_trackid() == 0, true);
check_ret("1g", audio :: current_trackid() == 0, true); check_ret("1g", audio :: position(), 0);
check_ret("1h", audio :: position(), 0); print("\n");
check_ret("1i", audio :: duration(), song.track->length); }
/* Test pause_after() */
unsigned int test_2_count = 0;
int test_2_cb(gpointer data)
{
long seek_pos, pos, max;
library :: Song song;
GMainLoop *loop = (GMainLoop *)data;
library :: lookup(audio :: current_trackid(), &song);
pos = audio :: position();
switch (test_2_count) {
case 0:
break;
case 1:
check_ret("2g", audio :: duration(), song.track->length * GST_SECOND);
seek_pos = (song.track->length * GST_SECOND) - GST_SECOND;
check_ret("2h", audio :: seek_to(seek_pos), true);
break;
case 2:
max = (song.track->length * GST_SECOND) - GST_SECOND + (501 * GST_MSECOND);
check_ret("2i", pos <= max, true);
check_ret("2j", audio :: stop(), true);
break;
case 3:
check_ret("2k", pos, 0);
check_ret("2l", audio :: play(), true);
check_ret("2m", audio :: seek_to(audio :: duration() - 1), true);
break;
case 4:
check_ret("2n", audio :: pause_count(), (long)2);
check_ret("2o", audio :: seek_to(audio :: duration() - 1), true);
break;
case 5:
check_ret("2p", audio :: pause_count(), (long)1);
check_ret("2q", audio :: seek_to(audio :: duration() - 1), true);
break;
case 6:
check_ret("2r", audio :: pause_count(), (long)0);
check_ret("2s", audio :: seek_to(audio :: duration() - 1), true);
break;
case 7:
check_ret("2t", audio :: pause_enabled(), false);
check_ret("2u", audio :: pause_count(), (long)0);
break;
case 8:
pos = audio :: position();
check_ret("2v", (0 <= pos) && (pos <= GST_MSECOND), true);
break;
case 9:
pos = audio :: position();
check_ret("2w", (0 <= pos) && (pos <= GST_MSECOND), true);
default:
g_main_quit(loop);
}
test_2_count++;
return true;
}
void test_2()
{
GMainLoop *loop;
check_ret("2a", audio :: pause_enabled(), false);
check_ret("2b", audio :: pause_count(), (long)0);
audio :: pause_after(true, 3);
check_ret("2c", audio :: pause_enabled(), true);
check_ret("2d", audio :: pause_count(), (long)3);
audio :: next();
check_ret("2e", audio :: pause_enabled(), true);
check_ret("2f", audio :: pause_count(), (long)3);
audio :: play();
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add(500, test_2_cb, loop);
g_main_loop_run(loop);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@ -87,6 +166,8 @@ int main(int argc, char **argv)
plist->add(i); plist->add(i);
test_1(); test_1();
test_2();
//audio :: quit();
return 0; return 0;
} }

46
tests/audio/audio.good Normal file
View File

@ -0,0 +1,46 @@
Generating library: 0
Generating library: 1
Generating library: 2
Generating library: 3
Generating library: 4
Test 0a: Success!
Test 0b: Success!
Test 0c: Success!
Test 0d: Success!
Test 0e: Success!
Test 0f: Success!
Test 0g: Success!
Test 0h: Success!
Test 1a: Success!
Test 1b: Success!
Test 1c: Success!
Test 1d: Success!
Test 1e: Success!
Test 1f: Success!
Test 1g: Success!
Test 2a: Success!
Test 2b: Success!
Test 2c: Success!
Test 2d: Success!
Test 2e: Success!
Test 2f: Success!
Test 2g: Success!
Test 2h: Success!
Test 2i: Success!
Test 2j: Success!
Test 2k: Success!
Test 2l: Success!
Test 2m: Success!
Test 2n: Success!
Test 2o: Success!
Test 2p: Success!
Test 2q: Success!
Test 2r: Success!
Test 2s: Success!
Test 2t: Success!
Test 2u: Success!
Test 2v: Success!
Test 2w: Success!