mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-18 11:36:14 +02:00
Basic metadata working librespot/server/client. Still missing client hooks.
The librespot metadata api kinda messy, no clear API. For now I addded printing of artist in Librespot, should publish patch
This commit is contained in:
parent
d444052233
commit
af3ea660b9
13 changed files with 101 additions and 60 deletions
|
@ -31,7 +31,8 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
CXXFLAGS += $(ADD_CFLAGS) -std=c++0x -Wall -Wno-unused-function -O3 -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -isystem ../externals/asio/asio/include -I../externals/popl/include -I../externals/aixlog/include
|
# Include the process.hpp for usage in meta tags callback
|
||||||
|
CXXFLAGS += $(ADD_CFLAGS) -std=c++0x -Wall -Wno-unused-function -O3 -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -isystem ../externals/asio/asio/include -I../externals/popl/include -I../externals/aixlog/include -I../server/streamreader
|
||||||
LDFLAGS = -logg -lFLAC
|
LDFLAGS = -logg -lFLAC
|
||||||
OBJ = snapClient.o stream.o clientConnection.o timeProvider.o player/player.o decoder/pcmDecoder.o decoder/oggDecoder.o decoder/flacDecoder.o controller.o ../message/pcmChunk.o ../common/sampleFormat.o
|
OBJ = snapClient.o stream.o clientConnection.o timeProvider.o player/player.o decoder/pcmDecoder.o decoder/oggDecoder.o decoder/flacDecoder.o controller.o ../message/pcmChunk.o ../common/sampleFormat.o
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,21 @@ void Controller::onMessageReceived(ClientConnection* connection, const msg::Base
|
||||||
streamTags_.reset(new msg::StreamTags());
|
streamTags_.reset(new msg::StreamTags());
|
||||||
streamTags_->deserialize(baseMessage, buffer);
|
streamTags_->deserialize(baseMessage, buffer);
|
||||||
|
|
||||||
LOG(INFO) << "Tag received: artist = " << streamTags_->getArtist() << "\n";
|
LOG(INFO) << "Stream tags: artist = <" << streamTags_->getArtist() << ">, album = <" << streamTags_->getAlbum() << ">, track = <" << streamTags_->getTrack() << ">\n";
|
||||||
LOG(INFO) << "Tag received: album = " << streamTags_->getAlbum() << "\n";
|
|
||||||
LOG(INFO) << "Tag received: track = " << streamTags_->getTrack() << "\n";
|
// And we should trigger the meta tags script if given
|
||||||
|
struct stat buffer;
|
||||||
|
if(stat(meta_callback_.c_str(), &buffer) == 0)
|
||||||
|
{
|
||||||
|
LOG(INFO) << "About to execute meta tag callback script!\n";
|
||||||
|
|
||||||
|
// Check if its there, set environment and execute it
|
||||||
|
// Probably can use the process thing from streamreader
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Meta tag callback script not found!\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseMessage.type != message_type::kTime)
|
if (baseMessage.type != message_type::kTime)
|
||||||
|
@ -163,10 +175,11 @@ bool Controller::sendTimeSyncMessage(long after)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Controller::start(const PcmDevice& pcmDevice, const std::string& host, size_t port, int latency)
|
void Controller::start(const PcmDevice& pcmDevice, const std::string& host, size_t port, int latency, const std::string& meta_callback)
|
||||||
{
|
{
|
||||||
pcmDevice_ = pcmDevice;
|
pcmDevice_ = pcmDevice;
|
||||||
latency_ = latency;
|
latency_ = latency;
|
||||||
|
meta_callback_ = meta_callback;
|
||||||
clientConnection_.reset(new ClientConnection(this, host, port));
|
clientConnection_.reset(new ClientConnection(this, host, port));
|
||||||
controllerThread_ = thread(&Controller::worker, this);
|
controllerThread_ = thread(&Controller::worker, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Controller : public MessageReceiver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Controller(const std::string& clientId, size_t instance);
|
Controller(const std::string& clientId, size_t instance);
|
||||||
void start(const PcmDevice& pcmDevice, const std::string& host, size_t port, int latency);
|
void start(const PcmDevice& pcmDevice, const std::string& host, size_t port, int latency, const std::string& meta_callback);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
/// Implementation of MessageReceiver.
|
/// Implementation of MessageReceiver.
|
||||||
|
@ -63,6 +63,7 @@ private:
|
||||||
void worker();
|
void worker();
|
||||||
bool sendTimeSyncMessage(long after = 1000);
|
bool sendTimeSyncMessage(long after = 1000);
|
||||||
std::string hostId_;
|
std::string hostId_;
|
||||||
|
std::string meta_callback_;
|
||||||
size_t instance_;
|
size_t instance_;
|
||||||
std::atomic<bool> active_;
|
std::atomic<bool> active_;
|
||||||
std::thread controllerThread_;
|
std::thread controllerThread_;
|
||||||
|
|
|
@ -73,6 +73,7 @@ int main (int argc, char **argv)
|
||||||
int exitcode = EXIT_SUCCESS;
|
int exitcode = EXIT_SUCCESS;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
string meta_callback("");
|
||||||
string soundcard("default");
|
string soundcard("default");
|
||||||
string host("");
|
string host("");
|
||||||
size_t port(1704);
|
size_t port(1704);
|
||||||
|
@ -87,6 +88,7 @@ int main (int argc, char **argv)
|
||||||
auto listSwitch = op.add<Switch>("l", "list", "list pcm devices");
|
auto listSwitch = op.add<Switch>("l", "list", "list pcm devices");
|
||||||
/*auto soundcardValue =*/ op.add<Value<string>>("s", "soundcard", "index or name of the soundcard", "default", &soundcard);
|
/*auto soundcardValue =*/ op.add<Value<string>>("s", "soundcard", "index or name of the soundcard", "default", &soundcard);
|
||||||
#endif
|
#endif
|
||||||
|
/*auto metaValue =*/ op.add<Value<string>>("m", "meta", "script to call on meta tags", "", &meta_callback);
|
||||||
/*auto hostValue =*/ op.add<Value<string>>("h", "host", "server hostname or ip address", "", &host);
|
/*auto hostValue =*/ op.add<Value<string>>("h", "host", "server hostname or ip address", "", &host);
|
||||||
/*auto portValue =*/ op.add<Value<size_t>>("p", "port", "server port", 1704, &port);
|
/*auto portValue =*/ op.add<Value<size_t>>("p", "port", "server port", 1704, &port);
|
||||||
#ifdef HAS_DAEMON
|
#ifdef HAS_DAEMON
|
||||||
|
@ -230,7 +232,7 @@ int main (int argc, char **argv)
|
||||||
if (!g_terminated)
|
if (!g_terminated)
|
||||||
{
|
{
|
||||||
LOG(INFO) << "Latency: " << latency << "\n";
|
LOG(INFO) << "Latency: " << latency << "\n";
|
||||||
controller->start(pcmDevice, host, port, latency);
|
controller->start(pcmDevice, host, port, latency, meta_callback);
|
||||||
while(!g_terminated)
|
while(!g_terminated)
|
||||||
chronos::sleep(100);
|
chronos::sleep(100);
|
||||||
controller->stop();
|
controller->stop();
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
/***
|
|
||||||
This file is part of snapcast
|
|
||||||
Copyright (C) 2014-2017 Johannes Pohl
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
***/
|
|
||||||
|
|
||||||
#ifndef METATAGS_DATA_H
|
|
||||||
#define METATAGS_DATA_H
|
|
||||||
|
|
||||||
#include "message/streamTags.h"
|
|
||||||
|
|
||||||
class MetaTags
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MetaTags();
|
|
||||||
virtual ~MetaTags();
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -21,6 +21,19 @@
|
||||||
|
|
||||||
#include "jsonMessage.h"
|
#include "jsonMessage.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Due to the PCM pipe implementation of snapcast input we cannot know track start/end
|
||||||
|
* it's all a long stream (although we detect idle situations)
|
||||||
|
*
|
||||||
|
* So, we cannot push metadata on start of track as we don't know when that is.
|
||||||
|
*
|
||||||
|
* I.E. we push metadata as we get an update, as we don't know when an update
|
||||||
|
* is complete (different meta supported in different stream interfaces)
|
||||||
|
* it is the streamreaders responsibility to update metadata and
|
||||||
|
* trigger a client notification.
|
||||||
|
*
|
||||||
|
* I.E. we need to suppply the client notification mechanism.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace msg
|
namespace msg
|
||||||
{
|
{
|
||||||
|
@ -33,12 +46,23 @@ public:
|
||||||
msg["meta_artist"] = "";
|
msg["meta_artist"] = "";
|
||||||
msg["meta_album"] = "";
|
msg["meta_album"] = "";
|
||||||
msg["meta_track"] = "";
|
msg["meta_track"] = "";
|
||||||
|
msg["meta_albumart"] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~StreamTags()
|
virtual ~StreamTags()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json toJson() const
|
||||||
|
{
|
||||||
|
json j = {
|
||||||
|
{"artist", getArtist()},
|
||||||
|
{"album", getAlbum()},
|
||||||
|
{"track", getTrack()},
|
||||||
|
};
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
std::string getArtist() const
|
std::string getArtist() const
|
||||||
{
|
{
|
||||||
return msg["meta_artist"];
|
return msg["meta_artist"];
|
||||||
|
@ -54,6 +78,11 @@ public:
|
||||||
return msg["meta_track"];
|
return msg["meta_track"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getAlbumArt() const
|
||||||
|
{
|
||||||
|
return msg["meta_albumart"];
|
||||||
|
}
|
||||||
|
|
||||||
void setArtist(std::string artist)
|
void setArtist(std::string artist)
|
||||||
{
|
{
|
||||||
msg["meta_artist"] = artist;
|
msg["meta_artist"] = artist;
|
||||||
|
@ -68,6 +97,12 @@ public:
|
||||||
{
|
{
|
||||||
msg["meta_track"] = track;
|
msg["meta_track"] = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ascii encoded image XXX: more details
|
||||||
|
void setAlbumArt(std::string art)
|
||||||
|
{
|
||||||
|
msg["meta_albumart"] = art;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ endif
|
||||||
|
|
||||||
CXXFLAGS += $(ADD_CFLAGS) -std=c++0x -Wall -Wno-unused-function -O3 -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -isystem ../externals/asio/asio/include -I../externals/popl/include -I../externals/aixlog/include -I../externals/jsonrpcpp/lib -I../externals
|
CXXFLAGS += $(ADD_CFLAGS) -std=c++0x -Wall -Wno-unused-function -O3 -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -isystem ../externals/asio/asio/include -I../externals/popl/include -I../externals/aixlog/include -I../externals/jsonrpcpp/lib -I../externals
|
||||||
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC
|
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC
|
||||||
OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o streamreader/streamUri.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o streamreader/processStream.o streamreader/airplayStream.o streamreader/spotifyStream.o streamreader/watchdog.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o ../common/metatags.o ../common/sampleFormat.o ../message/pcmChunk.o ../externals/jsonrpcpp/lib/jsonrp.o
|
OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o streamreader/streamUri.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o streamreader/processStream.o streamreader/airplayStream.o streamreader/spotifyStream.o streamreader/watchdog.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o ../common/sampleFormat.o ../message/pcmChunk.o ../externals/jsonrpcpp/lib/jsonrp.o
|
||||||
|
|
||||||
|
|
||||||
ifneq (,$(TARGET))
|
ifneq (,$(TARGET))
|
||||||
|
|
|
@ -39,6 +39,23 @@ StreamServer::~StreamServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StreamServer::onMetaChanged(const PcmStream* pcmStream)
|
||||||
|
{
|
||||||
|
/// Notification: {"jsonrpc":"2.0","method":"Stream.OnMetadata","params":{"id":"stream 1", "meta": {"album": "some album", "artist": "some artist", "track": "some track"...}}
|
||||||
|
|
||||||
|
const auto meta = pcmStream->getMeta();
|
||||||
|
for (auto s : sessions_)
|
||||||
|
{
|
||||||
|
if (s->pcmStream().get() == pcmStream)
|
||||||
|
s->sendAsync(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "onMetaChanged (" << pcmStream->getName() << ")\n";
|
||||||
|
json notification = jsonrpcpp::Notification("Stream.OnMetadata", jsonrpcpp::Parameter("id", pcmStream->getId(), "meta", meta->toJson())).to_json();
|
||||||
|
controlServer_->send(notification.dump(), NULL);
|
||||||
|
cout << "Notification: " << notification.dump() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
void StreamServer::onStateChanged(const PcmStream* pcmStream, const ReaderState& state)
|
void StreamServer::onStateChanged(const PcmStream* pcmStream, const ReaderState& state)
|
||||||
{
|
{
|
||||||
/// Notification: {"jsonrpc":"2.0","method":"Stream.OnUpdate","params":{"id":"stream 1","stream":{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}}}
|
/// Notification: {"jsonrpc":"2.0","method":"Stream.OnUpdate","params":{"id":"stream 1","stream":{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"buffer_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}}}
|
||||||
|
@ -251,6 +268,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
|
||||||
session_ptr session = getStreamSession(client->id);
|
session_ptr session = getStreamSession(client->id);
|
||||||
if (session && (session->pcmStream() != stream))
|
if (session && (session->pcmStream() != stream))
|
||||||
{
|
{
|
||||||
|
session->sendAsync(stream->getMeta());
|
||||||
session->sendAsync(stream->getHeader());
|
session->sendAsync(stream->getHeader());
|
||||||
session->setPcmStream(stream);
|
session->setPcmStream(stream);
|
||||||
}
|
}
|
||||||
|
@ -303,6 +321,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
|
||||||
session_ptr session = getStreamSession(client->id);
|
session_ptr session = getStreamSession(client->id);
|
||||||
if (session && stream && (session->pcmStream() != stream))
|
if (session && stream && (session->pcmStream() != stream))
|
||||||
{
|
{
|
||||||
|
session->sendAsync(stream->getMeta());
|
||||||
session->sendAsync(stream->getHeader());
|
session->sendAsync(stream->getHeader());
|
||||||
session->setPcmStream(stream);
|
session->setPcmStream(stream);
|
||||||
}
|
}
|
||||||
|
@ -517,14 +536,7 @@ void StreamServer::onMessageReceived(StreamSession* connection, const msg::BaseM
|
||||||
|
|
||||||
Config::instance().save();
|
Config::instance().save();
|
||||||
|
|
||||||
// Send the group stream tags
|
|
||||||
LOG(INFO) << "request kStreamTags\n";
|
|
||||||
//auto metaTags = make_shared<msg::StreamTags>();
|
|
||||||
//metaTags->setArtist(stream->getMeta()->getArtist());
|
|
||||||
//connection->sendAsync(metaTags);
|
|
||||||
connection->sendAsync(stream->getMeta());
|
connection->sendAsync(stream->getMeta());
|
||||||
LOG(INFO) << "kStreamTags sent\n";
|
|
||||||
|
|
||||||
connection->setPcmStream(stream);
|
connection->setPcmStream(stream);
|
||||||
auto headerChunk = stream->getHeader();
|
auto headerChunk = stream->getHeader();
|
||||||
connection->sendAsync(headerChunk);
|
connection->sendAsync(headerChunk);
|
||||||
|
|
|
@ -92,6 +92,7 @@ public:
|
||||||
virtual void onMessageReceived(ControlSession* connection, const std::string& message);
|
virtual void onMessageReceived(ControlSession* connection, const std::string& message);
|
||||||
|
|
||||||
/// Implementation of PcmListener
|
/// Implementation of PcmListener
|
||||||
|
virtual void onMetaChanged(const PcmStream* pcmStream);
|
||||||
virtual void onStateChanged(const PcmStream* pcmStream, const ReaderState& state);
|
virtual void onStateChanged(const PcmStream* pcmStream, const ReaderState& state);
|
||||||
virtual void onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk, double duration);
|
virtual void onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk, double duration);
|
||||||
virtual void onResync(const PcmStream* pcmStream, double ms);
|
virtual void onResync(const PcmStream* pcmStream, double ms);
|
||||||
|
|
|
@ -171,7 +171,8 @@ json PcmStream::toJson() const
|
||||||
json j = {
|
json j = {
|
||||||
{"uri", uri_.toJson()},
|
{"uri", uri_.toJson()},
|
||||||
{"id", getId()},
|
{"id", getId()},
|
||||||
{"status", state}
|
{"status", state},
|
||||||
|
{"meta", meta_->toJson()}
|
||||||
};
|
};
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ enum ReaderState
|
||||||
class PcmListener
|
class PcmListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual void onMetaChanged(const PcmStream* pcmStream) = 0;
|
||||||
virtual void onStateChanged(const PcmStream* pcmStream, const ReaderState& state) = 0;
|
virtual void onStateChanged(const PcmStream* pcmStream, const ReaderState& state) = 0;
|
||||||
virtual void onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk, double duration) = 0;
|
virtual void onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk, double duration) = 0;
|
||||||
virtual void onResync(const PcmStream* pcmStream, double ms) = 0;
|
virtual void onResync(const PcmStream* pcmStream, double ms) = 0;
|
||||||
|
@ -86,7 +87,7 @@ public:
|
||||||
virtual json toJson() const;
|
virtual json toJson() const;
|
||||||
|
|
||||||
//const msg::StreamTags *getMeta()
|
//const msg::StreamTags *getMeta()
|
||||||
std::shared_ptr<msg::StreamTags> getMeta()
|
std::shared_ptr<msg::StreamTags> getMeta() const
|
||||||
{
|
{
|
||||||
return meta_;
|
return meta_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,7 @@ void SpotifyStream::onStderrMsg(const char* buffer, size_t n)
|
||||||
// 2016-11-03 09-00-18 [out] INFO:librespot::session: Authenticated !
|
// 2016-11-03 09-00-18 [out] INFO:librespot::session: Authenticated !
|
||||||
watchdog_->trigger();
|
watchdog_->trigger();
|
||||||
string logmsg = utils::string::trim_copy(string(buffer, n));
|
string logmsg = utils::string::trim_copy(string(buffer, n));
|
||||||
|
|
||||||
if ((logmsg.find("allocated stream") == string::npos) &&
|
if ((logmsg.find("allocated stream") == string::npos) &&
|
||||||
(logmsg.find("Got channel") == string::npos) &&
|
(logmsg.find("Got channel") == string::npos) &&
|
||||||
(logmsg.find('\0') == string::npos) &&
|
(logmsg.find('\0') == string::npos) &&
|
||||||
|
@ -123,16 +124,24 @@ void SpotifyStream::onStderrMsg(const char* buffer, size_t n)
|
||||||
LOG(INFO) << "(" << getName() << ") " << logmsg << "\n";
|
LOG(INFO) << "(" << getName() << ") " << logmsg << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for metadata
|
// Track tags "Julia Michaels" "Issues - Acoustic"
|
||||||
if (logmsg.find("Loading track") != string::npos)
|
if (logmsg.find("Track tags") != string::npos)
|
||||||
{
|
{
|
||||||
regex re("Loading track \"(.*)\"");
|
// Traditional Libreelec meta interface, only track name
|
||||||
|
regex re("Track tags \"(.*)\" \"(.*)\"");
|
||||||
smatch m;
|
smatch m;
|
||||||
|
|
||||||
if (regex_search(logmsg, m, re))
|
if (regex_search(logmsg, m, re))
|
||||||
{
|
{
|
||||||
LOG(INFO) << "Loading track (" << m[1] << ")\n";
|
// Create a new meta struct?
|
||||||
getMeta()->setTrack(m[1]);
|
LOG(INFO) << "Loading track <" << m[1] << "> <" << m[2] << ">\n";
|
||||||
|
getMeta()->setArtist(m[1]);
|
||||||
|
getMeta()->setAlbum("");
|
||||||
|
getMeta()->setTrack(m[2]);
|
||||||
|
|
||||||
|
// Trigger a stream update
|
||||||
|
if (pcmListener_)
|
||||||
|
pcmListener_->onMetaChanged(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue