diff options
Diffstat (limited to 'src/StatsPublish.cpp')
-rw-r--r-- | src/StatsPublish.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/StatsPublish.cpp b/src/StatsPublish.cpp new file mode 100644 index 0000000..ccf2bb4 --- /dev/null +++ b/src/StatsPublish.cpp @@ -0,0 +1,123 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2019 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 "StatsPublish.h" +#include <stdexcept> +#include <sstream> +#include <cstring> +#include <cerrno> +#include <cassert> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +using namespace std; + +StatsPublisher::StatsPublisher(const string& socket_path) : + m_socket_path(socket_path) +{ + // The client socket binds to a socket whose name depends on PID, and connects to + // `socket_path` + + m_sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (m_sock == -1) { + throw runtime_error("Stats 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/odr-audioenc.%ld", (long) getpid()); + + int ret = bind(m_sock, (const struct sockaddr *) &claddr, sizeof(struct sockaddr_un)); + if (ret == -1) { + throw runtime_error("Stats socket bind failed " + string(strerror(errno))); + } +} + +void StatsPublisher::update_audio_levels(int16_t audiolevel_left, int16_t audiolevel_right) +{ + m_audio_left = audiolevel_left; + m_audio_right = audiolevel_right; +} + +void StatsPublisher::notify_underrun() +{ + m_num_underruns++; +} + +void StatsPublisher::notify_overrun() +{ + m_num_overruns++; +} + +void StatsPublisher::send_stats() +{ + // Manually build YAML, as it's quite easy. + stringstream yaml; + yaml << "---\n"; + yaml << "program: " << PACKAGE_NAME << "\n"; + yaml << "version: " << +#if defined(GITVERSION) + GITVERSION +#else + PACKAGE_VERSION +#endif + << "\n"; + yaml << "audiolevels: { left: " << m_audio_left << ", right: " << m_audio_right << "}\n"; + yaml << "driftcompensation: { underruns: " << m_num_underruns << ", overruns: " << m_num_overruns << "}\n"; + + const auto yamlstr = yaml.str(); + + struct sockaddr_un claddr; + memset(&claddr, 0, sizeof(struct sockaddr_un)); + claddr.sun_family = AF_UNIX; + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "%s", m_socket_path.c_str()); + + int ret = sendto(m_sock, yamlstr.data(), yamlstr.size(), 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_destination_available) { + fprintf(stderr, "Stats destination not available at %s\n", m_socket_path.c_str()); + m_destination_available = false; + } + } + else { + fprintf(stderr, "Statistics send failed: %s\n", strerror(errno)); + } + } + else if (ret != yamlstr.size()) { + fprintf(stderr, "Statistics send incorrect length: %d bytes of %zu transmitted\n", + ret, yamlstr.size()); + } + else if (not m_destination_available) { + fprintf(stderr, "Stats destination is now available at %s\n", m_socket_path.c_str()); + m_destination_available = true; + } + + m_audio_left = 0; + m_audio_right = 0; +} |