summaryrefslogtreecommitdiffstats
path: root/src/AVTEDIInput.h
blob: 4ec608668d9857c587a52ac6ae7664859432fdf1 (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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* ------------------------------------------------------------------
 * Copyright (C) 2017 AVT GmbH - Fabien Vercasson
 *
 * 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.
 * -------------------------------------------------------------------
 */
 
 
/*! \section AVT Input
 *
 * Extract audio frame from EDI frames produced by AVT encoder.
 *
 * The EDI frames are not special, it is just assumed that the audio is transported
 * into the first stream.
 *
 * PFT with spreaded packets is supported.	TODO
 * Error correction is applied			TODO
 * AF without PFT supported			TODO
 * Resend not supported
 * 
 * ref: ETSI TS 102 821 V1.4.1
 *      ETSI TS 102 693 V1.1.2
 */

#ifndef _AVT_EDI_INPUT_
#define _AVT_EDI_INPUT_

#include <stdint.h>
#include <stdio.h>
#include <string>
#include <map>
#include <vector>
#include <chrono>

class OrderedQueue;
class PFTFrag;
class PFT;
class EDISubCh;

/* ------------------------------------------------------------------
 *
 */
class AVTEDIInput
{
    public:
        /*\param fragmentTimeoutMs How long to wait for all fragment before applying FEC or dropping old frames*/
        AVTEDIInput(uint32_t fragmentTimeoutMs = 120);
        ~AVTEDIInput();

        /*! Push new data to edi decoder
         * \return false is data is not EDI
         */
        bool pushData(uint8_t* buf, size_t length);
        
        /*! Give next available audio frame from EDI
         * \return The size of the buffer. 0 if not data available
         */
        size_t popFrame(std::vector<uint8_t>& data, int32_t& frameNumber);

    private:
        uint32_t _fragmentTimeoutMs;
        std::map<int, PFT*>  _pft;
        typedef std::map<int, PFT*>::iterator PFTIterator;
        
        OrderedQueue*   _subChannelQueue;

        bool _pushPFTFrag(uint8_t* buf, size_t length);
        bool _pushAF(uint8_t* buf, size_t length, bool checked);
};

/* ------------------------------------------------------------------
 *
 */
class PFTFrag
{
    public:
        PFTFrag(uint8_t* buf, size_t length);
        ~PFTFrag();
        
        inline bool isValid() { return _valid; }
        inline uint32_t Pseq() { return _Pseq; }
        inline uint32_t Findex() { return _Findex; }
        inline uint32_t Fcount() { return _Fcount; }
        inline uint32_t FEC() { return _FEC; }
        inline uint32_t Plen() { return _Plen; }
        inline uint32_t RSk() { return _RSk; }
        inline uint32_t RSz() { return _RSz; }
        inline uint8_t* payload() { return _payload.data(); }
        inline const std::vector<uint8_t>& payloadVector()
            { return _payload; }

    private:
        std::vector<uint8_t> _payload;

        uint32_t _Pseq;
        uint32_t _Findex;
        uint32_t _Fcount;
        uint32_t _FEC;
        uint32_t _Addr;
        uint32_t _Plen;
        uint32_t _RSk;
        uint32_t _RSz;
        uint32_t _Source;
        uint32_t _Dest;
        bool _valid;
        
        bool _parse(uint8_t* buf, size_t length);       
};

/* ------------------------------------------------------------------
 *
 */
class PFT
{
    public:
        PFT(uint32_t Pseq, uint32_t Fcount);
        ~PFT();

        /*! the given frag belongs to the PFT class,
         *! it will be deleted by the class */
        void pushPFTFrag(PFTFrag* frag);

        /* \return true if all framgnements are received*/
        bool complete();
        
        /*! try to build the AF with received fragments.
         *! Apply error correction if necessary (missing packets/CRC errors)
         * \return true if the AF is completed
         */
        bool extractAF(std::vector<uint8_t>& afdata);  
        
        inline std::chrono::steady_clock::time_point creation()
            { return _creation; }

    private:
        PFTFrag** _frags;
        uint32_t _Pseq;
        uint32_t _Fcount;
        uint32_t _Plen;
        uint32_t _nbFrag;
        uint32_t _RSk;
        uint32_t _RSz;
        uint32_t _cmax;
        uint32_t _rxmin;

        std::chrono::steady_clock::time_point _creation;  
        
        bool _canAttemptToDecode();
        
        static void* _rs_handler;
        static void _initRSDecoder();
};

/* ------------------------------------------------------------------
 *
 */
class EDISubCh {
    public:
        EDISubCh(uint8_t* buf, size_t length);
        ~EDISubCh();

        inline uint32_t frameCount() { return _frameCount; }
        inline uint8_t* payload() { return _payload.data(); }
        inline const std::vector<uint8_t>& payloadVector()
            { return _payload; }

    private:
        uint32_t _frameCount;
        std::vector<uint8_t> _payload;
};

#endif // _AVT_EDI_INPUT_