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 
19 extern "C" {
20 #include "libavcodec/avcodec.h"
21 #include "libavformat/avformat.h"
22 }
23 
24 class QTcpSocket;
25 class QUdpSocket;
26 class QTimer;
27 class AudioOutput;
28 class ServerPool;
29 class RaopNetStream;
30 
31 using RawHash = QHash<QString,QString>;
32 
33 struct AudioData
34 {
35  uint8_t *data;
36  int32_t length;
37  int32_t frames;
38 };
39 
41 {
43  QList<AudioData> *data;
44 };
45 
46 class 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;
124  QByteArray m_incomingContent;
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  QList<int> m_audioFormat;
156  int m_channels {2};
157  int m_sampleSize {16};
158  int m_frameRate {44100};
159  int m_framesPerPacket {352};
160  QTimer *m_dequeueAudioTimer {nullptr};
161 
162  QMap<std::chrono::milliseconds, AudioPacket> m_audioQueue;
163  uint32_t m_queueLength {0};
164  bool m_streamingStarted {false};
165  bool m_allowVolumeControl {true};
166 
167  // packet index, increase after each resend packet request
168  uint16_t m_seqNum {0};
169  // audio/packet sync
170  uint16_t m_lastSequence {0};
171  std::chrono::milliseconds m_lastTimestamp {0ms};
172  std::chrono::milliseconds m_currentTimestamp {0ms};
173  uint16_t m_nextSequence {0};
174  std::chrono::milliseconds m_nextTimestamp {0ms};
175  std::chrono::milliseconds m_bufferLength {0ms};
176  std::chrono::milliseconds m_timeLastSync {0ms};
177  std::chrono::milliseconds m_cardLatency {-1ms};
178  std::chrono::milliseconds m_adjustedLatency {-1ms};
179  bool m_audioStarted {false};
180 
181  // clock sync
182  std::chrono::milliseconds m_networkLatency {0ms};
183  // Difference in ms between reference. This value will typically
184  // be huge (~50 years)and meaningless as Apple products seem to
185  // only send uptimes, not wall times.
186  std::chrono::milliseconds m_clockSkew {0ms};
187 
188  // audio retry timer
189  QTimer *m_audioTimer {nullptr};
190 
191  //Current Stream Info
192  uint32_t m_progressStart {0};
193  uint32_t m_progressCurrent {0};
194  uint32_t m_progressEnd {0};
195  QByteArray m_artwork;
197 
198  //Authentication
199  QString m_nonce;
200 
201  // Notification Center registration Id
202  int m_id;
203  bool m_firstSend {false};
204  bool m_playbackStarted {false};
205 
206  private slots:
207  void ProcessAudio(void);
208 };
209 
210 #endif // MYTHRAOPCONNECTION_H
AudioPacket::data
QList< AudioData > * data
Definition: mythraopconnection.h:43
build_compdb.dest
dest
Definition: build_compdb.py:9
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
MythRAOPConnection::g_devPrivKey
static EVP_PKEY * g_devPrivKey
Definition: mythraopconnection.h:142
MythRAOPConnection::m_dataPort
int m_dataPort
Definition: mythraopconnection.h:129
MythRAOPConnection::m_resends
QMap< uint16_t, std::chrono::milliseconds > m_resends
Definition: mythraopconnection.h:139
MythRAOPConnection::m_eventClients
QList< QTcpSocket * > m_eventClients
Definition: mythraopconnection.h:136
MythRAOPConnection::GetSocket
QTcpSocket * GetSocket()
Definition: mythraopconnection.h:57
ServerPool
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:59
mythtvexp.h
build_compdb.content
content
Definition: build_compdb.py:38
AudioData::frames
int32_t frames
Definition: mythraopconnection.h:37
RaopNetStream
Definition: mythraopconnection.cpp:59
AudioData
Definition: mythraopconnection.h:33
MythRAOPConnection::m_artwork
QByteArray m_artwork
Definition: mythraopconnection.h:195
AudioPacket
Definition: mythraopconnection.h:40
RawHash
QHash< QString, QString > RawHash
Definition: mythraopconnection.h:31
AudioPacket::seq
uint16_t seq
Definition: mythraopconnection.h:42
MythRAOPConnection::GetDataPort
int GetDataPort() const
Definition: mythraopconnection.h:58
AudioOutput
Definition: audiooutput.h:26
AudioData::data
uint8_t * data
Definition: mythraopconnection.h:35
MythRAOPDevice
Definition: mythraopdevice.h:16
hardwareprofile.i18n.t
t
Definition: i18n.py:36
MythRAOPConnection::m_hardwareId
QByteArray m_hardwareId
Definition: mythraopconnection.h:122
MythRAOPConnection::m_nonce
QString m_nonce
Definition: mythraopconnection.h:199
MythRAOPConnection::m_dmap
DMAP m_dmap
Definition: mythraopconnection.h:196
MythRAOPConnection::m_incomingContent
QByteArray m_incomingContent
Definition: mythraopconnection.h:124
MythRAOPConnection::HasAudio
bool HasAudio()
Definition: mythraopconnection.h:59
AudioData::length
int32_t length
Definition: mythraopconnection.h:36
MythRAOPConnection::m_incomingHeaders
QStringList m_incomingHeaders
Definition: mythraopconnection.h:123
mythnotification.h
MythRAOPConnection::m_peerAddress
QHostAddress m_peerAddress
Definition: mythraopconnection.h:127
MythRAOPConnection::m_id
int m_id
Definition: mythraopconnection.h:202
MythRAOPConnection::m_aesIV
QByteArray m_aesIV
Definition: mythraopconnection.h:141
MTV_PUBLIC
#define MTV_PUBLIC
Definition: mythtvexp.h:15
MythRAOPConnection::m_sessionKey
std::vector< uint8_t > m_sessionKey
Definition: mythraopconnection.h:143
MythRAOPConnection::g_rsaLastError
static QString g_rsaLastError
Definition: mythraopconnection.h:150
MythRAOPConnection::RSALastError
static QString RSALastError(void)
Definition: mythraopconnection.h:62
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
MythRAOPConnection::m_audioQueue
QMap< std::chrono::milliseconds, AudioPacket > m_audioQueue
Definition: mythraopconnection.h:162
DMAP
QMap< QString, QString > DMAP
Definition: mythnotification.h:26
MythRAOPConnection
Definition: mythraopconnection.h:46
MythRAOPConnection::m_audioFormat
QList< int > m_audioFormat
Definition: mythraopconnection.h:155