JackTrip
AudioTester.h
Go to the documentation of this file.
1 //*****************************************************************
2 /*
3  JackTrip: A System for High-Quality Audio Network Performance
4  over the Internet
5 
6  Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
7  SoundWIRE group at CCRMA, Stanford University.
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  OTHER DEALINGS IN THE SOFTWARE.
29 */
30 //*****************************************************************
31 
39 #pragma once
40 
41 #include "jacktrip_types.h" // sample_t
42 
43 #include <iostream>
44 //#include <ctime>
45 #include <chrono>
46 #include <cstdint>
47 #include <cmath>
48 #include <string>
49 #include <map>
50 
51 #include <QVarLengthArray>
52 
54 {
55  bool enabled { false };
56  float printIntervalSec { 1.0f };
57  int sendChannel { 0 };
58 
59  bool impulsePending { false };
60  int64_t lastPrintTimeUS { 0 };
61  int64_t impulseTimeUS { 0 };
62  int64_t impulseTimeSamples { 0 };
63  uint64_t sampleCountSinceImpulse { 1 }; // 0 not used
64  double roundTripMean { 0.0 };
65  double roundTripMeanSquare { 0.0 };
66  double roundTripCount { 0.0 };
67  const int bufferSkipStart { 100 };
68  int bufferSkip { bufferSkipStart };
69  const float impulseAmplitude { 0.1f };
70  const int numAmpCells { 10 };
71  const float ampCellHeight { impulseAmplitude/numAmpCells };
72 
73  const double latencyHistogramCellWidth { 5.0 }; // latency range in ms covered one cell
74  const double latencyHistogramCellMin { 0.0 };
75  const double latencyHistogramCellMax { 19.0 }; // in cells, so 5x this is max latency in ms
76  const int latencyHistogramPrintCountMax { 72 }; // normalize when asterisks exceed this number
77 
78  int pendingCell { 0 }; // 0 is not used
79  float sampleRate { 48000.0f };
80 
81 public:
83  ~AudioTester() = default;
84 
85  void lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
86  unsigned int n_frames);
87 
88  void writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy,
89  unsigned int n_frames);
90 
91  bool getEnabled() { return enabled; }
92  void setEnabled(bool e) { enabled = e; }
93  void setPrintIntervalSec(float s) { printIntervalSec = s; }
94  void setSendChannel(int c) { sendChannel = c; }
95  int getSendChannel() { return sendChannel; }
96  int getPendingCell() { return pendingCell; }
97  void setPendingCell(int pc) { pendingCell = pc; }
98  void setSampleRate(float fs) { sampleRate = fs; }
99  int getBufferSkip() { return bufferSkip; } // used for debugging breakpoints
100  void printHelp(char* command, char helpCase);
101 
102 private:
103 
104  float getImpulseAmp() {
105  pendingCell += 1; // only called when no impulse is pending
106  if (pendingCell >= numAmpCells) {
107  pendingCell = 1; // wrap-around, not using zero
108  }
109  float imp = float(pendingCell) * (impulseAmplitude/float(numAmpCells));
110  return imp;
111  }
112 
113  int getImpulseCellNum(float amp) {
114  float ch = ampCellHeight;
115  float cell = amp / ch;
116  int iCell = int(std::floor(0.5f + cell));
117  if (iCell > numAmpCells - 1) {
118  std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is beyond maximum expected\n";
119  iCell = numAmpCells-1;
120  } else if (iCell < 0) {
121  std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is below minimum expected\n";
122  iCell = 0;
123  }
124  return iCell;
125  }
126 
127  uint64_t timeMicroSec() {
128 #if 1
129  using namespace std::chrono;
130  // return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
131  return duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
132 #else
133  clock_t tics_since_launch = std::clock();
134  double timeUS = double(tics_since_launch)/double(CLOCKS_PER_SEC);
135  return (uint64_t)timeUS;
136 #endif
137  }
138 
139  std::map<int, int> latencyHistogram;
140 
141  std::map<int, int> getLatencyHistogram() {
142  return latencyHistogram;
143  }
144 
145  void extendLatencyHistogram(double latencyMS) {
146  int latencyCell = static_cast<int>(floor(std::max(latencyHistogramCellMin,
147  std::min(latencyHistogramCellMax,
148  std::floor(latencyMS / latencyHistogramCellWidth)))));
149  latencyHistogram[latencyCell] += 1;
150  }
151 
152  int latencyHistogramCountMax() {
153  int lhMax = 0;
154  int histStart = latencyHistogramFirstNonzeroCellIndex();
155  int histLast = latencyHistogramLastNonzeroCellIndex();
156  for (int i = histStart; i <= histLast; ++i) {
157  int lhi = latencyHistogram[i];
158  if (lhi > lhMax) {
159  lhMax = lhi;
160  }
161  }
162  return lhMax;
163  }
164 
165  int latencyHistogramFirstNonzeroCellIndex() {
166  for (int i=latencyHistogramCellMin; i <= latencyHistogramCellMax; i++) {
167  if (latencyHistogram[i]>0) {
168  return i;
169  }
170  }
171  std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
172  return -1;
173  }
174 
175  int latencyHistogramLastNonzeroCellIndex() {
176  for (int i=latencyHistogramCellMax; i>=latencyHistogramCellMin; i--) {
177  if (latencyHistogram[i]>0) {
178  return i;
179  }
180  }
181  std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
182  return -1;
183  }
184 
185  std::string getLatencyHistogramString() {
186  int histStart = latencyHistogramFirstNonzeroCellIndex();
187  int histLast = latencyHistogramLastNonzeroCellIndex();
188  std::string marker = "*";
189  double histScale = 1.0;
190  int lhcm = latencyHistogramCountMax();
191  int lhpcm = latencyHistogramPrintCountMax;
192  bool normalizing = lhpcm < lhcm;
193  if (normalizing) {
194  marker = "#";
195  histScale = double(lhpcm) / double(lhcm);
196  }
197  std::string rows = "";
198  for (int i = histStart; i <= histLast; ++i) {
199  int hi = latencyHistogram[i];
200  int hin = int(std::round(histScale * double(hi)));
201  std::string istrm1 = std::to_string(int(latencyHistogramCellWidth * double(i)));
202  std::string istr = std::to_string(int(latencyHistogramCellWidth * double(i+1)));
203  // std::string histr = boost::format("%02d",hi);
204  std::string histr = std::to_string(hi);
205  while (histr.length()<3) {
206  histr = " " + histr;
207  }
208  std::string row = "["+istrm1+"-"+istr+"ms]="+histr+":";
209  for (int j=0; j<hin; j++) {
210  row += marker;
211  }
212  rows += row + "\n";
213  }
214  if (histLast == latencyHistogramCellMax) {
215  rows += " and above\n";
216  }
217  return rows;
218  }
219 
220 };
AudioTester::AudioTester
AudioTester()
Definition: AudioTester.h:82
AudioTester::getSendChannel
int getSendChannel()
Definition: AudioTester.h:95
AudioTester::getPendingCell
int getPendingCell()
Definition: AudioTester.h:96
AudioTester::setPendingCell
void setPendingCell(int pc)
Definition: AudioTester.h:97
AudioTester::setSampleRate
void setSampleRate(float fs)
Definition: AudioTester.h:98
AudioTester::getBufferSkip
int getBufferSkip()
Definition: AudioTester.h:99
AudioTester
Definition: AudioTester.h:54
AudioTester::lookForReturnPulse
void lookForReturnPulse(QVarLengthArray< sample_t * > &out_buffer, unsigned int n_frames)
Definition: AudioTester.cpp:43
AudioTester::getEnabled
bool getEnabled()
Definition: AudioTester.h:91
AudioTester::setSendChannel
void setSendChannel(int c)
Definition: AudioTester.h:94
AudioTester::writeImpulse
void writeImpulse(QVarLengthArray< sample_t * > &mInBufCopy, unsigned int n_frames)
Definition: AudioTester.cpp:135
AudioTester::printHelp
void printHelp(char *command, char helpCase)
Definition: AudioTester.cpp:179
AudioTester::~AudioTester
~AudioTester()=default
jacktrip_types.h
AudioTester::setEnabled
void setEnabled(bool e)
Definition: AudioTester.h:92
AudioTester::setPrintIntervalSec
void setPrintIntervalSec(float s)
Definition: AudioTester.h:93