Switch to side-by-side view

--- 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;