--- a/sc2src/sc2mpd.cpp
+++ b/sc2src/sc2mpd.cpp
@@ -58,7 +58,9 @@
#include <signal.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/un.h>
#include <fcntl.h>
using namespace std;
@@ -108,7 +110,6 @@
using namespace OpenHome::Net;
using namespace OpenHome::TestFramework;
using namespace OpenHome::Av;
-
class OhmReceiverDriver : public IOhmReceiverDriver, public IOhmMsgProcessor {
public:
@@ -454,6 +455,101 @@
}
#endif
+#define SOCK_PATH "/tmp/sc2mpd.sock"
+#define BUF_SIZE 16
+void HandleUserCmd(OhmReceiver* receiver, AudioEater* audio, const Brx& aUri)
+{
+ struct sockaddr_un server_addr, client_addr;
+ struct timeval read_timeout;
+ socklen_t len;
+ ssize_t num_bytes;
+ char buf[BUF_SIZE];
+ int sockfd = -1;
+
+ read_timeout.tv_sec = 1;
+ read_timeout.tv_usec = 0;
+
+ LOGDEB("OhmReceiver: Running user command handler\n");
+
+ sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sockfd == -1) {
+ LOGERR("Error: Cannot create socket: " << strerror(errno) << endl);
+ goto _leave;
+ }
+ setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout,
+ sizeof read_timeout);
+
+ if (remove(SOCK_PATH) == -1 && errno != ENOENT) {
+ LOGERR("Error: Cannot remove socket path: " << strerror(errno) << endl);
+ goto _close_socket;
+ }
+
+ memset(&server_addr, 0, sizeof(struct sockaddr_un));
+ server_addr.sun_family = AF_UNIX;
+ strncpy(server_addr.sun_path, SOCK_PATH, sizeof(server_addr.sun_path) - 1);
+
+ if (bind(sockfd, (struct sockaddr *) &server_addr,
+ sizeof(struct sockaddr_un)) == -1) {
+ LOGERR("Error: Cannot bind to socket: " << strerror(errno) << endl);
+ goto _close_socket;
+ }
+
+ while (!g_quitrequest) {
+ len = sizeof(struct sockaddr_un);
+ // recvfrom() is a blocking call and will wait for messages to arrive.
+ // If no data has been received within `read_timeout` then -1 is
+ // returned by `recvfrom()` with errno set to EAGAIN or EWOULDBLOCK.
+ num_bytes = recvfrom(sockfd, buf, BUF_SIZE, 0,
+ (struct sockaddr *) &client_addr, &len);
+ if (num_bytes == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ continue; // Ignore timeout
+ }
+ else {
+ LOGERR("Error: Failed to receive from socket: " <<
+ strerror(errno) << endl);
+ goto _close_socket;
+ }
+ }
+ if (num_bytes > 0) {
+ string response("OK");
+
+ LOGDEB("HandleUserCmd: Received " << num_bytes << " bytes: " <<
+ string(buf, num_bytes) << endl);
+ if (strncmp("play", buf, num_bytes) == 0)
+ receiver->Play(aUri);
+ else if (strncmp("stop", buf, num_bytes) == 0)
+ receiver->Stop();
+ else if (strncmp("state", buf, num_bytes) == 0) {
+ response = "Unknown";
+ if (audio->state) {
+ switch (audio->state()) {
+ case AudioEater::AudioState::STOPPED:
+ response = "Stopped"; break;
+ case AudioEater::AudioState::PLAYING:
+ response = "Playing"; break;
+ case AudioEater::AudioState::UNKNOWN:
+ break;
+ }
+ }
+ }
+ ssize_t bytes_sent = sendto(sockfd, (const void *)response.c_str(),
+ response.length(), 0,
+ (struct sockaddr *)&client_addr, len);
+ if (bytes_sent == -1) {
+ LOGERR("Error: Cannot write to socket: " <<
+ strerror(errno) << endl);
+ }
+ }
+ }
+
+_close_socket:
+ if (sockfd > 0)
+ close(sockfd);
+_leave:
+ LOGDEB("OhmReceiver: Leaving user command handler\n");
+}
+
int CDECL main(int aArgc, char* aArgv[])
{
string logfilename;
@@ -556,9 +652,10 @@
((subnet >> 8) & 0xff) << "." << ((subnet >> 16) & 0xff) << "." <<
((subnet >> 24) & 0xff) << endl);
- OhmReceiverDriver* driver =
- new OhmReceiverDriver(optionDevice.Value() ?
- &alsaAudioEater : &httpAudioEater, ctxt);
+ AudioEater* eater = optionDevice.Value() ?
+ &alsaAudioEater : &httpAudioEater;
+
+ OhmReceiverDriver* driver = new OhmReceiverDriver(eater, ctxt);
OhmReceiver* receiver = new OhmReceiver(lib->Env(), adapter, ttl, *driver);
@@ -592,6 +689,7 @@
}
receiver->Play(uri);
for (;;) {
+ HandleUserCmd(receiver, eater, uri);
if (g_quitrequest) {
LOGDEB("Quit requested\n");
break;