-
Notifications
You must be signed in to change notification settings - Fork 241
Expand file tree
/
Copy pathchannel.cpp
More file actions
746 lines (635 loc) · 26.2 KB
/
channel.cpp
File metadata and controls
746 lines (635 loc) · 26.2 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
/******************************************************************************\
* Copyright (c) 2004-2024
*
* Author(s):
* Volker Fischer
*
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
\******************************************************************************/
#include "channel.h"
// CChannel implementation *****************************************************
CChannel::CChannel ( const bool bNIsServer ) :
vecfGains ( MAX_NUM_CHANNELS, 1.0f ),
vecfPannings ( MAX_NUM_CHANNELS, 0.5f ),
iCurSockBufNumFrames ( INVALID_INDEX ),
bDoAutoSockBufSize ( true ),
bUseSequenceNumber ( false ), // this is important since in the client we reset on Channel.SetEnable ( false )
iSendSequenceNumber ( 0 ),
iFadeInCnt ( 0 ),
iFadeInCntMax ( FADE_IN_NUM_FRAMES_DBLE_FRAMESIZE ),
bIsEnabled ( false ),
bIsServer ( bNIsServer ),
bIsIdentified ( false ),
bDisconnectAndDisable ( false ),
iAudioFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ),
SignalLevelMeter ( false, 0.5 ) // server mode with mono out and faster smoothing
{
// reset network transport properties
ResetNetworkTransportProperties();
// initial value for connection time out counter, we calculate the total
// number of samples here and subtract the number of samples of the block
// which we take out of the buffer to be independent of block sizes
iConTimeOutStartVal = CON_TIME_OUT_SEC_MAX * SYSTEM_SAMPLE_RATE_HZ;
// init time-out for the buffer with zero -> no connection
iConTimeOut = 0;
// init the socket buffer
SetSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL );
// initialize channel info
ResetInfo();
// Connections -------------------------------------------------------------
//### TODO: BEGIN ###//
// if we later do not fire vectors in the emits, we can remove this again
qRegisterMetaType<CVector<uint8_t>> ( "CVector<uint8_t>" );
qRegisterMetaType<CHostAddress> ( "CHostAddress" );
//### TODO: END ###//
QObject::connect ( &Protocol, &CProtocol::MessReadyForSending, this, &CChannel::OnSendProtMessage );
QObject::connect ( &Protocol, &CProtocol::ChangeJittBufSize, this, &CChannel::OnJittBufSizeChange );
QObject::connect ( &Protocol, &CProtocol::ReqJittBufSize, this, &CChannel::ReqJittBufSize );
QObject::connect ( &Protocol, &CProtocol::ReqChanInfo, this, &CChannel::ReqChanInfo );
QObject::connect ( &Protocol, &CProtocol::ReqConnClientsList, this, &CChannel::ReqConnClientsList );
QObject::connect ( &Protocol, &CProtocol::ConClientListMesReceived, this, &CChannel::ConClientListMesReceived );
QObject::connect ( &Protocol, &CProtocol::ChangeChanGain, this, &CChannel::OnChangeChanGain );
QObject::connect ( &Protocol, &CProtocol::ChangeChanPan, this, &CChannel::OnChangeChanPan );
QObject::connect ( &Protocol, &CProtocol::ClientIDReceived, this, &CChannel::ClientIDReceived );
QObject::connect ( &Protocol, &CProtocol::MuteStateHasChangedReceived, this, &CChannel::MuteStateHasChangedReceived );
QObject::connect ( &Protocol, &CProtocol::ChangeChanInfo, this, &CChannel::OnChangeChanInfo );
QObject::connect ( &Protocol, &CProtocol::ChatTextReceived, this, &CChannel::ChatTextReceived );
QObject::connect ( &Protocol, &CProtocol::NetTranspPropsReceived, this, &CChannel::OnNetTranspPropsReceived );
QObject::connect ( &Protocol, &CProtocol::ReqNetTranspProps, this, &CChannel::OnReqNetTranspProps );
QObject::connect ( &Protocol, &CProtocol::ReqSplitMessSupport, this, &CChannel::OnReqSplitMessSupport );
QObject::connect ( &Protocol, &CProtocol::SplitMessSupported, this, &CChannel::OnSplitMessSupported );
QObject::connect ( &Protocol, &CProtocol::LicenceRequired, this, &CChannel::LicenceRequired );
QObject::connect ( &Protocol, &CProtocol::VersionAndOSReceived, this, &CChannel::OnVersionAndOSReceived );
QObject::connect ( &Protocol, &CProtocol::RecorderStateReceived, this, &CChannel::RecorderStateReceived );
}
bool CChannel::ProtocolIsEnabled()
{
// for the server, only enable protocol if the channel is connected, i.e.,
// successfully audio packets are received from a client
// for the client, enable protocol if the channel is enabled, i.e., the
// connection button was hit by the user
if ( bIsServer )
{
return IsConnected();
}
else
{
return bIsEnabled;
}
}
void CChannel::SetEnable ( const bool bNEnStat )
{
QMutexLocker locker ( &Mutex );
// set internal parameter
bIsEnabled = bNEnStat;
bDisconnectAndDisable = false;
// The support for the packet sequence number must be reset if the client
// disconnects from a server since we do not yet know if the next server we
// connect to will support the sequence number. We use the SetEnable call in
// the client for this task since at every start/stop it will call this
// function. NOTE that it is important to reset this parameter on SetEnable(false)
// since the SetEnable(true) is set AFTER the Init() in the client -> we
// simply set it regardless of the state which does not hurt.
bUseSequenceNumber = false;
// if channel is not enabled, reset time out count and protocol
if ( !bNEnStat )
{
iConTimeOut = 0;
Protocol.Reset();
}
}
void CChannel::OnVersionAndOSReceived ( COSUtil::EOpSystemType eOSType, QString strVersion )
{
// check if audio packet counter is supported by the server (minimum version is 3.6.0)
#if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 )
if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 6, 0 ) ) >= 0 )
{
// activate sequence counter and update the audio stream properties (which
// does all the initialization and tells the server about the change)
bUseSequenceNumber = true;
SetAudioStreamProperties ( eAudioCompressionType, iCeltNumCodedBytes, iNetwFrameSizeFact, iNumAudioChannels );
}
#endif
emit VersionAndOSReceived ( eOSType, strVersion );
}
void CChannel::SetAudioStreamProperties ( const EAudComprType eNewAudComprType,
const int iNewCeltNumCodedBytes,
const int iNewNetwFrameSizeFact,
const int iNewNumAudioChannels )
{
/*
this function is intended for the client (not the server)
*/
CNetworkTransportProps NetworkTransportProps;
Mutex.lock();
{
// store new values
eAudioCompressionType = eNewAudComprType;
iNumAudioChannels = iNewNumAudioChannels;
iCeltNumCodedBytes = iNewCeltNumCodedBytes;
iNetwFrameSizeFact = iNewNetwFrameSizeFact;
// add the size of the optional packet counter
if ( bUseSequenceNumber )
{
iNetwFrameSize = iCeltNumCodedBytes + 1; // per definition 1 byte counter
}
else
{
iNetwFrameSize = iCeltNumCodedBytes;
}
// update audio frame size
if ( eAudioCompressionType == CT_OPUS )
{
iAudioFrameSizeSamples = DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES;
}
else
{
iAudioFrameSizeSamples = SYSTEM_FRAME_SIZE_SAMPLES;
}
MutexSocketBuf.lock();
{
// init socket buffer
SockBuf.SetUseDoubleSystemFrameSize ( eAudioCompressionType == CT_OPUS ); // NOTE must be set BEFORE the init()
SockBuf.Init ( iCeltNumCodedBytes, iCurSockBufNumFrames, bUseSequenceNumber );
}
MutexSocketBuf.unlock();
MutexConvBuf.lock();
{
// init conversion buffer
ConvBuf.Init ( iNetwFrameSize * iNetwFrameSizeFact, bUseSequenceNumber );
}
MutexConvBuf.unlock();
// fill network transport properties struct
NetworkTransportProps = GetNetworkTransportPropsFromCurrentSettings();
}
Mutex.unlock();
// tell the server about the new network settings
Protocol.CreateNetwTranspPropsMes ( NetworkTransportProps );
}
bool CChannel::SetSockBufNumFrames ( const int iNewNumFrames, const bool bPreserve )
{
bool ReturnValue = true; // init with error
bool bCurDoAutoSockBufSize = false; // we have to init but init values does not matter
// first check for valid input parameter range
if ( ( iNewNumFrames >= MIN_NET_BUF_SIZE_NUM_BL ) && ( iNewNumFrames <= MAX_NET_BUF_SIZE_NUM_BL ) )
{
// only apply parameter if new parameter is different from current one
if ( iCurSockBufNumFrames != iNewNumFrames )
{
MutexSocketBuf.lock();
{
// store new value
iCurSockBufNumFrames = iNewNumFrames;
// the network block size is a multiple of the minimum network
// block size
SockBuf.Init ( iCeltNumCodedBytes, iNewNumFrames, bUseSequenceNumber, bPreserve );
// store current auto socket buffer size setting in the mutex
// region since if we use the current parameter below in the
// if condition, it may have been changed in between the time
// when we have left the mutex region and entered the if
// condition
bCurDoAutoSockBufSize = bDoAutoSockBufSize;
ReturnValue = false; // -> no error
}
MutexSocketBuf.unlock();
}
}
// only in case there is no error, we are the server and auto jitter buffer
// setting is enabled, we have to report the current setting to the client
if ( !ReturnValue && bIsServer && bCurDoAutoSockBufSize )
{
// we cannot call the "CreateJitBufMes" function directly since
// this would give us problems with different threads (e.g. the
// timer thread) and the protocol mechanism (problem with
// qRegisterMetaType(), etc.)
emit ServerAutoSockBufSizeChange ( iNewNumFrames );
}
return ReturnValue; // set error flag
}
void CChannel::SetGain ( const int iChanID, const float fNewGain )
{
QMutexLocker locker ( &Mutex );
// set value (make sure channel ID is in range)
if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
{
// signal mute change
if ( ( vecfGains[iChanID] == 0 ) && ( fNewGain > 0 ) )
{
emit MuteStateHasChanged ( iChanID, false );
}
if ( ( vecfGains[iChanID] > 0 ) && ( fNewGain == 0 ) )
{
emit MuteStateHasChanged ( iChanID, true );
}
vecfGains[iChanID] = fNewGain;
}
}
float CChannel::GetGain ( const int iChanID )
{
QMutexLocker locker ( &Mutex );
// get value (make sure channel ID is in range)
if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
{
return vecfGains[iChanID];
}
else
{
return 0;
}
}
void CChannel::SetPan ( const int iChanID, const float fNewPan )
{
QMutexLocker locker ( &Mutex );
// set value (make sure channel ID is in range)
if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
{
vecfPannings[iChanID] = fNewPan;
}
}
float CChannel::GetPan ( const int iChanID )
{
QMutexLocker locker ( &Mutex );
// get value (make sure channel ID is in range)
if ( ( iChanID >= 0 ) && ( iChanID < MAX_NUM_CHANNELS ) )
{
return vecfPannings[iChanID];
}
else
{
return 0;
}
}
void CChannel::SetChanInfo ( const CChannelCoreInfo& NChanInf )
{
// apply value (if a new channel or different from previous one)
if ( !bIsIdentified || ChannelInfo != NChanInf )
{
bIsIdentified = true; // Indicate we have received channel info
ChannelInfo = NChanInf;
// fire message that the channel info has changed
emit ChanInfoHasChanged();
}
}
QString CChannel::GetName()
{
// make sure the string is not written at the same time when it is
// read here -> use mutex to secure access
QMutexLocker locker ( &Mutex );
return ChannelInfo.strName;
}
void CChannel::OnSendProtMessage ( CVector<uint8_t> vecMessage )
{
// only send messages if protocol is enabled, otherwise delete complete
// queue
if ( ProtocolIsEnabled() )
{
// emit message to actually send the data
emit MessReadyForSending ( vecMessage );
}
else
{
// delete send message queue
Protocol.Reset();
}
}
void CChannel::OnJittBufSizeChange ( int iNewJitBufSize )
{
// for server apply setting, for client emit message
if ( bIsServer )
{
// first check for special case: auto setting
if ( iNewJitBufSize == AUTO_NET_BUF_SIZE_FOR_PROTOCOL )
{
SetDoAutoSockBufSize ( true );
}
else
{
// manual setting is received, turn OFF auto setting and apply new value
SetDoAutoSockBufSize ( false );
SetSockBufNumFrames ( iNewJitBufSize, true );
}
}
else
{
emit JittBufSizeChanged ( iNewJitBufSize );
}
}
void CChannel::OnChangeChanGain ( int iChanID, float fNewGain ) { SetGain ( iChanID, fNewGain ); }
void CChannel::OnChangeChanPan ( int iChanID, float fNewPan ) { SetPan ( iChanID, fNewPan ); }
void CChannel::OnChangeChanInfo ( CChannelCoreInfo ChanInfo ) { SetChanInfo ( ChanInfo ); }
void CChannel::OnNetTranspPropsReceived ( CNetworkTransportProps NetworkTransportProps )
{
// only the server shall act on network transport properties message
if ( bIsServer )
{
// OPUS and OPUS64 codecs are the only supported codecs right now
if ( ( NetworkTransportProps.eAudioCodingType != CT_OPUS ) && ( NetworkTransportProps.eAudioCodingType != CT_OPUS64 ) )
{
Protocol.CreateOpusSupportedMes();
return;
}
Mutex.lock();
{
// store received parameters
eAudioCompressionType = NetworkTransportProps.eAudioCodingType;
iNumAudioChannels = static_cast<int> ( NetworkTransportProps.iNumAudioChannels );
iNetwFrameSizeFact = NetworkTransportProps.iBlockSizeFact;
iNetwFrameSize = static_cast<int> ( NetworkTransportProps.iBaseNetworkPacketSize );
bUseSequenceNumber = ( NetworkTransportProps.eFlags == NF_WITH_COUNTER );
if ( bUseSequenceNumber )
{
iCeltNumCodedBytes = iNetwFrameSize - 1; // per definition 1 byte counter
}
else
{
iCeltNumCodedBytes = iNetwFrameSize;
}
// update maximum number of frames for fade in counter (only needed for server)
// and audio frame size
if ( eAudioCompressionType == CT_OPUS )
{
iFadeInCntMax = FADE_IN_NUM_FRAMES_DBLE_FRAMESIZE / iNetwFrameSizeFact;
iAudioFrameSizeSamples = DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES;
}
else
{
iFadeInCntMax = FADE_IN_NUM_FRAMES / iNetwFrameSizeFact;
iAudioFrameSizeSamples = SYSTEM_FRAME_SIZE_SAMPLES;
}
// the fade-in counter maximum value may have changed, make sure the fade-in counter
// is not larger than the allowed maximum value
iFadeInCnt = std::min ( iFadeInCnt, iFadeInCntMax );
MutexSocketBuf.lock();
{
// update socket buffer (the network block size is a multiple of the
// minimum network frame size)
SockBuf.SetUseDoubleSystemFrameSize ( eAudioCompressionType == CT_OPUS ); // NOTE must be set BEFORE the init()
SockBuf.Init ( iCeltNumCodedBytes, iCurSockBufNumFrames, bUseSequenceNumber );
}
MutexSocketBuf.unlock();
MutexConvBuf.lock();
{
// init conversion buffer
ConvBuf.Init ( iNetwFrameSize * iNetwFrameSizeFact, bUseSequenceNumber );
}
MutexConvBuf.unlock();
}
Mutex.unlock();
}
}
void CChannel::OnReqNetTranspProps()
{
// fill network transport properties struct from current settings and send it
Protocol.CreateNetwTranspPropsMes ( GetNetworkTransportPropsFromCurrentSettings() );
}
void CChannel::OnReqSplitMessSupport()
{
// activate split messages in our protocol (client) and return answer message to the server
Protocol.SetSplitMessageSupported ( true );
Protocol.CreateSplitMessSupportedMes();
}
CNetworkTransportProps CChannel::GetNetworkTransportPropsFromCurrentSettings()
{
// set network flags
ENetwFlags eFlags = NF_NONE;
if ( bUseSequenceNumber )
{
eFlags = NF_WITH_COUNTER;
}
// use current stored settings of the channel to fill the network transport
// properties structure
return CNetworkTransportProps ( static_cast<uint32_t> ( iNetwFrameSize ),
static_cast<uint16_t> ( iNetwFrameSizeFact ),
static_cast<uint32_t> ( iNumAudioChannels ),
SYSTEM_SAMPLE_RATE_HZ,
eAudioCompressionType,
eFlags,
0 );
}
void CChannel::Disconnect()
{
// we only have to disconnect the channel if it is actually connected
if ( IsConnected() )
{
// set time out counter to a small value > 0 so that the next time a
// received audio block is queried, the disconnection is performed
// (assuming that no audio packet is received in the meantime)
iConTimeOut = 1; // a small number > 0
}
if ( !bIsServer )
{
if ( IsConnected() )
{
// for a Client, block further audio data and disable the channel as soon as Disconnect() is called
// TODO: Add reasoning from #2550
bDisconnectAndDisable = true;
}
else
{
// For disconnected clients set defaults
bDisconnectAndDisable = false;
bIsEnabled = false;
iConTimeOut = 0;
}
}
}
void CChannel::PutProtocolData ( const int iRecCounter, const int iRecID, const CVector<uint8_t>& vecbyMesBodyData, const CHostAddress& RecHostAddr )
{
// Only process protocol message if:
// - for client only: the packet comes from the server we want to talk to
// - the channel is enabled
// - the protocol mechanism is enabled
if ( ( bIsServer || ( GetAddress() == RecHostAddr ) ) && IsEnabled() && ProtocolIsEnabled() )
{
// parse the message assuming this is a regular protocol message
Protocol.ParseMessageBody ( vecbyMesBodyData, iRecCounter, iRecID );
}
}
EPutDataStat CChannel::PutAudioData ( const CVector<uint8_t>& vecbyData, const int iNumBytes, const CHostAddress& RecHostAddr )
{
// init return state
EPutDataStat eRet = PS_GEN_ERROR;
// Only process audio data if:
// - for client only: the packet comes from the server we want to talk to and we aren't disconnecting
// - the channel is enabled
if ( ( bIsServer || ( !bIsServer && GetAddress() == RecHostAddr && !bDisconnectAndDisable ) ) && IsEnabled() )
{
MutexSocketBuf.lock();
{
// only process audio if packet has correct size
if ( iNumBytes == ( iNetwFrameSize * iNetwFrameSizeFact ) )
{
// store new packet in jitter buffer
if ( SockBuf.Put ( vecbyData, iNumBytes ) )
{
eRet = PS_AUDIO_OK;
}
else
{
eRet = PS_AUDIO_ERR;
}
// manage audio fade-in counter, after channel is identified
if ( iFadeInCnt < iFadeInCntMax && bIsIdentified )
{
iFadeInCnt++;
}
}
else
{
// the protocol parsing failed and this was no audio block,
// we treat this as protocol error (unknown packet)
eRet = PS_PROT_ERR;
}
// All network packets except of valid protocol messages
// regardless if they are valid or invalid audio packets lead to
// a state change to a connected channel.
// This is because protocol messages can only be sent on a
// connected channel and the client has to inform the server
// about the audio packet properties via the protocol.
// check if channel was not connected, this is a new connection
if ( !IsConnected() )
{
// overwrite status
eRet = PS_NEW_CONNECTION;
// init audio fade-in counter
iFadeInCnt = 0;
// init level meter
SignalLevelMeter.Reset();
}
// reset time-out counter (note that this must be done after the
// "IsConnected()" query above)
ResetTimeOutCounter();
}
MutexSocketBuf.unlock();
}
else
{
eRet = PS_AUDIO_INVALID;
}
return eRet;
}
EGetDataStat CChannel::GetData ( CVector<uint8_t>& vecbyData, const int iNumBytes )
{
EGetDataStat eGetStatus;
MutexSocketBuf.lock();
{
// the socket access must be inside a mutex
const bool bSockBufState = SockBuf.Get ( vecbyData, iNumBytes );
// decrease time-out counter
if ( iConTimeOut > 0 )
{
// subtract the number of samples of the current block since the
// time out counter is based on samples not on blocks (definition:
// always one atomic block is get by using the GetData() function
// where the atomic block size is "iAudioFrameSizeSamples")
iConTimeOut -= iAudioFrameSizeSamples;
if ( iConTimeOut <= 0 )
{
// channel is just disconnected
eGetStatus = GS_CHAN_NOW_DISCONNECTED;
iConTimeOut = 0; // make sure we do not have negative values
if ( bDisconnectAndDisable && !bIsServer )
{
bDisconnectAndDisable = false;
bIsEnabled = false;
}
// reset network transport properties
ResetNetworkTransportProperties();
}
else
{
if ( bSockBufState )
{
// everything is ok
eGetStatus = GS_BUFFER_OK;
}
else
{
// channel is not yet disconnected but no data in buffer
eGetStatus = GS_BUFFER_UNDERRUN;
}
}
}
else
{
// channel is disconnected
eGetStatus = GS_CHAN_NOT_CONNECTED;
if ( bDisconnectAndDisable && !bIsServer )
{
bDisconnectAndDisable = false;
bIsEnabled = false;
iConTimeOut = 0;
}
}
}
MutexSocketBuf.unlock();
// in case we are just disconnected, we have to fire a message
if ( eGetStatus == GS_CHAN_NOW_DISCONNECTED )
{
// reset the protocol
Protocol.Reset();
// emit message
emit Disconnected();
}
return eGetStatus;
}
void CChannel::PrepAndSendPacket ( CHighPrioSocket* pSocket, const CVector<uint8_t>& vecbyNPacket, const int iNPacketLen )
{
// From v3.8.0 onwards, a server will not send audio to a client until that client has sent channel info.
// This addresses #1243 but means that clients earlier than v3.3.0 (24 Feb 2013) will no longer be compatible.
if ( bIsServer && !bIsIdentified )
{
return;
}
QMutexLocker locker ( &MutexConvBuf );
// use conversion buffer to convert sound card block size in network
// block size and take care of optional sequence number (note that
// the sequence number wraps automatically)
if ( ConvBuf.Put ( vecbyNPacket, iNPacketLen, iSendSequenceNumber++ ) )
{
pSocket->SendPacket ( ConvBuf.GetAll(), GetAddress() );
}
}
double CChannel::UpdateAndGetLevelForMeterdB ( const CVector<short>& vecsAudio, const int iInSize, const bool bIsStereoIn )
{
// update the signal level meter and immediately return the current value
SignalLevelMeter.Update ( vecsAudio, iInSize, bIsStereoIn );
return SignalLevelMeter.GetLevelForMeterdBLeftOrMono();
}
int CChannel::GetUploadRateKbps()
{
const int iAudioSizeOut = iNetwFrameSizeFact * iAudioFrameSizeSamples;
// we assume that the UDP packet which is transported via IP has an
// additional header size of ("Network Music Performance (NMP) in narrow
// band networks; Carot, Kraemer, Schuller; 2006")
// 8 (UDP) + 20 (IP without optional fields) = 28 bytes
// 2 (PPP) + 6 (PPPoE) + 18 (MAC) = 26 bytes
// 5 (RFC1483B) + 8 (AAL) + 10 (ATM) = 23 bytes
return ( iNetwFrameSize * iNetwFrameSizeFact + 28 + 26 + 23 /* header */ ) * 8 /* bits per byte */ * SYSTEM_SAMPLE_RATE_HZ / iAudioSizeOut / 1000;
}
void CChannel::UpdateSocketBufferSize()
{
// just update the socket buffer size if auto setting is enabled, otherwise
// do nothing
if ( bDoAutoSockBufSize )
{
// use auto setting result from channel, make sure we preserve the
// buffer memory since we just adjust the size here
SetSockBufNumFrames ( SockBuf.GetAutoSetting(), true );
}
}