diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-05-20 08:49:29 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-05-20 08:49:29 +0200 |
commit | 7102f830e01c3d4d695c0d36608cb09064e4aedc (patch) | |
tree | 5b0bbb2a9fff3af44c4b0a7c88b96edfd3675a39 /src/Outputs.cpp | |
parent | 3b68a6188b4983816833dc9a20be4f6b74f4c03f (diff) | |
download | ODR-AudioEnc-7102f830e01c3d4d695c0d36608cb09064e4aedc.tar.gz ODR-AudioEnc-7102f830e01c3d4d695c0d36608cb09064e4aedc.tar.bz2 ODR-AudioEnc-7102f830e01c3d4d695c0d36608cb09064e4aedc.zip |
Move outputs to a separate file
Diffstat (limited to 'src/Outputs.cpp')
-rw-r--r-- | src/Outputs.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/Outputs.cpp b/src/Outputs.cpp new file mode 100644 index 0000000..a80ca08 --- /dev/null +++ b/src/Outputs.cpp @@ -0,0 +1,171 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2011 Martin Storsjo + * 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 "Outputs.h" +#include <string> +#include <stdexcept> +#include <cstring> +#include <cerrno> +#include <cassert> + +namespace Output { + +using namespace std; + +void Base::update_audio_levels(int16_t audiolevel_left, int16_t audiolevel_right) +{ + m_audio_left = audiolevel_left; + m_audio_right = audiolevel_right; +} + +File::File(const char *filename) +{ + m_fd = fopen(filename, "wb"); + if (m_fd == nullptr) { + throw runtime_error(string("Error opening output file: ") + strerror(errno)); + } +} + +File::File(FILE *fd) : m_fd(fd) { } + +File::~File() { + if (m_fd) { + fclose(m_fd); + m_fd = nullptr; + } +} + +bool File::write_frame(const uint8_t *buf, size_t len) +{ + if (m_fd == nullptr) { + throw logic_error("Invalid usage of closed File output"); + } + + return fwrite(buf, len, 1, m_fd) == 1; +} + +ZMQ::ZMQ() : + m_ctx(), + m_sock(m_ctx, ZMQ_PUB) +{ + // Do not wait at teardown to send all data out + int linger = 0; + m_sock.setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); +} + +ZMQ::~ZMQ() {} + +void ZMQ::connect(const char *uri, const char *keyfile) +{ + if (keyfile) { + fprintf(stderr, "Enabling encryption\n"); + + int rc = readkey(keyfile, m_secretkey); + if (rc) { + throw runtime_error("Error reading secret key"); + } + + const int yes = 1; + m_sock.setsockopt(ZMQ_CURVE_SERVER, + &yes, sizeof(yes)); + + m_sock.setsockopt(ZMQ_CURVE_SECRETKEY, + m_secretkey, CURVE_KEYLEN); + } + m_sock.connect(uri); +} + +void ZMQ::set_encoder_type(encoder_selection_t& enc, int bitrate) +{ + m_encoder = enc; + m_bitrate = bitrate; +} + +bool ZMQ::write_frame(const uint8_t *buf, size_t len) +{ + switch (m_encoder) { + case encoder_selection_t::fdk_dabplus: + return send_frame(buf, len); + case encoder_selection_t::toolame_dab: + return write_toolame(buf, len); + } + throw logic_error("Unhandled encoder in ZMQ::write_frame"); +} + +bool ZMQ::write_toolame(const uint8_t *buf, size_t len) +{ + m_toolame_buffer.insert(m_toolame_buffer.end(), + buf, buf + len); + + // ODR-DabMux expects frames of length 3*bitrate + const auto frame_len = 3 * m_bitrate; + while (m_toolame_buffer.size() > frame_len) { + vec_u8 frame(frame_len); + // this is probably not very efficient + std::copy(m_toolame_buffer.begin(), m_toolame_buffer.begin() + frame_len, frame.begin()); + + bool success = send_frame(frame.data(), frame.size()); + if (not success) { + return false; + } + + m_toolame_buffer.erase(m_toolame_buffer.begin(), m_toolame_buffer.begin() + frame_len); + } + return true; +} + +bool ZMQ::send_frame(const uint8_t *buf, size_t len) +{ + if (m_framebuf.size() != ZMQ_HEADER_SIZE + len) { + m_framebuf.resize(ZMQ_HEADER_SIZE + len); + } + + zmq_frame_header_t *zmq_frame_header = (zmq_frame_header_t*)m_framebuf.data(); + + try { + switch (m_encoder) { + case encoder_selection_t::fdk_dabplus: + zmq_frame_header->encoder = ZMQ_ENCODER_FDK; + break; + case encoder_selection_t::toolame_dab: + zmq_frame_header->encoder = ZMQ_ENCODER_TOOLAME; + break; + } + + zmq_frame_header->version = 1; + zmq_frame_header->datasize = len; + zmq_frame_header->audiolevel_left = m_audio_left; + zmq_frame_header->audiolevel_right = m_audio_right; + + assert(ZMQ_FRAME_SIZE(zmq_frame_header) <= m_framebuf.size()); + + memcpy(ZMQ_FRAME_DATA(zmq_frame_header), buf, len); + + m_sock.send(m_framebuf.data(), ZMQ_FRAME_SIZE(zmq_frame_header), + ZMQ_DONTWAIT); + } + catch (zmq::error_t& e) { + fprintf(stderr, "ZeroMQ send error !\n"); + return false; + } + + return true; +} + +} |