aboutsummaryrefslogtreecommitdiffstats
path: root/src/PadInterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/PadInterface.cpp')
-rw-r--r--src/PadInterface.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/PadInterface.cpp b/src/PadInterface.cpp
new file mode 100644
index 0000000..7e8a6ee
--- /dev/null
+++ b/src/PadInterface.cpp
@@ -0,0 +1,138 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2020 Matthias P. Braendli
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#include "config.h"
+#include "PadInterface.h"
+#include <stdexcept>
+#include <sstream>
+#include <cstring>
+#include <cerrno>
+#include <cassert>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define MESSAGE_REQUEST 1
+#define MESSAGE_PAD_DATA 2
+
+using namespace std;
+
+void PadInterface::open(const std::string &pad_ident)
+{
+ m_pad_ident = pad_ident;
+
+ m_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ if (m_sock == -1) {
+ throw runtime_error("PAD socket creation failed: " + string(strerror(errno)));
+ }
+
+ struct sockaddr_un claddr;
+ memset(&claddr, 0, sizeof(struct sockaddr_un));
+ claddr.sun_family = AF_UNIX;
+ snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.audioenc", m_pad_ident.c_str());
+ if (unlink(claddr.sun_path) == -1 and errno != ENOENT) {
+ fprintf(stderr, "Unlinking of socket %s failed: %s\n", claddr.sun_path, strerror(errno));
+ }
+
+ int ret = bind(m_sock, (const struct sockaddr *) &claddr, sizeof(struct sockaddr_un));
+ if (ret == -1) {
+ throw runtime_error("PAD socket bind failed " + string(strerror(errno)));
+ }
+}
+
+vector<uint8_t> PadInterface::request(uint8_t padlen)
+{
+ if (m_pad_ident.empty()) {
+ throw logic_error("Uninitialised PadInterface::request() called");
+ }
+
+ // Sending requests allows the PadEnc to know both the padlen, but also
+ // will allow proper timing.
+
+ uint8_t packet[2];
+
+ packet[0] = MESSAGE_REQUEST; // Message type, to allow future expansion
+ packet[1] = padlen;
+
+ struct sockaddr_un claddr;
+ memset(&claddr, 0, sizeof(struct sockaddr_un));
+ claddr.sun_family = AF_UNIX;
+ snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.padenc", m_pad_ident.c_str());
+
+ ssize_t ret = sendto(m_sock, packet, sizeof(packet), 0, (struct sockaddr*)&claddr, sizeof(struct sockaddr_un));
+ if (ret == -1) {
+ // This suppresses the -Wlogical-op warning
+ if (errno == EAGAIN
+#if EAGAIN != EWOULDBLOCK
+ or errno == EWOULDBLOCK
+#endif
+ or errno == ECONNREFUSED
+ or errno == ENOENT) {
+ if (m_padenc_reachable) {
+ fprintf(stderr, "ODR-PadEnc at %s not reachable\n", claddr.sun_path);
+ m_padenc_reachable = false;
+ }
+ }
+ else {
+ fprintf(stderr, "PAD request send failed: %s\n", strerror(errno));
+ }
+ }
+ else if (ret != sizeof(packet)) {
+ fprintf(stderr, "PAD request incorrect length sent: %zu bytes of %zu transmitted\n",
+ ret, sizeof(packet));
+ }
+ else if (not m_padenc_reachable) {
+ fprintf(stderr, "ODR-PadEnc is now reachable at %s\n", claddr.sun_path);
+ m_padenc_reachable = true;
+ }
+
+ vector<uint8_t> buffer(2048);
+
+ while (true) {
+ ret = recvfrom(m_sock, buffer.data(), buffer.size(), 0, nullptr, nullptr);
+
+ if (ret == -1) {
+ // This suppresses the -Wlogical-op warning
+#if EAGAIN == EWOULDBLOCK
+ if (errno != EAGAIN)
+#else
+ if (not (errno == EAGAIN or errno == EWOULDBLOCK))
+#endif
+ {
+ throw runtime_error(string("Can't receive data: ") + strerror(errno));
+ }
+
+ return {};
+ }
+ else if (ret > 0) {
+ buffer.resize(ret);
+
+ // We could check where the data comes from, but since we're using UNIX sockets
+ // the source is anyway local to the machine.
+
+ if (buffer[0] == MESSAGE_PAD_DATA) {
+ vector<uint8_t> pad_data(buffer.size() - 1);
+ copy(buffer.begin() + 1, buffer.end(), pad_data.begin());
+ return pad_data;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+}