Add code to generate python visualization to neteq_rtpplay

This adds a command line flag to generate a python visualization script from neteq_rtpplay.

Bug: webrtc:8614
Change-Id: Ia6f10d7ff0abac6fdbe9302e7f97a8a12a5bb65b
Reviewed-on: https://webrtc-review.googlesource.com/29940
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21116}
diff --git a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
index 34e7a84..882f823 100644
--- a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
+++ b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
@@ -252,5 +252,85 @@
   }
 }
 
+void NetEqDelayAnalyzer::CreatePythonScript(
+    const std::string& script_name) const {
+  std::vector<float> send_time_s;
+  std::vector<float> arrival_delay_ms;
+  std::vector<float> corrected_arrival_delay_ms;
+  std::vector<rtc::Optional<float>> playout_delay_ms;
+  std::vector<rtc::Optional<float>> target_delay_ms;
+  CreateGraphs(&send_time_s, &arrival_delay_ms, &corrected_arrival_delay_ms,
+               &playout_delay_ms, &target_delay_ms);
+
+  // Create an output file stream to the python script file.
+  std::ofstream output(script_name);
+  // The iterator is used to batch-output comma-separated values from vectors.
+  std::ostream_iterator<float> output_iterator(output, ",");
+
+  // Necessary includes
+  output << "import numpy as np" << std::endl;
+  output << "import matplotlib.pyplot as plt" << std::endl;
+
+  output << "send_time_s = [";
+  std::copy(send_time_s.begin(), send_time_s.end(), output_iterator);
+  output << "]" << std::endl;
+
+  output << "arrival_delay_ms = [";
+  std::copy(arrival_delay_ms.begin(), arrival_delay_ms.end(), output_iterator);
+  output << "]" << std::endl;
+
+  output << "corrected_arrival_delay_ms = [";
+  std::copy(corrected_arrival_delay_ms.begin(),
+            corrected_arrival_delay_ms.end(), output_iterator);
+  output << "]" << std::endl;
+
+  output << "playout_delay_ms = [";
+  for (const auto& v : playout_delay_ms) {
+    if (!v) {
+      output << "float('nan'), ";
+    } else {
+      output << *v << ", ";
+    }
+  }
+  output << "]" << std::endl;
+
+  output << "target_delay_ms = [";
+  for (const auto& v : target_delay_ms) {
+    if (!v) {
+      output << "float('nan'), ";
+    } else {
+      output << *v << ", ";
+    }
+  }
+  output << "]" << std::endl;
+
+  output << "if __name__ == '__main__':" << std::endl;
+  output << "  h=plt.plot(send_time_s, arrival_delay_ms, "
+         << "send_time_s, target_delay_ms, 'g.', "
+         << "send_time_s, playout_delay_ms)" << std::endl;
+  output << "  plt.setp(h[0],'color',[.75, .75, .75])" << std::endl;
+  output << "  plt.setp(h[1],'markersize',6)" << std::endl;
+  output << "  plt.setp(h[2],'linewidth',1.5)" << std::endl;
+  output << "  plt.axis('tight')" << std::endl;
+  output << "  plt.xlabel('send time [s]')" << std::endl;
+  output << "  plt.ylabel('relative delay [ms]')" << std::endl;
+  if (!ssrcs_.empty()) {
+    auto ssrc_it = ssrcs_.cbegin();
+    output << "  plt.title('SSRC: 0x" << std::hex
+           << static_cast<int64_t>(*ssrc_it++);
+    while (ssrc_it != ssrcs_.end()) {
+      output << ", 0x" << std::hex << static_cast<int64_t>(*ssrc_it++);
+    }
+    output << std::dec;
+    auto pt_it = payload_types_.cbegin();
+    output << "; Payload Types: " << *pt_it++;
+    while (pt_it != payload_types_.end()) {
+      output << ", " << *pt_it++;
+    }
+    output << "')" << std::endl;
+  }
+  output << "  plt.show()" << std::endl;
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
index 62bea4e..e6d6913 100644
--- a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
+++ b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
@@ -48,6 +48,11 @@
   // as provided by CreateGraphs.
   void CreateMatlabScript(const std::string& script_name) const;
 
+  // Creates a python script with file name |script_name|. When executed in
+  // Python, the script will generate graphs with the same timing information
+  // as provided by CreateGraphs.
+  void CreatePythonScript(const std::string& script_name) const;
+
  private:
   struct TimingData {
     explicit TimingData(double at) : arrival_time_ms(at) {}
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index 2657bfa..e2d0907 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -125,6 +125,9 @@
 DEFINE_bool(matlabplot,
             false,
             "Generates a matlab script for plotting the delay profile");
+DEFINE_bool(pythonplot,
+            false,
+            "Generates a python script for plotting the delay profile");
 DEFINE_bool(help, false, "Prints this message");
 
 // Maps a codec type to a printable name string.
@@ -614,7 +617,7 @@
 
   NetEqTest::Callbacks callbacks;
   std::unique_ptr<NetEqDelayAnalyzer> delay_analyzer;
-  if (FLAG_matlabplot) {
+  if (FLAG_matlabplot || FLAG_pythonplot) {
     delay_analyzer.reset(new NetEqDelayAnalyzer);
   }
 
@@ -637,6 +640,14 @@
               << std::endl;
     delay_analyzer->CreateMatlabScript(matlab_script_name + ".m");
   }
+  if (FLAG_pythonplot) {
+    auto python_script_name = output_file_name;
+    std::replace(python_script_name.begin(), python_script_name.end(), '.',
+                 '_');
+    std::cout << "Creating Python plot script " << python_script_name + ".py"
+              << std::endl;
+    delay_analyzer->CreatePythonScript(python_script_name + ".py");
+  }
 
   printf("Simulation statistics:\n");
   printf("  output duration: %" PRId64 " ms\n", test_duration_ms);