libsaria: Implement gapless playback

I need to get the next file out of the library or queue without changing
it immediately.  I then queue it up in the gstreamer pipeline so it will
play automatically when the current track finishes.
This commit is contained in:
Bryan Schumaker 2011-12-23 20:48:37 -05:00
parent 2783b8d995
commit 0e983e4043
7 changed files with 69 additions and 9 deletions

View File

@ -4,6 +4,7 @@
namespace libsaria
{
void next();
string next_file();
void set_pause_after(bool);
bool get_pause_after();
void toggle_play();

View File

@ -24,9 +24,11 @@ namespace libsaria
void refresh();
void next();
string next_file();
void add_path(string);
void remove_path(string);
void play_id(ino_t &);
string find_filepath(ino_t &);
TrackTag *get_info(ino_t &);
void for_each(SourceModel *);
void for_each_path(void (*)(struct PathInfo &));

View File

@ -15,6 +15,7 @@ namespace libsaria
unsigned int size();
void next();
string next_file();
}
}

View File

@ -2,10 +2,12 @@
#include <libsaria/audio.h>
#include <libsaria/controls.h>
#include <libsaria/print.h>
#include <libsaria/library.h>
#include <libsaria/callback.h>
#include "audio.h"
GstElement *player = NULL;
GstElement *alsa = NULL;
GstBus *bus = NULL;
static void parse_error(GstMessage *error)
@ -49,6 +51,16 @@ static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
return TRUE;
}
static void about_to_finish(GstElement *playbin, gpointer data)
{
string file;
println("About to finish!");
file = libsaria::next_file();
if (file != "")
load_file(playbin, file);
}
static void audio_changed(GstElement *playbin, gpointer data)
{
GQuark quark = g_quark_from_string("audio-changed");
@ -68,9 +80,15 @@ namespace libsaria
gst_init(&argc, &argv);
player = gst_element_factory_make("playbin2", "player");
alsa = gst_element_factory_make("alsasink", "alsa");
bus = gst_pipeline_get_bus(GST_PIPELINE(player));
gst_bus_add_watch(bus, on_message, NULL);
/* Without this gapless playback won't work */
g_object_set(G_OBJECT(player), "audio-sink", alsa, NULL);
g_signal_connect(player, "about-to-finish", G_CALLBACK(about_to_finish), NULL);
g_signal_connect(player, "audio-changed", G_CALLBACK(audio_changed), NULL);
set_volume(1.0);

View File

@ -23,6 +23,14 @@ namespace libsaria
audio::play();
}
string next_file()
{
if (queue::size() > 0)
return queue::next_file();
else
return library::next_file();
}
void set_pause_after(bool state)
{
pause_after_current = state;

View File

@ -157,6 +157,14 @@ namespace libsaria
}
}
string library::find_filepath(ino_t &id)
{
list<TrackTag *>::iterator it;
if (find_id(id, it))
return (*it)->get_filepath();
return "";
}
TrackTag *library::get_info(ino_t &id)
{
list<TrackTag *>::iterator it;
@ -165,20 +173,28 @@ namespace libsaria
return NULL;
}
void library::next()
string library::next_file()
{
string filepath = "";
if (libsaria::library::size() == 0) {
libsaria::audio::stop();
return;
}
if (libsaria::library::size() == 0)
return filepath;
do {
pick_next();
filepath = (*cur_track)->get_filepath();
} while (filepath == "");
libsaria::audio::load(filepath);
return filepath;
}
void library::next()
{
string filepath = next_file();
if (filepath != "")
libsaria::audio::load(filepath);
else
libsaria::audio::stop();
}
unsigned int library::size()

View File

@ -9,6 +9,13 @@ using namespace std;
static deque<ino_t> playqueue;
static void pop_queue(ino_t &inode)
{
inode = playqueue.front();
playqueue.pop_front();
trigger_callback(QUEUE_REFRESH);
}
namespace libsaria
{
@ -35,11 +42,18 @@ namespace libsaria
return playqueue.size();
}
string queue::next_file()
{
ino_t inode;
pop_queue(inode);
return library::find_filepath(inode);
}
void queue::next()
{
library::play_id(playqueue.front());
playqueue.pop_front();
trigger_callback(QUEUE_REFRESH);
ino_t inode;
pop_queue(inode);
library::play_id(inode);
}
} /* Namespace: libsaria */