SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
rtpsink.cpp
Go to the documentation of this file.
1 // Copyright (C) 2018 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include "rtpsink.h"
20 #include "dsp/dsptypes.h"
21 #include <algorithm>
22 
23 RTPSink::RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo) :
24  m_payloadType(stereo ? RTPSink::PayloadL16Stereo : RTPSink::PayloadL16Mono),
25  m_sampleRate(sampleRate),
26  m_sampleBytes(0),
27  m_packetSamples(0),
28  m_bufferSize(0),
29  m_sampleBufferIndex(0),
30  m_byteBuffer(0),
31  m_destport(9998),
32  m_mutex(QMutex::Recursive)
33 {
35  m_rtpTransmissionParams.SetRTCPMultiplexing(true); // do not allocate another socket for RTCP
36  m_rtpTransmissionParams.SetUseExistingSockets(udpSocket, udpSocket);
37 
38  int status = m_rtpTransmitter.Init();
39  if (status < 0) {
40  qCritical("RTPSink::RTPSink: cannot initialize transmitter: %s", qrtplib::RTPGetErrorString(status).c_str());
41  m_valid = false;
42  } else {
43  qDebug("RTPSink::RTPSink: initialized transmitter: %s", qrtplib::RTPGetErrorString(status).c_str());
44  }
45 
47  qDebug("RTPSink::RTPSink: created transmitter: %s", qrtplib::RTPGetErrorString(status).c_str());
48 
50  if (status < 0) {
51  qCritical("RTPSink::RTPSink: cannot create session: %s", qrtplib::RTPGetErrorString(status).c_str());
52  m_valid = false;
53  } else {
54  qDebug("RTPSink::RTPSink: created session: %s", qrtplib::RTPGetErrorString(status).c_str());
55  }
56 
57  setPayloadInformation(m_payloadType, m_sampleRate);
58  m_valid = true;
59 
60  uint32_t endianTest32 = 1;
61  uint8_t *ptr = (uint8_t*) &endianTest32;
62  m_endianReverse = (*ptr == 1);
63 }
64 
66 {
67  qrtplib::RTPTime delay = qrtplib::RTPTime(10.0);
68  m_rtpSession.BYEDestroy(delay, "Time's up", 9);
69 
70  if (m_byteBuffer) {
71  delete[] m_byteBuffer;
72  }
73 }
74 
75 void RTPSink::setPayloadInformation(PayloadType payloadType, int sampleRate)
76 {
77  uint32_t timestampinc;
78  QMutexLocker locker(&m_mutex);
79 
80  qDebug("RTPSink::setPayloadInformation: payloadType: %d sampleRate: %d", payloadType, sampleRate);
81 
82  switch (payloadType)
83  {
84  case PayloadPCMA8:
85  m_sampleBytes = 1;
87  m_packetSamples = m_sampleRate / 50; // 20ms packet samples
88  timestampinc = m_sampleRate / 50; // 1 channel
89  break;
90  case PayloadPCMU8:
91  m_sampleBytes = 1;
93  m_packetSamples = m_sampleRate / 50; // 20ms packet samples
94  timestampinc = m_sampleRate / 50; // 1 channel
95  break;
96  case PayloadL8:
97  m_sampleBytes = 1;
99  m_packetSamples = m_sampleRate / 50; // 20ms packet samples
100  timestampinc = m_sampleRate / 50; // 1 channel
101  break;
102  case PayloadL16Stereo:
103  m_sampleBytes = 4;
105  m_packetSamples = m_sampleRate / 50; // 20ms packet samples
106  timestampinc = m_sampleRate / 100; // 2 channels
107  break;
108  case PayloadG722:
109  m_sampleBytes = 1;
111  m_packetSamples = 160; // Fixed 8 kB/s 20ms packet samples
112  timestampinc = 160; // 1 channel
113  break;
114  case PayloadOpus:
115  m_sampleBytes = 1;
117  m_packetSamples = 160; // Payload size is 160 bytes
118  timestampinc = 960; // But increment is 960
119  break;
120  case PayloadL16Mono:
121  default:
122  m_sampleBytes = 2;
124  m_packetSamples = m_sampleRate / 50; // 20ms packet samples
125  timestampinc = m_sampleRate / 50; // 1 channel
126  break;
127  }
128 
130 
131  if (m_byteBuffer) {
132  delete[] m_byteBuffer;
133  }
134 
137  m_payloadType = payloadType;
138 
139  int status = m_rtpSession.SetTimestampUnit(1.0 / (double) m_sampleRate);
140 
141  if (status < 0) {
142  qCritical("RTPSink::setPayloadInformation: cannot set timestamp unit: %s", qrtplib::RTPGetErrorString(status).c_str());
143  } else {
144  qDebug("RTPSink::setPayloadInformation: timestamp unit set to %f: %s",
145  1.0 / (double) m_sampleRate,
146  qrtplib::RTPGetErrorString(status).c_str());
147  }
148 
149  status = m_rtpSession.SetDefaultMark(false);
150 
151  if (status < 0) {
152  qCritical("RTPSink::setPayloadInformation: cannot set default mark: %s", qrtplib::RTPGetErrorString(status).c_str());
153  } else {
154  qDebug("RTPSink::setPayloadInformation: set default mark to false: %s", qrtplib::RTPGetErrorString(status).c_str());
155  }
156 
157  status = m_rtpSession.SetDefaultTimestampIncrement(timestampinc);
158 
159  if (status < 0) {
160  qCritical("RTPSink::setPayloadInformation: cannot set default timestamp increment: %s", qrtplib::RTPGetErrorString(status).c_str());
161  } else {
162  qDebug("RTPSink::setPayloadInformation: set default timestamp increment to %d: %s", timestampinc, qrtplib::RTPGetErrorString(status).c_str());
163  }
164 
165  int maximumPacketSize = m_bufferSize+20; // was +40
166 
167  while (maximumPacketSize < RTP_MINPACKETSIZE) {
168  maximumPacketSize += m_bufferSize;
169  }
170 
171  status = m_rtpSession.SetMaximumPacketSize(maximumPacketSize);
172 
173  if (status < 0) {
174  qCritical("RTPSink::setPayloadInformation: cannot set maximum packet size: %s", qrtplib::RTPGetErrorString(status).c_str());
175  } else {
176  qDebug("RTPSink::setPayloadInformation: set maximum packet size to %d bytes: %s", maximumPacketSize, qrtplib::RTPGetErrorString(status).c_str());
177  }
178 }
179 
180 void RTPSink::setDestination(const QString& address, uint16_t port)
181 {
184  m_destip.setAddress(address);
185  m_destport = port;
186 
188 
189  if (status < 0) {
190  qCritical("RTPSink::setDestination: cannot set destination address: %s", qrtplib::RTPGetErrorString(status).c_str());
191  }
192 }
193 
194 void RTPSink::deleteDestination(const QString& address, uint16_t port)
195 {
196  QHostAddress destip(address);
197 
198  int status = m_rtpSession.DeleteDestination(qrtplib::RTPAddress(destip, port));
199 
200  if (status < 0) {
201  qCritical("RTPSink::deleteDestination: cannot delete destination address: %s", qrtplib::RTPGetErrorString(status).c_str());
202  }
203 }
204 
205 void RTPSink::addDestination(const QString& address, uint16_t port)
206 {
207  QHostAddress destip(address);
208 
209  int status = m_rtpSession.AddDestination(qrtplib::RTPAddress(destip, port));
210 
211  if (status < 0) {
212  qCritical("RTPSink::addDestination: cannot add destination address: %s", qrtplib::RTPGetErrorString(status).c_str());
213  } else {
214  qDebug("RTPSink::addDestination: destination address set to %s:%d: %s",
215  address.toStdString().c_str(),
216  port,
217  qrtplib::RTPGetErrorString(status).c_str());
218  }
219 }
220 
221 void RTPSink::write(const uint8_t *sampleByte)
222 {
223  QMutexLocker locker(&m_mutex);
224 
226  {
228  sampleByte,
230  m_sampleBytes,
233  }
234  else
235  {
236  int status = m_rtpSession.SendPacket((const void *) m_byteBuffer, (std::size_t) m_bufferSize);
237 
238  if (status < 0) {
239  qCritical("RTPSink::write: cannot write packet: %s", qrtplib::RTPGetErrorString(status).c_str());
240  }
241 
242  writeNetBuf(&m_byteBuffer[0],
243  sampleByte,
248  }
249 }
250 
251 void RTPSink::write(const uint8_t *sampleByteL, const uint8_t *sampleByteR)
252 {
253  QMutexLocker locker(&m_mutex);
254 
256  {
258  sampleByteL,
260  m_sampleBytes,
263  sampleByteR,
265  m_sampleBytes,
268  }
269  else
270  {
271  int status = m_rtpSession.SendPacket((const void *) m_byteBuffer, (std::size_t) m_bufferSize);
272 
273  if (status < 0) {
274  qCritical("RTPSink::write: cannot write packet: %s", qrtplib::RTPGetErrorString(status).c_str());
275  }
276 
277  writeNetBuf(&m_byteBuffer[0], sampleByteL, elemLength(m_payloadType), m_sampleBytes, m_endianReverse);
278  writeNetBuf(&m_byteBuffer[2], sampleByteR, elemLength(m_payloadType), m_sampleBytes, m_endianReverse);
280  }
281 
282 }
283 
284 void RTPSink::write(const uint8_t *samples, int nbSamples)
285 {
286  int samplesIndex = 0;
287  QMutexLocker locker(&m_mutex);
288 
289  // fill remainder of buffer and send it
290  if (m_sampleBufferIndex + nbSamples > m_packetSamples)
291  {
293  &samples[samplesIndex*m_sampleBytes],
295  (m_packetSamples - m_sampleBufferIndex)*m_sampleBytes,
297  m_rtpSession.SendPacket((const void *) m_byteBuffer, (std::size_t) m_bufferSize);
298  nbSamples -= (m_packetSamples - m_sampleBufferIndex);
300  }
301 
302  // send complete packets
303  while (nbSamples > m_packetSamples)
304  {
306  samples,
308  m_bufferSize,
310  m_rtpSession.SendPacket((const void *) m_byteBuffer, (std::size_t) m_bufferSize);
311  samplesIndex += m_packetSamples;
312  nbSamples -= m_packetSamples;
313  }
314 
315  // copy remainder of input to buffer
317  &samples[samplesIndex*m_sampleBytes],
319  nbSamples*m_sampleBytes,m_endianReverse);
320 }
321 
322 void RTPSink::writeNetBuf(uint8_t *dest, const uint8_t *src, unsigned int elemLen, unsigned int bytesLen, bool endianReverse)
323 {
324  for (unsigned int i = 0; i < bytesLen; i += elemLen)
325  {
326  memcpy(&dest[i], &src[i], elemLen);
327 
328  if (endianReverse) {
329  std::reverse(&dest[i], &dest[i+elemLen]);
330  }
331  }
332 }
333 
334 unsigned int RTPSink::elemLength(PayloadType payloadType)
335 {
336  switch (payloadType)
337  {
338  case PayloadPCMA8:
339  case PayloadPCMU8:
340  case PayloadG722:
341  case PayloadOpus:
342  case PayloadL8:
343  return sizeof(int8_t);
344  break;
345  case PayloadL16Stereo:
346  case PayloadL16Mono:
347  default:
348  return sizeof(int16_t);
349  break;
350  }
351 }
352 
short int16_t
Definition: rtptypes_win.h:43
int SetMaximumPacketSize(std::size_t s)
Definition: rtpsession.cpp:835
void setDestination(const QString &address, uint16_t port)
Definition: rtpsink.cpp:180
int Create(const RTPSessionParams &sessparams, RTPTransmitter *transmitter)
Definition: rtpsession.cpp:145
std::size_t GetMaximumPacketSize() const
int m_bufferSize
Definition: rtpsink.h:77
void BYEDestroy(const RTPTime &maxwaittime, const void *reason, std::size_t reasonlength)
Definition: rtpsession.cpp:321
static void writeNetBuf(uint8_t *dest, const uint8_t *src, unsigned int elemLen, unsigned int bytesLen, bool endianReverse)
Definition: rtpsink.cpp:322
int DeleteDestination(const RTPAddress &addr)
Definition: rtpsession.cpp:422
PayloadType
Definition: rtpsink.h:42
qrtplib::RTPUDPTransmitter m_rtpTransmitter
Definition: rtpsink.h:85
int m_packetSamples
Definition: rtpsink.h:76
uint8_t * m_byteBuffer
Definition: rtpsink.h:79
void deleteDestination(const QString &address, uint16_t port)
Definition: rtpsink.cpp:194
virtual int Create(std::size_t maxpacksize, const RTPTransmissionParams *transparams)
unsigned int uint32_t
Definition: rtptypes_win.h:46
int AddDestination(const RTPAddress &addr)
Definition: rtpsession.cpp:415
uint16_t m_destport
Definition: rtpsink.h:81
#define RTP_MINPACKETSIZE
Definition: rtpdefines.h:39
unsigned char uint8_t
Definition: rtptypes_win.h:42
PayloadType m_payloadType
Definition: rtpsink.h:73
unsigned short uint16_t
Definition: rtptypes_win.h:44
int SetDefaultPayloadType(uint8_t pt)
Definition: rtpsession.cpp:608
int32_t i
Definition: decimators.h:244
char int8_t
Definition: rtptypes_win.h:41
RTPSink(QUdpSocket *udpSocket, int sampleRate, bool stereo)
Definition: rtpsink.cpp:23
int m_sampleBytes
Definition: rtpsink.h:75
int m_sampleRate
Definition: rtpsink.h:74
qrtplib::RTPSession m_rtpSession
Definition: rtpsink.h:82
void SetOwnTimestampUnit(double tsunit)
int SetDefaultTimestampIncrement(uint32_t timestampinc)
Definition: rtpsession.cpp:630
int SetTimestampUnit(double u)
Definition: rtpsession.cpp:881
bool m_endianReverse
Definition: rtpsink.h:86
void addDestination(const QString &address, uint16_t port)
Definition: rtpsink.cpp:205
void write(const uint8_t *sampleByte)
Definition: rtpsink.cpp:221
qrtplib::RTPUDPTransmissionParams m_rtpTransmissionParams
Definition: rtpsink.h:84
QHostAddress m_destip
Definition: rtpsink.h:80
qrtplib::RTPSessionParams m_rtpSessionParams
Definition: rtpsink.h:83
bool m_valid
Definition: rtpsink.h:72
QMutex m_mutex
Definition: rtpsink.h:87
int m_sampleBufferIndex
Definition: rtpsink.h:78
std::string RTPGetErrorString(int errcode)
Definition: rtperrors.cpp:248
void SetUseExistingSockets(QUdpSocket *rtpsocket, QUdpSocket *rtcpsocket)
static unsigned int elemLength(PayloadType payloadType)
Definition: rtpsink.cpp:334
int SendPacket(const void *data, std::size_t len)
Definition: rtpsession.cpp:457
~RTPSink()
Definition: rtpsink.cpp:65
int SetDefaultMark(bool m)
Definition: rtpsession.cpp:619
void setPayloadInformation(PayloadType payloadType, int sampleRate)
Definition: rtpsink.cpp:75