summaryrefslogtreecommitdiffstats
path: root/src/Outputs.h
blob: 1211841a57de8deee2a625a72cf8d58a5f380792 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/* ------------------------------------------------------------------
 * Copyright (C) 2011 Martin Storsjo
 * 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.
 * -------------------------------------------------------------------
 */

#pragma once
#include <vector>
#include <chrono>
#include <deque>
#include <cstdint>
#include <cstddef>
#include <cstdio>
#include "common.h"
#include "zmq.hpp"
#include "ClockTAI.h"
#include "edi/TagItems.h"
#include "edi/TagPacket.h"
#include "edi/AFPacket.h"
#include "edi/Transport.h"
extern "C" {
#include "encryption.h"
}

namespace Output {

/*! \file Outputs.h
 *
 * Declaration of all outputs
 */

class Base {
    public:
        virtual ~Base() {};

        /*! Write a buffer of encoded data to the output */
        virtual bool write_frame(const uint8_t *buf, size_t len) = 0;

        /*! Update peak audio level information */
        virtual void update_audio_levels(
                int16_t audiolevel_left, int16_t audiolevel_right);

    protected:
        int16_t m_audio_left = 0;
        int16_t m_audio_right = 0;
};

class File : public Base {
    public:
        File(const char *filename);
        File(FILE *file);
        File(const File&) = delete;
        File& operator=(const File&) = delete;
        virtual ~File() override;

        virtual bool write_frame(const uint8_t *buf, size_t len) override;

    private:
        FILE *m_fd = nullptr;
};

/*! This defines the on-wire representation of a ZMQ message header.
 * It must be compatible with the definition in ODR-DabMux.
 *
 * The data follows right after this header */
struct zmq_frame_header_t
{
    uint16_t version; // we support version=1 now
    uint16_t encoder; // see ZMQ_ENCODER_XYZ

    /* length of the 'data' field */
    uint32_t datasize;

    /* Audio level, peak, linear PCM */
    int16_t audiolevel_left;
    int16_t audiolevel_right;

    /* Data follows this header */
} __attribute__ ((packed));

#define ZMQ_ENCODER_AACPLUS 1
#define ZMQ_ENCODER_MPEG_L2 2

#define ZMQ_HEADER_SIZE sizeof(struct zmq_frame_header_t)

/* The expected frame size incl data of the given frame */
#define ZMQ_FRAME_SIZE(f) (sizeof(struct zmq_frame_header_t) + f->datasize)

#define ZMQ_FRAME_DATA(f) ( ((uint8_t*)f)+sizeof(struct zmq_frame_header_t) )


class ZMQ: public Base {
    public:
        ZMQ();
        ZMQ(const ZMQ&) = delete;
        ZMQ& operator=(const ZMQ&) = delete;
        virtual ~ZMQ() override;

        void connect(const char *uri, const char *keyfile);
        void set_encoder_type(encoder_selection_t& enc, int bitrate);

        virtual bool write_frame(const uint8_t *buf, size_t len) override;

    private:
        zmq::context_t m_ctx;
        zmq::socket_t m_sock;

        int m_bitrate = 0;
        char m_secretkey[CURVE_KEYLEN+1];
        encoder_selection_t m_encoder = encoder_selection_t::fdk_dabplus;
        using vec_u8 = std::vector<uint8_t>;
        vec_u8 m_framebuf;
};


class EDI: public Base {
    public:
        EDI();
        EDI(const EDI&) = delete;
        EDI& operator=(const EDI&) = delete;
        virtual ~EDI() override;

        void set_odr_version_tag(const std::string& odr_version_tag);

        void add_udp_destination(const std::string& host, unsigned int port);
        void add_tcp_destination(const std::string& host, unsigned int port);

        void set_tist(bool enable, uint32_t delay_ms);

        bool enabled() const;

        virtual bool write_frame(const uint8_t *buf, size_t len) override;

    private:
        std::string m_odr_version_tag;

        edi::configuration_t m_edi_conf;
        std::shared_ptr<edi::Sender> m_edi_sender;

        uint32_t m_timestamp = 0;
        uint32_t m_num_seconds_sent = 0;
        std::time_t m_edi_time = 0;
        std::time_t m_send_version_at_time = 0;

        edi::TagDSTI m_edi_tagDSTI;

        ClockTAI m_clock_tai;
        bool m_tist = false;
        uint32_t m_delay_ms = 0;
};

}