MythTV master
mythraopconnection.h
Go to the documentation of this file.
1#ifndef MYTHRAOPCONNECTION_H
2#define MYTHRAOPCONNECTION_H
3
4#include <QObject>
5#include <QMap>
6#include <QHash>
7#include <QHostAddress>
8#include <QStringList>
9
10#include <openssl/rsa.h>
11#include <openssl/pem.h>
12#include <openssl/aes.h>
13#include <openssl/err.h>
14
15#include "libmythtv/mythtvexp.h"
16
18
19extern "C" {
20#include "libavcodec/avcodec.h"
21#include "libavformat/avformat.h"
22}
23
24class QTcpSocket;
25class QUdpSocket;
26class QTimer;
27class AudioOutput;
28class ServerPool;
29class RaopNetStream;
30
31using RawHash = QHash<QString,QString>;
32
34{
35 uint8_t *data;
36 int32_t length;
37 int32_t frames;
38};
39
41{
43 QList<AudioData> *data;
44};
45
46class MTV_PUBLIC MythRAOPConnection : public QObject
47{
48 Q_OBJECT
49
50 friend class MythRAOPDevice;
51
52 public:
53 MythRAOPConnection(QObject *parent, QTcpSocket *socket, QByteArray id,
54 int port);
55 ~MythRAOPConnection() override;
56 bool Init(void);
57 QTcpSocket *GetSocket() { return m_socket; }
58 int GetDataPort() const { return m_dataPort; }
59 bool HasAudio() { return m_audio; }
60 static QMap<QString,QString> decodeDMAP(const QByteArray &dmap);
61 static bool LoadKey(void);
62 static QString RSALastError(void) { return g_rsaLastError; }
63
64 private slots:
65 void readClient(void);
66 void udpDataReady(QByteArray buf, const QHostAddress& peer, quint16 port);
67 void timeout(void);
68 void audioRetry(void);
69 void newEventClient(QTcpSocket *client);
70 void deleteEventClient();
71
72 private:
73 void ProcessSync(const QByteArray &buf);
74 void SendResendRequest(std::chrono::milliseconds timestamp,
75 uint16_t expected, uint16_t got);
76 void ExpireResendRequests(std::chrono::milliseconds timestamp);
77 uint32_t decodeAudioPacket(uint8_t type, const QByteArray *buf,
78 QList<AudioData> *dest);
79 int ExpireAudio(std::chrono::milliseconds timestamp);
80 void ResetAudio(void);
81 void ProcessRequest(const QStringList &header,
82 const QByteArray &content);
83 static void FinishResponse(RaopNetStream *stream, QTcpSocket *socket,
84 QString &option, QString &cseq, QString &responseData);
85 void FinishAuthenticationResponse(RaopNetStream *stream, QTcpSocket *socket,
86 QString &cseq);
87
88 static RawHash FindTags(const QStringList &lines);
89 bool CreateDecoder(void);
90 void DestroyDecoder(void);
91 bool OpenAudioDevice(void);
92 void CloseAudioDevice(void);
93 void StartAudioTimer(void);
94 void StopAudioTimer(void);
95 void CleanUp(void);
96
97 // time sync
98 void SendTimeRequest(void);
99 void ProcessTimeResponse(const QByteArray &buf);
100 static std::chrono::milliseconds NTPToLocal(uint32_t sec, uint32_t ticks);
101 static void microsecondsToNTP(std::chrono::microseconds usec, uint32_t &ntpSec, uint32_t &ntpTicks);
102 static void timevalToNTP(timeval t, uint32_t &ntpSec, uint32_t &ntpTicks);
103
104 // incoming data packet
105 static bool GetPacketType(const QByteArray &buf, uint8_t &type,
106 uint16_t &seq, uint64_t &timestamp);
107
108 // utility functions
109 std::chrono::milliseconds AudioCardLatency(void);
110 static QStringList splitLines(const QByteArray &lines);
111 static QString stringFromSeconds(int timeInSeconds);
112 std::chrono::milliseconds framesToMs(uint64_t frames) const;
113 uint64_t MsToFrame(std::chrono::milliseconds millis) const;
114
115 // notification functions
116 void SendNotification(bool update = false);
117
118 QTimer *m_watchdogTimer {nullptr};
119 // comms socket
120 QTcpSocket *m_socket {nullptr};
121 RaopNetStream *m_textStream {nullptr};
122 QByteArray m_hardwareId;
123 QStringList m_incomingHeaders;
125 bool m_incomingPartial {false};
126 int32_t m_incomingSize {0};
127 QHostAddress m_peerAddress;
128 ServerPool *m_dataSocket {nullptr};
130 ServerPool *m_clientControlSocket {nullptr};
131 int m_clientControlPort {0};
132 ServerPool *m_clientTimingSocket {nullptr};
133 int m_clientTimingPort {0};
134 ServerPool *m_eventServer {nullptr};
135 int m_eventPort {-1};
136 QList<QTcpSocket *> m_eventClients;
137
138 // incoming audio
139 QMap<uint16_t,std::chrono::milliseconds> m_resends;
140 // crypto
141 QByteArray m_aesIV;
142 static EVP_PKEY *g_devPrivKey;
143 std::vector<uint8_t> m_sessionKey;
144#if OPENSSL_VERSION_NUMBER < 0x030000000L
145 const EVP_CIPHER *m_cipher {nullptr};
146#else
147 EVP_CIPHER *m_cipher {nullptr};
148#endif
149 EVP_CIPHER_CTX *m_cctx {nullptr};
150 static QString g_rsaLastError;
151 // audio out
152 AudioOutput *m_audio {nullptr};
153 const AVCodec *m_codec {nullptr};
154 AVCodecContext *m_codecContext {nullptr};
155
156 QList<int> m_audioFormat;
157 //< For Apple Lossless streams, this data is passed as a series of
158 // 12 integers. Note: this is the format of the stream between
159 // sender and receiver, not the format of the file being played.
160 // An MP3 file is sent as an ALAC stream.
161 //
162 // 0: stream number (matches a=rtpmap:XX)
163 // 1: frameLength - default frames per packet
164 // 2: compatibleVersion (must be 0)
165 // 3: bitDepth (max 32)
166 // 4: pb (should be 40)
167 // 5: mb (should be 10)
168 // 6: kb (should be 14)
169 // 7: numChannels
170 // 8: maxRun (unused, set to 255)
171 // 9: maxFrameBytes (0 is unknown)
172 // 10: avgBitRate (0 is unknown)
173 // 11: sampleRate
174 //
175 // Example:
176 // a=fmtp:96 352 0 16 40 10 14 2 255 0 0 44100
177 //
178 // See https://github.com/macosforge/alac/blob/c38887c5c5e64a4b31108733bd79ca9b2496d987/ALACMagicCookieDescription.txt#L48
179
180 int m_channels {2};
181 int m_sampleSize {16};
182 int m_frameRate {44100};
183 int m_framesPerPacket {352};
184 QTimer *m_dequeueAudioTimer {nullptr};
185
186 QMap<std::chrono::milliseconds, AudioPacket> m_audioQueue;
187 uint32_t m_queueLength {0};
188 bool m_streamingStarted {false};
189 bool m_allowVolumeControl {true};
190
191 // packet index, increase after each resend packet request
192 uint16_t m_seqNum {0};
193 // audio/packet sync
194 uint16_t m_lastSequence {0};
195 std::chrono::milliseconds m_lastTimestamp {0ms};
196 std::chrono::milliseconds m_currentTimestamp {0ms};
197 uint16_t m_nextSequence {0};
198 std::chrono::milliseconds m_nextTimestamp {0ms};
199 std::chrono::milliseconds m_bufferLength {0ms};
200 std::chrono::milliseconds m_timeLastSync {0ms};
201 std::chrono::milliseconds m_cardLatency {-1ms};
202 std::chrono::milliseconds m_adjustedLatency {-1ms};
203 bool m_audioStarted {false};
204
205 // clock sync
206 std::chrono::milliseconds m_networkLatency {0ms};
207 // Difference in ms between reference. This value will typically
208 // be huge (~50 years)and meaningless as Apple products seem to
209 // only send uptimes, not wall times.
210 std::chrono::milliseconds m_clockSkew {0ms};
211
212 // audio retry timer
213 QTimer *m_audioTimer {nullptr};
214
215 //Current Stream Info
216 uint32_t m_progressStart {0};
217 uint32_t m_progressCurrent {0};
218 uint32_t m_progressEnd {0};
219 QByteArray m_artwork;
221
222 //Authentication
223 QString m_nonce;
224
225 // Notification Center registration Id
226 int m_id;
227 bool m_firstSend {false};
228 bool m_playbackStarted {false};
229
230 private slots:
231 void ProcessAudio(void);
232};
233
234#endif // MYTHRAOPCONNECTION_H
QList< int > m_audioFormat
QHostAddress m_peerAddress
QMap< uint16_t, std::chrono::milliseconds > m_resends
static EVP_PKEY * g_devPrivKey
QStringList m_incomingHeaders
QMap< std::chrono::milliseconds, AudioPacket > m_audioQueue
static QString RSALastError(void)
QList< QTcpSocket * > m_eventClients
QTcpSocket * GetSocket()
std::vector< uint8_t > m_sessionKey
static QString g_rsaLastError
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:60
unsigned short uint16_t
Definition: iso6937tables.h:3
QMap< QString, QString > DMAP
QHash< QString, QString > RawHash
#define MTV_PUBLIC
Definition: mythtvexp.h:15
uint8_t * data
QList< AudioData > * data