<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <memory>
#include <sstream>
#include <string>

#include "absl/strings/str_join.h"
#include "tensorflow/lite/core/api/error_reporter.h"
#include "tensorflow/lite/model_builder.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/schema/schema_utils.h"
#include "tensorflow/lite/tools/versioning/gpu_compatibility.h"
#include "tensorflow/lite/version.h"

namespace tflite {

namespace {

// Dump details of the given tensor.
void dump_tensor_detail(std::stringstream& out_stream,
                        const tflite::Tensor* tensor, const int tensor_idx) {
  out_stream << "T#" << tensor_idx;
  out_stream << "(" << tensor->name()->str() << ") ";
  // Prints `shape_signature` instead of `shape` if it's available since it
  // supports dynamic shapes.
  if (tensor->shape_signature()) {
    out_stream << "shape_signature:[";
    for (int i = 0; i < tensor->shape_signature()->Length(); ++i) {
      const int j = tensor->shape_signature()->Get(i);
      out_stream << j;
      if (i != tensor->shape_signature()->Length() - 1) {
        out_stream << ", ";
      }
    }
    out_stream << "]";
  } else {
    out_stream << "shape:[";
    for (int i = 0; i < tensor->shape()->Length(); ++i) {
      const int j = tensor->shape()->Get(i);
      out_stream << j;
      if (i != tensor->shape()->Length() - 1) {
        out_stream << ", ";
      }
    }
    out_stream << "]";
  }
  out_stream << ", type:" << EnumNameTensorType(tensor->type());
  out_stream << "\n";
}

// Dump list of input or output tensors.
void dump_tensor_list(std::stringstream& out_stream,
                      const flatbuffers::Vector<int32_t>* tensors,
                      bool verbose = false) {
  for (int i = 0; i < tensors->Length(); ++i) {
    const int tensor_idx = tensors->Get(i);
    if (verbose) {
      out_stream << "tensor #" << tensor_idx;
    } else {
      out_stream << "T#" << tensor_idx;
    }
    if (i != tensors->Length() - 1) {
      if (verbose) {
        out_stream << " and ";
      } else {
        out_stream << ", ";
      }
    }
  }
}

// Returns the string representation of the given OperatorCode.
const std::string get_op_name(const OperatorCode* op_code) {
  auto builtin_code = GetBuiltinCode(op_code);
  if (builtin_code != BuiltinOperator_CUSTOM) {
    return EnumNameBuiltinOperator(builtin_code);
  } else {
    return op_code->custom_code()->str();
  }
}

// Dump the given Operator node.
void dump_node(std::stringstream& out_stream, const int node_no,
               const OperatorCode* op_code, const Operator* op,
               const SubGraph* subgraph) {
  out_stream << "Op#" << node_no << " " << get_op_name(op_code);
  out_stream << "(";
  dump_tensor_list(out_stream, op->inputs());
  out_stream << ") -> [";
  dump_tensor_list(out_stream, op->outputs());
  out_stream << "]\n";
}

// Dump the summary of the given TFLite flatbuffer model. It's printed at the
// beginning of the analyzer output.
void dump_model_summary(std::stringstream& out_stream,
                        const ::tflite::Model* model) {
  auto* subgraphs = model->subgraphs();
  out_stream
      << "Your TFLite model has ‘" << subgraphs->Length()
      << "’ subgraph(s). In the subgraph description below,\nT# represents the "
         "Tensor numbers. ";
  if (subgraphs->Length() > 0 && subgraphs->Get(0)->operators()->Length() > 0) {
    const Operator* first_op = subgraphs->Get(0)->operators()->Get(0);
    const OperatorCode* first_op_code =
        model->operator_codes()->Get(first_op->opcode_index());
    out_stream << "For example, in Subgraph#0, the "
               << get_op_name(first_op_code) << " op takes\n";
    dump_tensor_list(out_stream, first_op->inputs(), /*verbose=*/true);
    out_stream << " as input and produces ";
    dump_tensor_list(out_stream, first_op->outputs(), /*verbose=*/true);
    out_stream << " as output.\n\n";
  }
}

}  // namespace

class StreamErrorReporter : public ErrorReporter {
 public:
  explicit StreamErrorReporter(std::stringstream* out_stream)
      : out_stream_(out_stream) {}
  int Report(const char* format, va_list args) override {
    char buffer[1024];
    int size = vsnprintf(buffer, sizeof(buffer), format, args);
    *out_stream_ << buffer;
    return size;
  }

 private:
  std::stringstream* out_stream_;
};

std::string model_analyzer(const std::string& model_file_or_buffer,
                           bool input_is_filepath,
                           bool check_gpu_compatibility) {
  std::stringstream out_stream;
  StreamErrorReporter error_reporter(&out_stream);
  std::unique_ptr<FlatBufferModel> fb_model;
  if (input_is_filepath) {
    fb_model = FlatBufferModel::BuildFromFile(model_file_or_buffer.c_str(),
                                              &error_reporter);
    if (!fb_model) {
      out_stream << "Failed to mmap model " << model_file_or_buffer;
      return out_stream.str();
    }
  } else {
    fb_model = FlatBufferModel::BuildFromBuffer(model_file_or_buffer.c_str(),
                                                model_file_or_buffer.size(),
                                                &error_reporter);
    if (!fb_model) {
      out_stream << "Failed to mmap the given model buffer.";
      return out_stream.str();
    }
  }
  const ::tflite::Model* model = fb_model->GetModel();
  auto* subgraphs = model->subgraphs();

  dump_model_summary(out_stream, model);

  bool model_is_gpu_compatibile = true;
  for (int i = 0; i < subgraphs->Length(); ++i) {
    std::vector<int> gpu_incompatibile_nodes;
    const SubGraph* subgraph = subgraphs->Get(i);
    out_stream << "Subgraph#" << i;
    if (subgraph->name()) {
      out_stream << " " << subgraph->name()->str();
    }
    out_stream << "(";
    dump_tensor_list(out_stream, subgraph->inputs());
    out_stream << ") -> [";
    dump_tensor_list(out_stream, subgraph->outputs());
    out_stream << "]\n";
    for (int j = 0; j < subgraph->operators()->Length(); ++j) {
      const Operator* op = subgraph->operators()->Get(j);
      const OperatorCode* op_code =
          model->operator_codes()->Get(op->opcode_index());
      out_stream << "  ";  // indents for operators
      dump_node(out_stream, /*node_no=*/j, op_code, op, subgraph);
      if (check_gpu_compatibility) {
        auto status =
            CheckGpuDelegateCompatibility(op_code, op, subgraph, model);
        if (!status.ok()) {
          gpu_incompatibile_nodes.push_back(j);
          out_stream << "GPU COMPATIBILITY WARNING: " << status.message()
                     << "\n";
        }
      }
    }
    if (!gpu_incompatibile_nodes.empty()) {
      model_is_gpu_compatibile = false;
      out_stream << "\nGPU COMPATIBILITY WARNING: Subgraph#" << i
                 << " has GPU delegate compatibility issues at nodes "
                 << absl::StrJoin(gpu_incompatibile_nodes, ", ")
                 << " with TFLite runtime version " << TF_VERSION_STRING
                 << "\n";
    }

    // Dump Subgraph Tensors.
    out_stream << "\nTensors of Subgraph#" << i << "\n";
    auto tensors = subgraph->tensors();
    for (int j = 0; j < tensors->Length(); ++j) {
      auto tensor = tensors->Get(j);
      out_stream << "  ";  // indents for tensors
      dump_tensor_detail(out_stream, tensor, j);
    }
  }
  if (check_gpu_compatibility && model_is_gpu_compatibile) {
    out_stream
        << "\nYour model looks compatibile with GPU delegate"
        << " with TFLite runtime version " << TF_VERSION_STRING
        << ".\nBut it doesn't guarantee that your model works well with GPU "
           "delegate.\nThere could be some runtime incompatibililty happen.\n";
  }
  return out_stream.str();
}

}  // namespace tflite
<commit_msg>model_analyzer: print new line after dump of tensors<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <memory>
#include <sstream>
#include <string>

#include "absl/strings/str_join.h"
#include "tensorflow/lite/core/api/error_reporter.h"
#include "tensorflow/lite/model_builder.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/schema/schema_utils.h"
#include "tensorflow/lite/tools/versioning/gpu_compatibility.h"
#include "tensorflow/lite/version.h"

namespace tflite {

namespace {

// Dump details of the given tensor.
void dump_tensor_detail(std::stringstream& out_stream,
                        const tflite::Tensor* tensor, const int tensor_idx) {
  out_stream << "T#" << tensor_idx;
  out_stream << "(" << tensor->name()->str() << ") ";
  // Prints `shape_signature` instead of `shape` if it's available since it
  // supports dynamic shapes.
  if (tensor->shape_signature()) {
    out_stream << "shape_signature:[";
    for (int i = 0; i < tensor->shape_signature()->Length(); ++i) {
      const int j = tensor->shape_signature()->Get(i);
      out_stream << j;
      if (i != tensor->shape_signature()->Length() - 1) {
        out_stream << ", ";
      }
    }
    out_stream << "]";
  } else {
    out_stream << "shape:[";
    for (int i = 0; i < tensor->shape()->Length(); ++i) {
      const int j = tensor->shape()->Get(i);
      out_stream << j;
      if (i != tensor->shape()->Length() - 1) {
        out_stream << ", ";
      }
    }
    out_stream << "]";
  }
  out_stream << ", type:" << EnumNameTensorType(tensor->type());
  out_stream << "\n";
}

// Dump list of input or output tensors.
void dump_tensor_list(std::stringstream& out_stream,
                      const flatbuffers::Vector<int32_t>* tensors,
                      bool verbose = false) {
  for (int i = 0; i < tensors->Length(); ++i) {
    const int tensor_idx = tensors->Get(i);
    if (verbose) {
      out_stream << "tensor #" << tensor_idx;
    } else {
      out_stream << "T#" << tensor_idx;
    }
    if (i != tensors->Length() - 1) {
      if (verbose) {
        out_stream << " and ";
      } else {
        out_stream << ", ";
      }
    }
  }
}

// Returns the string representation of the given OperatorCode.
const std::string get_op_name(const OperatorCode* op_code) {
  auto builtin_code = GetBuiltinCode(op_code);
  if (builtin_code != BuiltinOperator_CUSTOM) {
    return EnumNameBuiltinOperator(builtin_code);
  } else {
    return op_code->custom_code()->str();
  }
}

// Dump the given Operator node.
void dump_node(std::stringstream& out_stream, const int node_no,
               const OperatorCode* op_code, const Operator* op,
               const SubGraph* subgraph) {
  out_stream << "Op#" << node_no << " " << get_op_name(op_code);
  out_stream << "(";
  dump_tensor_list(out_stream, op->inputs());
  out_stream << ") -> [";
  dump_tensor_list(out_stream, op->outputs());
  out_stream << "]\n";
}

// Dump the summary of the given TFLite flatbuffer model. It's printed at the
// beginning of the analyzer output.
void dump_model_summary(std::stringstream& out_stream,
                        const ::tflite::Model* model) {
  auto* subgraphs = model->subgraphs();
  out_stream
      << "Your TFLite model has ‘" << subgraphs->Length()
      << "’ subgraph(s). In the subgraph description below,\nT# represents the "
         "Tensor numbers. ";
  if (subgraphs->Length() > 0 && subgraphs->Get(0)->operators()->Length() > 0) {
    const Operator* first_op = subgraphs->Get(0)->operators()->Get(0);
    const OperatorCode* first_op_code =
        model->operator_codes()->Get(first_op->opcode_index());
    out_stream << "For example, in Subgraph#0, the "
               << get_op_name(first_op_code) << " op takes\n";
    dump_tensor_list(out_stream, first_op->inputs(), /*verbose=*/true);
    out_stream << " as input and produces ";
    dump_tensor_list(out_stream, first_op->outputs(), /*verbose=*/true);
    out_stream << " as output.\n\n";
  }
}

}  // namespace

class StreamErrorReporter : public ErrorReporter {
 public:
  explicit StreamErrorReporter(std::stringstream* out_stream)
      : out_stream_(out_stream) {}
  int Report(const char* format, va_list args) override {
    char buffer[1024];
    int size = vsnprintf(buffer, sizeof(buffer), format, args);
    *out_stream_ << buffer;
    return size;
  }

 private:
  std::stringstream* out_stream_;
};

std::string model_analyzer(const std::string& model_file_or_buffer,
                           bool input_is_filepath,
                           bool check_gpu_compatibility) {
  std::stringstream out_stream;
  StreamErrorReporter error_reporter(&out_stream);
  std::unique_ptr<FlatBufferModel> fb_model;
  if (input_is_filepath) {
    fb_model = FlatBufferModel::BuildFromFile(model_file_or_buffer.c_str(),
                                              &error_reporter);
    if (!fb_model) {
      out_stream << "Failed to mmap model " << model_file_or_buffer;
      return out_stream.str();
    }
  } else {
    fb_model = FlatBufferModel::BuildFromBuffer(model_file_or_buffer.c_str(),
                                                model_file_or_buffer.size(),
                                                &error_reporter);
    if (!fb_model) {
      out_stream << "Failed to mmap the given model buffer.";
      return out_stream.str();
    }
  }
  const ::tflite::Model* model = fb_model->GetModel();
  auto* subgraphs = model->subgraphs();

  dump_model_summary(out_stream, model);

  bool model_is_gpu_compatibile = true;
  for (int i = 0; i < subgraphs->Length(); ++i) {
    std::vector<int> gpu_incompatibile_nodes;
    const SubGraph* subgraph = subgraphs->Get(i);
    out_stream << "Subgraph#" << i;
    if (subgraph->name()) {
      out_stream << " " << subgraph->name()->str();
    }
    out_stream << "(";
    dump_tensor_list(out_stream, subgraph->inputs());
    out_stream << ") -> [";
    dump_tensor_list(out_stream, subgraph->outputs());
    out_stream << "]\n";
    for (int j = 0; j < subgraph->operators()->Length(); ++j) {
      const Operator* op = subgraph->operators()->Get(j);
      const OperatorCode* op_code =
          model->operator_codes()->Get(op->opcode_index());
      out_stream << "  ";  // indents for operators
      dump_node(out_stream, /*node_no=*/j, op_code, op, subgraph);
      if (check_gpu_compatibility) {
        auto status =
            CheckGpuDelegateCompatibility(op_code, op, subgraph, model);
        if (!status.ok()) {
          gpu_incompatibile_nodes.push_back(j);
          out_stream << "GPU COMPATIBILITY WARNING: " << status.message()
                     << "\n";
        }
      }
    }
    if (!gpu_incompatibile_nodes.empty()) {
      model_is_gpu_compatibile = false;
      out_stream << "\nGPU COMPATIBILITY WARNING: Subgraph#" << i
                 << " has GPU delegate compatibility issues at nodes "
                 << absl::StrJoin(gpu_incompatibile_nodes, ", ")
                 << " with TFLite runtime version " << TF_VERSION_STRING
                 << "\n";
    }

    // Dump Subgraph Tensors.
    out_stream << "\nTensors of Subgraph#" << i << "\n";
    auto tensors = subgraph->tensors();
    for (int j = 0; j < tensors->Length(); ++j) {
      auto tensor = tensors->Get(j);
      out_stream << "  ";  // indents for tensors
      dump_tensor_detail(out_stream, tensor, j);
    }
    out_stream << "\n";
  }
  if (check_gpu_compatibility && model_is_gpu_compatibile) {
    out_stream
        << "\nYour model looks compatibile with GPU delegate"
        << " with TFLite runtime version " << TF_VERSION_STRING
        << ".\nBut it doesn't guarantee that your model works well with GPU "
           "delegate.\nThere could be some runtime incompatibililty happen.\n";
  }
  return out_stream.str();
}

}  // namespace tflite
<|endoftext|>


<commit_before>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include "kopete.h"

#include <dcopclient.h>
#include "kopeteiface.h"

static const char *description =
	I18N_NOOP("Kopete, the KDE Instant Messenger");

#define KOPETE_VERSION "0.5.8cvs >= 20021020"

static KCmdLineOptions options[] =
{
	{ "noplugins", I18N_NOOP("Do not load plugins"), 0 },
	{ "disable <plugin>", I18N_NOOP("Do not load specified plugin"), 0 },
	{ "!+[plugin]", I18N_NOOP("Load specified plugins"), 0 },
	{ 0, 0, 0 }
};

int main(int argc, char *argv[])
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001,2002, Duncan Mac-Vicar Prett\n(c) 2002, The Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, core developer"), "duncan@kde.org", "http://www.mac-vicar.com" );
	aboutData.addAuthor ( "Nick Betcher", I18N_NOOP("Core developer, fastest plugin developer on earth."), "nbetcher@kde.org", "http://www.kdedevelopers.net" );
	aboutData.addAuthor ( "Ryan Cumming", I18N_NOOP("Core developer"), "ryan@kde.org" );
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Core developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Richard Stellingwerff", I18N_NOOP("Developer"), "remenic@linuxfromscratch.org");
	aboutData.addAuthor ( "Daniel Stone", I18N_NOOP("Core developer, Jabber plugin"), "dstone@kde.org", "http://raging.dropbear.id.au/daniel/");
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Core developer, Jabber plugin"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Core developer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Hendrik vom Lehn", I18N_NOOP("Developer"), "hennevl@hennevl.de", "http://www.hennevl.de");
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Andres Krapf", I18N_NOOP("Developer"), "dae@chez.com" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("Winpopup plugin"), "gjw102@york.ac.uk" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Core developer, Gadu plugin"), "zack@kde.org" );
	aboutData.addAuthor ( "Carsten Pfeiffer", I18N_NOOP("Misc Bugfixes and Enhancelets"), "pfeiffer@kde.org" );
	aboutData.addAuthor ( "Chris TenHarmsel", I18N_NOOP("Developer"), "tenharmsel@users.sourceforge.net", "http://bemis.kicks-ass.net");
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Icon Author") );
	aboutData.addCredit ( "Vladimir Shutoff", I18N_NOOP("SIM icq library") );
	aboutData.addCredit ( "Herwin Jan Steehouwer", I18N_NOOP("KxEngine icq code") );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );
	aboutData.addCredit ( "Neil Stevens", I18N_NOOP("TAim engine AIM code") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Psi Jabber code") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	Kopete kopete;
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec
	kopete.exec();
}
/*
 * Local variables:
 * c-indentation-style: k&r
 * c-basic-offset: 8
 * indent-tabs-mode: t
 * End:
 */
// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>yes I read kde-cvs, why? ;-)<commit_after>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include "kopete.h"

#include <dcopclient.h>
#include "kopeteiface.h"

static const char *description =
	I18N_NOOP("Kopete, the KDE Instant Messenger");

#define KOPETE_VERSION "0.5.8cvs >= 20021020"

static KCmdLineOptions options[] =
{
	{ "noplugins", I18N_NOOP("Do not load plugins"), 0 },
	{ "disable <plugin>", I18N_NOOP("Do not load specified plugin"), 0 },
	{ "!+[plugin]", I18N_NOOP("Load specified plugins"), 0 },
	KCmdLineLastOption
};

int main(int argc, char *argv[])
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001,2002, Duncan Mac-Vicar Prett\n(c) 2002, The Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, core developer"), "duncan@kde.org", "http://www.mac-vicar.com" );
	aboutData.addAuthor ( "Nick Betcher", I18N_NOOP("Core developer, fastest plugin developer on earth."), "nbetcher@kde.org", "http://www.kdedevelopers.net" );
	aboutData.addAuthor ( "Ryan Cumming", I18N_NOOP("Core developer"), "ryan@kde.org" );
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Core developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Richard Stellingwerff", I18N_NOOP("Developer"), "remenic@linuxfromscratch.org");
	aboutData.addAuthor ( "Daniel Stone", I18N_NOOP("Core developer, Jabber plugin"), "dstone@kde.org", "http://raging.dropbear.id.au/daniel/");
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Core developer, Jabber plugin"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Core developer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Hendrik vom Lehn", I18N_NOOP("Developer"), "hennevl@hennevl.de", "http://www.hennevl.de");
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Andres Krapf", I18N_NOOP("Developer"), "dae@chez.com" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("Winpopup plugin"), "gjw102@york.ac.uk" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Core developer, Gadu plugin"), "zack@kde.org" );
	aboutData.addAuthor ( "Carsten Pfeiffer", I18N_NOOP("Misc Bugfixes and Enhancelets"), "pfeiffer@kde.org" );
	aboutData.addAuthor ( "Chris TenHarmsel", I18N_NOOP("Developer"), "tenharmsel@users.sourceforge.net", "http://bemis.kicks-ass.net");
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Icon Author") );
	aboutData.addCredit ( "Vladimir Shutoff", I18N_NOOP("SIM icq library") );
	aboutData.addCredit ( "Herwin Jan Steehouwer", I18N_NOOP("KxEngine icq code") );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );
	aboutData.addCredit ( "Neil Stevens", I18N_NOOP("TAim engine AIM code") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Psi Jabber code") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	Kopete kopete;
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec
	kopete.exec();
}
/*
 * Local variables:
 * c-indentation-style: k&r
 * c-basic-offset: 8
 * indent-tabs-mode: t
 * End:
 */
// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <google_smart_card_common/external_logs_printer.h>

#include <iostream>
#include <string>

#include <ppapi/cpp/var.h>

#include <google_smart_card_common/logging/logging.h>
#include <google_smart_card_common/messaging/typed_message_listener.h>
#include <google_smart_card_common/pp_var_utils/struct_converter.h>
#include <google_smart_card_common/value.h>
#include <google_smart_card_common/value_conversion.h>
#include <google_smart_card_common/value_nacl_pp_var_conversion.h>

namespace google_smart_card {

namespace {

// The structure represents the message handled by the external logs printer.
struct ExternalLogMessageData {
  std::string formatted_log_message;
};

void PrintExternalLogMessage(const ExternalLogMessageData& message_data) {
  // Note: Intentionally not using the GOOGLE_SMART_CARD_LOG*() macros and
  // related here, in order to avoid delivering them to the JS side and
  // therefore likely duplicating them.
  std::cerr << message_data.formatted_log_message;
  std::cerr.flush();
}

}  // namespace

template <>
StructValueDescriptor<ExternalLogMessageData>::Description
StructValueDescriptor<ExternalLogMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // //common/js/src/logging/log-buffer-forwarder.js.
  return Describe("ExternalLogMessageData")
      .WithField(&ExternalLogMessageData::formatted_log_message,
                 "formatted_log_message");
}

template <>
constexpr const char*
StructConverter<ExternalLogMessageData>::GetStructTypeName() {
  return "ExternalLogMessageData";
}

template <>
template <typename Callback>
void StructConverter<ExternalLogMessageData>::VisitFields(
    const ExternalLogMessageData& value,
    Callback callback) {
  callback(&value.formatted_log_message, "formatted_log_message");
}

ExternalLogsPrinter::ExternalLogsPrinter(
    const std::string& listened_message_type)
    : listened_message_type_(listened_message_type) {}

ExternalLogsPrinter::~ExternalLogsPrinter() = default;

std::string ExternalLogsPrinter::GetListenedMessageType() const {
  return listened_message_type_;
}

bool ExternalLogsPrinter::OnTypedMessageReceived(Value data) {
  // TODO(#185): Parse `Value` directly instead of transforming into `pp::Var`.
  pp::Var data_var = ConvertValueToPpVar(data);
  ExternalLogMessageData message_data;
  std::string error_message;
  if (!StructConverter<ExternalLogMessageData>::ConvertFromVar(
          data_var, &message_data, &error_message)) {
    GOOGLE_SMART_CARD_LOG_FATAL << "Failed to parse external log message: "
                                << error_message;
  }
  PrintExternalLogMessage(message_data);
  return true;
}

}  // namespace google_smart_card
<commit_msg>Remove NaCl specifics from external_logs_printer (#349)<commit_after>// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <google_smart_card_common/external_logs_printer.h>

#include <iostream>
#include <string>

#include <google_smart_card_common/logging/logging.h>
#include <google_smart_card_common/messaging/typed_message_listener.h>
#include <google_smart_card_common/value.h>
#include <google_smart_card_common/value_conversion.h>

namespace google_smart_card {

namespace {

// The structure represents the message handled by the external logs printer.
struct ExternalLogMessageData {
  std::string formatted_log_message;
};

void PrintExternalLogMessage(const ExternalLogMessageData& message_data) {
  // Note: Intentionally not using the GOOGLE_SMART_CARD_LOG*() macros and
  // related here, in order to avoid delivering them to the JS side and
  // therefore likely duplicating them.
  std::cerr << message_data.formatted_log_message;
  std::cerr.flush();
}

}  // namespace

template <>
StructValueDescriptor<ExternalLogMessageData>::Description
StructValueDescriptor<ExternalLogMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // //common/js/src/logging/log-buffer-forwarder.js.
  return Describe("ExternalLogMessageData")
      .WithField(&ExternalLogMessageData::formatted_log_message,
                 "formatted_log_message");
}

ExternalLogsPrinter::ExternalLogsPrinter(
    const std::string& listened_message_type)
    : listened_message_type_(listened_message_type) {}

ExternalLogsPrinter::~ExternalLogsPrinter() = default;

std::string ExternalLogsPrinter::GetListenedMessageType() const {
  return listened_message_type_;
}

bool ExternalLogsPrinter::OnTypedMessageReceived(Value data) {
  PrintExternalLogMessage(
      ConvertFromValueOrDie<ExternalLogMessageData>(std::move(data)));
  return true;
}

}  // namespace google_smart_card
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/voice_engine/include/voe_external_media.h"
#include "webrtc/voice_engine/test/auto_test/fakes/fake_media_process.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"

class ExternalMediaTest : public AfterStreamingFixture {
 protected:
  void TestRegisterExternalMedia(int channel, webrtc::ProcessingTypes type) {
    FakeMediaProcess fake_media_process;
    EXPECT_EQ(0, voe_xmedia_->RegisterExternalMediaProcessing(
        channel, type, fake_media_process));
    Sleep(2000);

    TEST_LOG("Back to normal.\n");
    EXPECT_EQ(0, voe_xmedia_->DeRegisterExternalMediaProcessing(
        channel, type));
    Sleep(2000);
  }
};

TEST_F(ExternalMediaTest, ManualCanRecordAndPlaybackUsingExternalPlayout) {
  SwitchToManualMicrophone();

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalPlayoutStatus(true));
  EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  TEST_LOG("Recording data for 2 seconds starting now: please speak.\n");
  int16_t recording[32000];
  for (int i = 0; i < 200; i++) {
    int sample_length = 0;
    EXPECT_EQ(0, voe_xmedia_->ExternalPlayoutGetData(
        &(recording[i * 160]), 16000, 100, sample_length));
    EXPECT_EQ(160, sample_length);
    Sleep(10);
  }

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalPlayoutStatus(false));
  EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalRecordingStatus(true));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  TEST_LOG("Playing back recording, you should hear what you said earlier.\n");
  for (int i = 0; i < 200; i++) {
    EXPECT_EQ(0, voe_xmedia_->ExternalRecordingInsertData(
        &(recording[i * 160]), 160, 16000, 20));
    Sleep(10);
  }

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalRecordingStatus(false));
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaProcessingOnAllChannelsAffectsPlayout) {
  TEST_LOG("Enabling external media processing: audio should be affected.\n");
  TestRegisterExternalMedia(-1, webrtc::kPlaybackAllChannelsMixed);
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaOnSingleChannelAffectsPlayout) {
  TEST_LOG("Enabling external media processing: audio should be affected.\n");
  TestRegisterExternalMedia(channel_, webrtc::kRecordingPerChannel);
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaOnAllChannelsMixedAffectsRecording) {
  SwitchToManualMicrophone();
  TEST_LOG("Speak and verify your voice is distorted.\n");
  TestRegisterExternalMedia(-1, webrtc::kRecordingAllChannelsMixed);
}

TEST_F(ExternalMediaTest,
       ExternalMixingCannotBeChangedDuringPlayback) {
  EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, true));
  EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, false));
}

TEST_F(ExternalMediaTest,
       ExternalMixingIsRequiredForGetAudioFrame) {
  webrtc::AudioFrame frame;
  EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
}

TEST_F(ExternalMediaTest,
       ExternalMixingPreventsAndRestoresRegularPlayback) {
  PausePlaying();
  ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  TEST_LOG("Verify that no sound is played out.\n");
  ResumePlaying();
  Sleep(1000);
  PausePlaying();
  ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
  TEST_LOG("Verify that sound is played out.\n");
  ResumePlaying();
  Sleep(1000);
}

TEST_F(ExternalMediaTest,
       ExternalMixingWorks) {
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
  EXPECT_LT(0, frame.sample_rate_hz_);
  EXPECT_LT(0, frame.samples_per_channel_);
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}

TEST_F(ExternalMediaTest,
       ExternalMixingResamplesToDesiredFrequency) {
  const int kValidFrequencies[] = {8000, 16000, 22000, 32000, 48000};
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  for (size_t i = 0; i < sizeof(kValidFrequencies) / sizeof(int); i++) {
    int f = kValidFrequencies[i];
    EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
       << "Resampling succeeds for freq=" << f;
    EXPECT_EQ(f, frame.sample_rate_hz_);
    EXPECT_EQ(f / 100, frame.samples_per_channel_);
  }
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}

TEST_F(ExternalMediaTest,
       ExternalMixingResamplingToInvalidFrequenciesFails) {
  const int kInvalidFrequencies[] = {-8000, -1, 1, 1000, 8001, 16001};
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  for (size_t i = 0; i < sizeof(kInvalidFrequencies) / sizeof(int); i++) {
    int f = kInvalidFrequencies[i];
    EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
        << "Resampling fails for freq=" << f;
  }
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}
<commit_msg>Fix error in mixing test for supported sample rates.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/voice_engine/include/voe_external_media.h"
#include "webrtc/voice_engine/test/auto_test/fakes/fake_media_process.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"

class ExternalMediaTest : public AfterStreamingFixture {
 protected:
  void TestRegisterExternalMedia(int channel, webrtc::ProcessingTypes type) {
    FakeMediaProcess fake_media_process;
    EXPECT_EQ(0, voe_xmedia_->RegisterExternalMediaProcessing(
        channel, type, fake_media_process));
    Sleep(2000);

    TEST_LOG("Back to normal.\n");
    EXPECT_EQ(0, voe_xmedia_->DeRegisterExternalMediaProcessing(
        channel, type));
    Sleep(2000);
  }
};

TEST_F(ExternalMediaTest, ManualCanRecordAndPlaybackUsingExternalPlayout) {
  SwitchToManualMicrophone();

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalPlayoutStatus(true));
  EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  TEST_LOG("Recording data for 2 seconds starting now: please speak.\n");
  int16_t recording[32000];
  for (int i = 0; i < 200; i++) {
    int sample_length = 0;
    EXPECT_EQ(0, voe_xmedia_->ExternalPlayoutGetData(
        &(recording[i * 160]), 16000, 100, sample_length));
    EXPECT_EQ(160, sample_length);
    Sleep(10);
  }

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalPlayoutStatus(false));
  EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalRecordingStatus(true));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  TEST_LOG("Playing back recording, you should hear what you said earlier.\n");
  for (int i = 0; i < 200; i++) {
    EXPECT_EQ(0, voe_xmedia_->ExternalRecordingInsertData(
        &(recording[i * 160]), 160, 16000, 20));
    Sleep(10);
  }

  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_xmedia_->SetExternalRecordingStatus(false));
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaProcessingOnAllChannelsAffectsPlayout) {
  TEST_LOG("Enabling external media processing: audio should be affected.\n");
  TestRegisterExternalMedia(-1, webrtc::kPlaybackAllChannelsMixed);
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaOnSingleChannelAffectsPlayout) {
  TEST_LOG("Enabling external media processing: audio should be affected.\n");
  TestRegisterExternalMedia(channel_, webrtc::kRecordingPerChannel);
}

TEST_F(ExternalMediaTest,
    ManualRegisterExternalMediaOnAllChannelsMixedAffectsRecording) {
  SwitchToManualMicrophone();
  TEST_LOG("Speak and verify your voice is distorted.\n");
  TestRegisterExternalMedia(-1, webrtc::kRecordingAllChannelsMixed);
}

TEST_F(ExternalMediaTest,
       ExternalMixingCannotBeChangedDuringPlayback) {
  EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, true));
  EXPECT_EQ(-1, voe_xmedia_->SetExternalMixing(channel_, false));
}

TEST_F(ExternalMediaTest,
       ExternalMixingIsRequiredForGetAudioFrame) {
  webrtc::AudioFrame frame;
  EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
}

TEST_F(ExternalMediaTest,
       ExternalMixingPreventsAndRestoresRegularPlayback) {
  PausePlaying();
  ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  TEST_LOG("Verify that no sound is played out.\n");
  ResumePlaying();
  Sleep(1000);
  PausePlaying();
  ASSERT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
  TEST_LOG("Verify that sound is played out.\n");
  ResumePlaying();
  Sleep(1000);
}

TEST_F(ExternalMediaTest,
       ExternalMixingWorks) {
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, 0, &frame));
  EXPECT_LT(0, frame.sample_rate_hz_);
  EXPECT_LT(0, frame.samples_per_channel_);
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}

TEST_F(ExternalMediaTest,
       ExternalMixingResamplesToDesiredFrequency) {
  const int kValidFrequencies[] = {8000, 16000, 22000, 32000, 48000};
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  for (size_t i = 0; i < sizeof(kValidFrequencies) / sizeof(int); i++) {
    int f = kValidFrequencies[i];
    EXPECT_EQ(0, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
       << "Resampling succeeds for freq=" << f;
    EXPECT_EQ(f, frame.sample_rate_hz_);
    EXPECT_EQ(f / 100, frame.samples_per_channel_);
  }
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}

TEST_F(ExternalMediaTest,
       ExternalMixingResamplingToInvalidFrequenciesFails) {
  const int kInvalidFrequencies[] = {-8000, -1};
  webrtc::AudioFrame frame;
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, true));
  ResumePlaying();
  for (size_t i = 0; i < sizeof(kInvalidFrequencies) / sizeof(int); i++) {
    int f = kInvalidFrequencies[i];
    EXPECT_EQ(-1, voe_xmedia_->GetAudioFrame(channel_, f, &frame))
        << "Resampling fails for freq=" << f;
  }
  PausePlaying();
  EXPECT_EQ(0, voe_xmedia_->SetExternalMixing(channel_, false));
  ResumePlaying();
}
<|endoftext|>


<commit_before>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow_lite_support/c/task/vision/image_classifier.h"

#include <memory>

#include "tensorflow_lite_support/c/common_utils.h"
#include "tensorflow_lite_support/c/task/vision/utils/frame_buffer_cpp_c_utils.h"
#include "tensorflow_lite_support/cc/task/vision/image_classifier.h"
#include "tensorflow_lite_support/cc/task/vision/proto/classifications_proto_inc.h"
#include "tensorflow_lite_support/cc/task/vision/proto/image_classifier_options_proto_inc.h"

namespace {
using ::tflite::support::StatusOr;
using ClassificationResultCpp = ::tflite::task::vision::ClassificationResult;
using ClassificationsCpp = ::tflite::task::vision::Classifications;
using ClassCpp = ::tflite::task::vision::Class;
using BoundingBoxCpp = ::tflite::task::vision::BoundingBox;
using ImageClassifierCpp = ::tflite::task::vision::ImageClassifier;
using ImageClassifierOptionsCpp =
    ::tflite::task::vision::ImageClassifierOptions;
using FrameBufferCpp = ::tflite::task::vision::FrameBuffer;
}  // namespace

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

struct TfLiteImageClassifier {
  std::unique_ptr<ImageClassifierCpp> impl;
};

TfLiteImageClassifierOptions TfLiteImageClassifierOptionsCreate() {
  return {.classification_options = {.max_results = -1},
          .base_options = {
              .compute_settings = {.cpu_settings = {.num_threads = -1}}}};
}

std::unique_ptr<ImageClassifierOptionsCpp>
CreateImageClassifierCppOptionsFromCOptions(
    const TfLiteImageClassifierOptions* c_options) {
  std::unique_ptr<ImageClassifierOptionsCpp> cpp_options(
      new ImageClassifierOptionsCpp);

  // More file sources can be added in else ifs
  if (c_options->base_options.model_file.file_path)
    cpp_options->mutable_base_options()->mutable_model_file()->set_file_name(
        c_options->base_options.model_file.file_path);

  // c_options->base_options.compute_settings.num_threads is expected to be
  // set to value > 0 or -1. Otherwise invoking
  // ImageClassifierCpp::CreateFromOptions() results in a not ok status.
  cpp_options->mutable_base_options()
      ->mutable_compute_settings()
      ->mutable_tflite_settings()
      ->mutable_cpu_settings()
      ->set_num_threads(
          c_options->base_options.compute_settings.cpu_settings.num_threads);

  for (int i = 0; i < c_options->classification_options.label_denylist.length;
       i++)
    cpp_options->add_class_name_blacklist(
        c_options->classification_options.label_denylist.list[i]);

  for (int i = 0; i < c_options->classification_options.label_allowlist.length;
       i++)
    cpp_options->add_class_name_whitelist(
        c_options->classification_options.label_allowlist.list[i]);

  // Check needed since setting a nullptr for this field results in a segfault
  // on invocation of ImageClassifierCpp::CreateFromOptions().
  if (c_options->classification_options.display_names_local) {
    cpp_options->set_display_names_locale(
        c_options->classification_options.display_names_local);
  }

  // c_options->classification_options.max_results is expected to be set to -1
  // or any value > 0. Otherwise invoking
  // ImageClassifierCpp::CreateFromOptions() results in a not ok status.
  cpp_options->set_max_results(c_options->classification_options.max_results);

  cpp_options->set_score_threshold(
      c_options->classification_options.score_threshold);

  return cpp_options;
}

TfLiteImageClassifier* TfLiteImageClassifierFromOptions(
    const TfLiteImageClassifierOptions* options, TfLiteSupportError** error) {
  std::unique_ptr<ImageClassifierOptionsCpp> cpp_options =
      CreateImageClassifierCppOptionsFromCOptions(options);

  if (cpp_options == nullptr) {
    return nullptr;
  }

  auto classifier_status = ImageClassifierCpp::CreateFromOptions(*cpp_options);

  if (classifier_status.ok()) {
    return new TfLiteImageClassifier{.impl =
                                         std::move(classifier_status.value())};
  } else {
    ::tflite::task::CreateTfLiteSupportErrorWithStatus(classifier_status.status(),
                                                error);
    return nullptr;
  }
}

TfLiteClassificationResult* GetClassificationResultCStruct(
    const ClassificationResultCpp& classification_result_cpp) {
  auto c_classifications =
      new TfLiteClassifications[classification_result_cpp
                                    .classifications_size()];

  for (int head = 0; head < classification_result_cpp.classifications_size();
       ++head) {
    const ClassificationsCpp& classifications =
        classification_result_cpp.classifications(head);
    c_classifications[head].head_index = head;

    auto c_categories = new TfLiteCategory[classifications.classes_size()];
    c_classifications->size = classifications.classes_size();

    for (int rank = 0; rank < classifications.classes_size(); ++rank) {
      const ClassCpp& classification = classifications.classes(rank);
      c_categories[rank].index = classification.index();
      c_categories[rank].score = classification.score();

      if (classification.has_class_name())
        c_categories[rank].label = strdup(classification.class_name().c_str());
      else
        c_categories[rank].label = nullptr;

      if (classification.has_display_name())
        c_categories[rank].display_name =
            strdup(classification.display_name().c_str());
      else
        c_categories[rank].display_name = nullptr;
    }
    c_classifications[head].categories = c_categories;
  }

  auto c_classification_result = new TfLiteClassificationResult;
  c_classification_result->classifications = c_classifications;
  c_classification_result->size =
      classification_result_cpp.classifications_size();

  return c_classification_result;
}

TfLiteClassificationResult* TfLiteImageClassifierClassifyWithRoi(
    const TfLiteImageClassifier* classifier,
    const TfLiteFrameBuffer* frame_buffer, const TfLiteBoundingBox* roi,
    TfLiteSupportError** error) {
  if (classifier == nullptr || frame_buffer == nullptr) {
    return nullptr;
  }

  BoundingBoxCpp cc_roi;
  if (roi == nullptr) {
    cc_roi.set_width(frame_buffer->dimension.width);
    cc_roi.set_height(frame_buffer->dimension.height);
  } else {
    cc_roi.set_origin_x(roi->origin_x);
    cc_roi.set_origin_y(roi->origin_y);
    cc_roi.set_width(roi->width);
    cc_roi.set_height(roi->height);
  }

  StatusOr<std::unique_ptr<FrameBufferCpp>> cpp_frame_buffer_status =
      ::tflite::task::vision::CreateCppFrameBuffer(*frame_buffer);
  if (!cpp_frame_buffer_status.ok()) return nullptr;

  // fnc_sample(cpp_frame_buffer_status);
  StatusOr<ClassificationResultCpp> classification_result_cpp =
      classifier->impl->Classify(*std::move(cpp_frame_buffer_status.value()),
                                 cc_roi);

  if (!classification_result_cpp.ok()) {
    ::tflite::task::CreateTfLiteSupportErrorWithStatus(
        classification_result_cpp.status(), error);
    return nullptr;
  }

  return GetClassificationResultCStruct(classification_result_cpp.value());
}

TfLiteClassificationResult* TfLiteImageClassifierClassify(
    const TfLiteImageClassifier* classifier,
    const TfLiteFrameBuffer* frame_buffer, TfLiteSupportError** error) {
  return TfLiteImageClassifierClassifyWithRoi(classifier, frame_buffer, nullptr,
                                              error);
}

void TfLiteImageClassifierDelete(TfLiteImageClassifier* classifier) {
  delete classifier;
}

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus
<commit_msg>Changed scope of TfLiteSupportError method calls<commit_after>/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow_lite_support/c/task/vision/image_classifier.h"

#include <memory>

#include "tensorflow_lite_support/c/common_utils.h"
#include "tensorflow_lite_support/c/task/vision/utils/frame_buffer_cpp_c_utils.h"
#include "tensorflow_lite_support/cc/task/vision/image_classifier.h"
#include "tensorflow_lite_support/cc/task/vision/proto/classifications_proto_inc.h"
#include "tensorflow_lite_support/cc/task/vision/proto/image_classifier_options_proto_inc.h"

namespace {
using ::tflite::support::StatusOr;
using ClassificationResultCpp = ::tflite::task::vision::ClassificationResult;
using ClassificationsCpp = ::tflite::task::vision::Classifications;
using ClassCpp = ::tflite::task::vision::Class;
using BoundingBoxCpp = ::tflite::task::vision::BoundingBox;
using ImageClassifierCpp = ::tflite::task::vision::ImageClassifier;
using ImageClassifierOptionsCpp =
    ::tflite::task::vision::ImageClassifierOptions;
using FrameBufferCpp = ::tflite::task::vision::FrameBuffer;
}  // namespace

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

struct TfLiteImageClassifier {
  std::unique_ptr<ImageClassifierCpp> impl;
};

TfLiteImageClassifierOptions TfLiteImageClassifierOptionsCreate() {
  return {.classification_options = {.max_results = -1},
          .base_options = {
              .compute_settings = {.cpu_settings = {.num_threads = -1}}}};
}

std::unique_ptr<ImageClassifierOptionsCpp>
CreateImageClassifierCppOptionsFromCOptions(
    const TfLiteImageClassifierOptions* c_options) {
  std::unique_ptr<ImageClassifierOptionsCpp> cpp_options(
      new ImageClassifierOptionsCpp);

  // More file sources can be added in else ifs
  if (c_options->base_options.model_file.file_path)
    cpp_options->mutable_base_options()->mutable_model_file()->set_file_name(
        c_options->base_options.model_file.file_path);

  // c_options->base_options.compute_settings.num_threads is expected to be
  // set to value > 0 or -1. Otherwise invoking
  // ImageClassifierCpp::CreateFromOptions() results in a not ok status.
  cpp_options->mutable_base_options()
      ->mutable_compute_settings()
      ->mutable_tflite_settings()
      ->mutable_cpu_settings()
      ->set_num_threads(
          c_options->base_options.compute_settings.cpu_settings.num_threads);

  for (int i = 0; i < c_options->classification_options.label_denylist.length;
       i++)
    cpp_options->add_class_name_blacklist(
        c_options->classification_options.label_denylist.list[i]);

  for (int i = 0; i < c_options->classification_options.label_allowlist.length;
       i++)
    cpp_options->add_class_name_whitelist(
        c_options->classification_options.label_allowlist.list[i]);

  // Check needed since setting a nullptr for this field results in a segfault
  // on invocation of ImageClassifierCpp::CreateFromOptions().
  if (c_options->classification_options.display_names_local) {
    cpp_options->set_display_names_locale(
        c_options->classification_options.display_names_local);
  }

  // c_options->classification_options.max_results is expected to be set to -1
  // or any value > 0. Otherwise invoking
  // ImageClassifierCpp::CreateFromOptions() results in a not ok status.
  cpp_options->set_max_results(c_options->classification_options.max_results);

  cpp_options->set_score_threshold(
      c_options->classification_options.score_threshold);

  return cpp_options;
}

TfLiteImageClassifier* TfLiteImageClassifierFromOptions(
    const TfLiteImageClassifierOptions* options, TfLiteSupportError** error) {
  std::unique_ptr<ImageClassifierOptionsCpp> cpp_options =
      CreateImageClassifierCppOptionsFromCOptions(options);

  if (cpp_options == nullptr) {
    return nullptr;
  }

  auto classifier_status = ImageClassifierCpp::CreateFromOptions(*cpp_options);

  if (classifier_status.ok()) {
    return new TfLiteImageClassifier{.impl =
                                         std::move(classifier_status.value())};
  } else {
    ::tflite::support::CreateTfLiteSupportErrorWithStatus(classifier_status.status(),
                                                error);
    return nullptr;
  }
}

TfLiteClassificationResult* GetClassificationResultCStruct(
    const ClassificationResultCpp& classification_result_cpp) {
  auto c_classifications =
      new TfLiteClassifications[classification_result_cpp
                                    .classifications_size()];

  for (int head = 0; head < classification_result_cpp.classifications_size();
       ++head) {
    const ClassificationsCpp& classifications =
        classification_result_cpp.classifications(head);
    c_classifications[head].head_index = head;

    auto c_categories = new TfLiteCategory[classifications.classes_size()];
    c_classifications->size = classifications.classes_size();

    for (int rank = 0; rank < classifications.classes_size(); ++rank) {
      const ClassCpp& classification = classifications.classes(rank);
      c_categories[rank].index = classification.index();
      c_categories[rank].score = classification.score();

      if (classification.has_class_name())
        c_categories[rank].label = strdup(classification.class_name().c_str());
      else
        c_categories[rank].label = nullptr;

      if (classification.has_display_name())
        c_categories[rank].display_name =
            strdup(classification.display_name().c_str());
      else
        c_categories[rank].display_name = nullptr;
    }
    c_classifications[head].categories = c_categories;
  }

  auto c_classification_result = new TfLiteClassificationResult;
  c_classification_result->classifications = c_classifications;
  c_classification_result->size =
      classification_result_cpp.classifications_size();

  return c_classification_result;
}

TfLiteClassificationResult* TfLiteImageClassifierClassifyWithRoi(
    const TfLiteImageClassifier* classifier,
    const TfLiteFrameBuffer* frame_buffer, const TfLiteBoundingBox* roi,
    TfLiteSupportError** error) {
  if (classifier == nullptr || frame_buffer == nullptr) {
    return nullptr;
  }

  BoundingBoxCpp cc_roi;
  if (roi == nullptr) {
    cc_roi.set_width(frame_buffer->dimension.width);
    cc_roi.set_height(frame_buffer->dimension.height);
  } else {
    cc_roi.set_origin_x(roi->origin_x);
    cc_roi.set_origin_y(roi->origin_y);
    cc_roi.set_width(roi->width);
    cc_roi.set_height(roi->height);
  }

  StatusOr<std::unique_ptr<FrameBufferCpp>> cpp_frame_buffer_status =
      ::tflite::task::vision::CreateCppFrameBuffer(*frame_buffer);
  if (!cpp_frame_buffer_status.ok()) return nullptr;

  // fnc_sample(cpp_frame_buffer_status);
  StatusOr<ClassificationResultCpp> classification_result_cpp =
      classifier->impl->Classify(*std::move(cpp_frame_buffer_status.value()),
                                 cc_roi);

  if (!classification_result_cpp.ok()) {
    ::tflite::support::CreateTfLiteSupportErrorWithStatus(
        classification_result_cpp.status(), error);
    return nullptr;
  }

  return GetClassificationResultCStruct(classification_result_cpp.value());
}

TfLiteClassificationResult* TfLiteImageClassifierClassify(
    const TfLiteImageClassifier* classifier,
    const TfLiteFrameBuffer* frame_buffer, TfLiteSupportError** error) {
  return TfLiteImageClassifierClassifyWithRoi(classifier, frame_buffer, nullptr,
                                              error);
}

void TfLiteImageClassifierDelete(TfLiteImageClassifier* classifier) {
  delete classifier;
}

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/media/audio_input_renderer_host.h"

#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/process.h"
#include "base/shared_memory.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/common/media/audio_messages.h"

using content::BrowserMessageFilter;
using content::BrowserThread;

AudioInputRendererHost::AudioEntry::AudioEntry()
    : stream_id(0),
      pending_close(false) {
}

AudioInputRendererHost::AudioEntry::~AudioEntry() {}

AudioInputRendererHost::AudioInputRendererHost(
    content::ResourceContext* resource_context,
    media::AudioManager* audio_manager)
    : resource_context_(resource_context),
      audio_manager_(audio_manager) {
}

AudioInputRendererHost::~AudioInputRendererHost() {
  DCHECK(audio_entries_.empty());
}

void AudioInputRendererHost::OnChannelClosing() {
  BrowserMessageFilter::OnChannelClosing();

  // Since the IPC channel is gone, close all requested audio streams.
  DeleteEntries();
}

void AudioInputRendererHost::OnDestruct() const {
  BrowserThread::DeleteOnIOThread::Destruct(this);
}

void AudioInputRendererHost::OnCreated(
    media::AudioInputController* controller) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(
          &AudioInputRendererHost::DoCompleteCreation,
          this,
          make_scoped_refptr(controller)));
}

void AudioInputRendererHost::OnRecording(
    media::AudioInputController* controller) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(
          &AudioInputRendererHost::DoSendRecordingMessage,
          this,
          make_scoped_refptr(controller)));
}

void AudioInputRendererHost::OnError(
    media::AudioInputController* controller,
    int error_code) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(&AudioInputRendererHost::DoHandleError,
          this, make_scoped_refptr(controller), error_code));
}

void AudioInputRendererHost::OnData(media::AudioInputController* controller,
                                    const uint8* data,
                                    uint32 size) {
  NOTREACHED() << "Only low-latency mode is supported.";
}

void AudioInputRendererHost::DoCompleteCreation(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupByController(controller);
  if (!entry)
    return;

  if (!peer_handle()) {
    NOTREACHED() << "Renderer process handle is invalid.";
    DeleteEntryOnError(entry);
    return;
  }

  if (!entry->controller->LowLatencyMode()) {
    NOTREACHED() << "Only low-latency mode is supported.";
    DeleteEntryOnError(entry);
    return;
  }

  // Once the audio stream is created then complete the creation process by
  // mapping shared memory and sharing with the renderer process.
  base::SharedMemoryHandle foreign_memory_handle;
  if (!entry->shared_memory.ShareToProcess(peer_handle(),
                                           &foreign_memory_handle)) {
    // If we failed to map and share the shared memory then close the audio
    // stream and send an error message.
    DeleteEntryOnError(entry);
    return;
  }

  media::AudioInputSyncWriter* writer =
      static_cast<media::AudioInputSyncWriter*>(entry->writer.get());

#if defined(OS_WIN)
  base::SyncSocket::Handle foreign_socket_handle;
#else
  base::FileDescriptor foreign_socket_handle;
#endif

  // If we failed to prepare the sync socket for the renderer then we fail
  // the construction of audio input stream.
  if (!writer->PrepareForeignSocketHandle(peer_handle(),
                                          &foreign_socket_handle)) {
    DeleteEntryOnError(entry);
    return;
  }

  Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
      foreign_memory_handle, foreign_socket_handle,
      entry->shared_memory.created_size()));
}

void AudioInputRendererHost::DoSendRecordingMessage(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // TODO(henrika): TBI?
  NOTIMPLEMENTED();
}

void AudioInputRendererHost::DoSendPausedMessage(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // TODO(henrika): TBI?
  NOTREACHED();
}

void AudioInputRendererHost::DoHandleError(
    media::AudioInputController* controller,
    int error_code) {
  DLOG(WARNING) << "AudioInputRendererHost::DoHandleError(error_code="
                << error_code << ")";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupByController(controller);
  if (!entry)
    return;

  DeleteEntryOnError(entry);
}

bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
                                               bool* message_was_ok) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_StartDevice, OnStartDevice)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP_EX()

  return handled;
}
void AudioInputRendererHost::OnStartDevice(int stream_id, int session_id) {
  VLOG(1) << "AudioInputRendererHost::OnStartDevice(stream_id="
          << stream_id << ", session_id = " << session_id << ")";

  // Get access to the AudioInputDeviceManager to start the device.
  media_stream::AudioInputDeviceManager* audio_input_man =
      media_stream::MediaStreamManager::GetForResourceContext(
          resource_context_, audio_manager_)->audio_input_device_manager();

  // Add the session entry to the map.
  session_entries_[session_id] = stream_id;

  // Start the device with the session_id. If the device is started
  // successfully, OnDeviceStarted() callback will be triggered.
  audio_input_man->Start(session_id, this);
}

void AudioInputRendererHost::OnCreateStream(
    int stream_id, const media::AudioParameters& params,
    const std::string& device_id, bool automatic_gain_control) {
  VLOG(1) << "AudioInputRendererHost::OnCreateStream(stream_id="
          << stream_id << ")";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK(LookupById(stream_id) == NULL);

  media::AudioParameters audio_params(params);

  DCHECK_GT(audio_params.frames_per_buffer(), 0);
  uint32 buffer_size = audio_params.GetBytesPerBuffer();

  // Create a new AudioEntry structure.
  scoped_ptr<AudioEntry> entry(new AudioEntry());

  uint32 mem_size = sizeof(media::AudioInputBufferParameters) + buffer_size;

  // Create the shared memory and share it with the renderer process
  // using a new SyncWriter object.
  if (!entry->shared_memory.CreateAndMapAnonymous(mem_size)) {
    // If creation of shared memory failed then send an error message.
    SendErrorMessage(stream_id);
    return;
  }

  scoped_ptr<media::AudioInputSyncWriter> writer(
      new media::AudioInputSyncWriter(&entry->shared_memory));

  if (!writer->Init()) {
    SendErrorMessage(stream_id);
    return;
  }

  // If we have successfully created the SyncWriter then assign it to the
  // entry and construct an AudioInputController.
  // TODO(henrika): replace CreateLowLatency() with Create() as soon
  // as satish has ensured that Speech Input also uses the default low-
  // latency path. See crbug.com/112472 for details.
  entry->writer.reset(writer.release());
  entry->controller = media::AudioInputController::CreateLowLatency(
      audio_manager_,
      this,
      audio_params,
      device_id,
      entry->writer.get());

  if (!entry->controller) {
    SendErrorMessage(stream_id);
    return;
  }

  // Set the initial AGC state for the audio input stream.
  entry->controller->SetAutomaticGainControl(automatic_gain_control);

  // If we have created the controller successfully create a entry and add it
  // to the map.
  entry->stream_id = stream_id;

  audio_entries_.insert(std::make_pair(stream_id, entry.release()));
}

void AudioInputRendererHost::OnRecordStream(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);
  if (!entry) {
    SendErrorMessage(stream_id);
    return;
  }

  entry->controller->Record();
}

void AudioInputRendererHost::OnCloseStream(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);

  if (entry)
    CloseAndDeleteStream(entry);

  int session_id = LookupSessionById(stream_id);

  if (session_id)
    StopAndDeleteDevice(session_id);
}

void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);
  if (!entry) {
    SendErrorMessage(stream_id);
    return;
  }

  entry->controller->SetVolume(volume);
}

void AudioInputRendererHost::SendErrorMessage(int stream_id) {
  Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id,
                                                  kAudioStreamError));
}

void AudioInputRendererHost::DeleteEntries() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  for (AudioEntryMap::iterator i = audio_entries_.begin();
       i != audio_entries_.end(); ++i) {
    CloseAndDeleteStream(i->second);
  }
}

void AudioInputRendererHost::OnDeviceStarted(
    int session_id, const std::string& device_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  SessionEntryMap::iterator it = session_entries_.find(session_id);
  if (it == session_entries_.end()) {
    DLOG(WARNING) << "AudioInputRendererHost::OnDeviceStarted()"
        " session does not exist.";
    return;
  }

  // Notify the renderer with the id of the opened device.
  Send(new AudioInputMsg_NotifyDeviceStarted(it->second, device_id));
}

void AudioInputRendererHost::OnDeviceStopped(int session_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  SessionEntryMap::iterator it = session_entries_.find(session_id);
  // Return if the stream has been closed.
  if (it == session_entries_.end())
    return;

  int stream_id = it->second;
  AudioEntry* entry = LookupById(stream_id);

  if (entry) {
    // Device has been stopped, close the input stream.
    CloseAndDeleteStream(entry);
    // Notify the renderer that the state of the input stream has changed.
    Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id,
                                                    kAudioStreamPaused));
  }

  // Delete the session entry.
  session_entries_.erase(it);
}

void AudioInputRendererHost::StopAndDeleteDevice(int session_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  media_stream::AudioInputDeviceManager* audio_input_man =
      media_stream::MediaStreamManager::GetForResourceContext(
          resource_context_, audio_manager_)->audio_input_device_manager();
  audio_input_man->Stop(session_id);

  // Delete the session entry.
  session_entries_.erase(session_id);
}

void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (!entry->pending_close) {
    entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
                                        this, entry));
    entry->pending_close = true;
  }
}

void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Delete the entry when this method goes out of scope.
  scoped_ptr<AudioEntry> entry_deleter(entry);

  // Erase the entry from the map.
  audio_entries_.erase(entry->stream_id);
}

void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Sends the error message first before we close the stream because
  // |entry| is destroyed in DeleteEntry().
  SendErrorMessage(entry->stream_id);
  CloseAndDeleteStream(entry);
}

AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
    int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntryMap::iterator i = audio_entries_.find(stream_id);
  if (i != audio_entries_.end())
    return i->second;
  return NULL;
}

AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Iterate the map of entries.
  // TODO(hclam): Implement a faster look up method.
  for (AudioEntryMap::iterator i = audio_entries_.begin();
       i != audio_entries_.end(); ++i) {
    if (controller == i->second->controller.get())
      return i->second;
  }
  return NULL;
}

int AudioInputRendererHost::LookupSessionById(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  for (SessionEntryMap::iterator it = session_entries_.begin();
       it != session_entries_.end(); ++it) {
    if (stream_id == it->second) {
      return it->first;
    }
  }
  return 0;
}
<commit_msg>We have seen error messages (see e.g. http://build.chromium.org/p/chromium.gpu.fyi/builders/Win7%20Audio/builds/1275/steps/content_unittests/logs/stdio) which might be confusing.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/media/audio_input_renderer_host.h"

#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/process.h"
#include "base/shared_memory.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/common/media/audio_messages.h"

using content::BrowserMessageFilter;
using content::BrowserThread;

AudioInputRendererHost::AudioEntry::AudioEntry()
    : stream_id(0),
      pending_close(false) {
}

AudioInputRendererHost::AudioEntry::~AudioEntry() {}

AudioInputRendererHost::AudioInputRendererHost(
    content::ResourceContext* resource_context,
    media::AudioManager* audio_manager)
    : resource_context_(resource_context),
      audio_manager_(audio_manager) {
}

AudioInputRendererHost::~AudioInputRendererHost() {
  DCHECK(audio_entries_.empty());
}

void AudioInputRendererHost::OnChannelClosing() {
  BrowserMessageFilter::OnChannelClosing();

  // Since the IPC channel is gone, close all requested audio streams.
  DeleteEntries();
}

void AudioInputRendererHost::OnDestruct() const {
  BrowserThread::DeleteOnIOThread::Destruct(this);
}

void AudioInputRendererHost::OnCreated(
    media::AudioInputController* controller) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(
          &AudioInputRendererHost::DoCompleteCreation,
          this,
          make_scoped_refptr(controller)));
}

void AudioInputRendererHost::OnRecording(
    media::AudioInputController* controller) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(
          &AudioInputRendererHost::DoSendRecordingMessage,
          this,
          make_scoped_refptr(controller)));
}

void AudioInputRendererHost::OnError(
    media::AudioInputController* controller,
    int error_code) {
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(&AudioInputRendererHost::DoHandleError,
          this, make_scoped_refptr(controller), error_code));
}

void AudioInputRendererHost::OnData(media::AudioInputController* controller,
                                    const uint8* data,
                                    uint32 size) {
  NOTREACHED() << "Only low-latency mode is supported.";
}

void AudioInputRendererHost::DoCompleteCreation(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupByController(controller);
  if (!entry)
    return;

  if (!peer_handle()) {
    NOTREACHED() << "Renderer process handle is invalid.";
    DeleteEntryOnError(entry);
    return;
  }

  if (!entry->controller->LowLatencyMode()) {
    NOTREACHED() << "Only low-latency mode is supported.";
    DeleteEntryOnError(entry);
    return;
  }

  // Once the audio stream is created then complete the creation process by
  // mapping shared memory and sharing with the renderer process.
  base::SharedMemoryHandle foreign_memory_handle;
  if (!entry->shared_memory.ShareToProcess(peer_handle(),
                                           &foreign_memory_handle)) {
    // If we failed to map and share the shared memory then close the audio
    // stream and send an error message.
    DeleteEntryOnError(entry);
    return;
  }

  media::AudioInputSyncWriter* writer =
      static_cast<media::AudioInputSyncWriter*>(entry->writer.get());

#if defined(OS_WIN)
  base::SyncSocket::Handle foreign_socket_handle;
#else
  base::FileDescriptor foreign_socket_handle;
#endif

  // If we failed to prepare the sync socket for the renderer then we fail
  // the construction of audio input stream.
  if (!writer->PrepareForeignSocketHandle(peer_handle(),
                                          &foreign_socket_handle)) {
    DeleteEntryOnError(entry);
    return;
  }

  Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
      foreign_memory_handle, foreign_socket_handle,
      entry->shared_memory.created_size()));
}

void AudioInputRendererHost::DoSendRecordingMessage(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // TODO(henrika): See crbug.com/115262 for details on why this method
  // should be implemented.
}

void AudioInputRendererHost::DoSendPausedMessage(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  // TODO(henrika): TBI?
  NOTREACHED();
}

void AudioInputRendererHost::DoHandleError(
    media::AudioInputController* controller,
    int error_code) {
  DLOG(WARNING) << "AudioInputRendererHost::DoHandleError(error_code="
                << error_code << ")";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupByController(controller);
  if (!entry)
    return;

  DeleteEntryOnError(entry);
}

bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
                                               bool* message_was_ok) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_StartDevice, OnStartDevice)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
    IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP_EX()

  return handled;
}
void AudioInputRendererHost::OnStartDevice(int stream_id, int session_id) {
  VLOG(1) << "AudioInputRendererHost::OnStartDevice(stream_id="
          << stream_id << ", session_id = " << session_id << ")";

  // Get access to the AudioInputDeviceManager to start the device.
  media_stream::AudioInputDeviceManager* audio_input_man =
      media_stream::MediaStreamManager::GetForResourceContext(
          resource_context_, audio_manager_)->audio_input_device_manager();

  // Add the session entry to the map.
  session_entries_[session_id] = stream_id;

  // Start the device with the session_id. If the device is started
  // successfully, OnDeviceStarted() callback will be triggered.
  audio_input_man->Start(session_id, this);
}

void AudioInputRendererHost::OnCreateStream(
    int stream_id, const media::AudioParameters& params,
    const std::string& device_id, bool automatic_gain_control) {
  VLOG(1) << "AudioInputRendererHost::OnCreateStream(stream_id="
          << stream_id << ")";
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK(LookupById(stream_id) == NULL);

  media::AudioParameters audio_params(params);

  DCHECK_GT(audio_params.frames_per_buffer(), 0);
  uint32 buffer_size = audio_params.GetBytesPerBuffer();

  // Create a new AudioEntry structure.
  scoped_ptr<AudioEntry> entry(new AudioEntry());

  uint32 mem_size = sizeof(media::AudioInputBufferParameters) + buffer_size;

  // Create the shared memory and share it with the renderer process
  // using a new SyncWriter object.
  if (!entry->shared_memory.CreateAndMapAnonymous(mem_size)) {
    // If creation of shared memory failed then send an error message.
    SendErrorMessage(stream_id);
    return;
  }

  scoped_ptr<media::AudioInputSyncWriter> writer(
      new media::AudioInputSyncWriter(&entry->shared_memory));

  if (!writer->Init()) {
    SendErrorMessage(stream_id);
    return;
  }

  // If we have successfully created the SyncWriter then assign it to the
  // entry and construct an AudioInputController.
  // TODO(henrika): replace CreateLowLatency() with Create() as soon
  // as satish has ensured that Speech Input also uses the default low-
  // latency path. See crbug.com/112472 for details.
  entry->writer.reset(writer.release());
  entry->controller = media::AudioInputController::CreateLowLatency(
      audio_manager_,
      this,
      audio_params,
      device_id,
      entry->writer.get());

  if (!entry->controller) {
    SendErrorMessage(stream_id);
    return;
  }

  // Set the initial AGC state for the audio input stream.
  entry->controller->SetAutomaticGainControl(automatic_gain_control);

  // If we have created the controller successfully create a entry and add it
  // to the map.
  entry->stream_id = stream_id;

  audio_entries_.insert(std::make_pair(stream_id, entry.release()));
}

void AudioInputRendererHost::OnRecordStream(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);
  if (!entry) {
    SendErrorMessage(stream_id);
    return;
  }

  entry->controller->Record();
}

void AudioInputRendererHost::OnCloseStream(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);

  if (entry)
    CloseAndDeleteStream(entry);

  int session_id = LookupSessionById(stream_id);

  if (session_id)
    StopAndDeleteDevice(session_id);
}

void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntry* entry = LookupById(stream_id);
  if (!entry) {
    SendErrorMessage(stream_id);
    return;
  }

  entry->controller->SetVolume(volume);
}

void AudioInputRendererHost::SendErrorMessage(int stream_id) {
  Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id,
                                                  kAudioStreamError));
}

void AudioInputRendererHost::DeleteEntries() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  for (AudioEntryMap::iterator i = audio_entries_.begin();
       i != audio_entries_.end(); ++i) {
    CloseAndDeleteStream(i->second);
  }
}

void AudioInputRendererHost::OnDeviceStarted(
    int session_id, const std::string& device_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  SessionEntryMap::iterator it = session_entries_.find(session_id);
  if (it == session_entries_.end()) {
    DLOG(WARNING) << "AudioInputRendererHost::OnDeviceStarted()"
        " session does not exist.";
    return;
  }

  // Notify the renderer with the id of the opened device.
  Send(new AudioInputMsg_NotifyDeviceStarted(it->second, device_id));
}

void AudioInputRendererHost::OnDeviceStopped(int session_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  SessionEntryMap::iterator it = session_entries_.find(session_id);
  // Return if the stream has been closed.
  if (it == session_entries_.end())
    return;

  int stream_id = it->second;
  AudioEntry* entry = LookupById(stream_id);

  if (entry) {
    // Device has been stopped, close the input stream.
    CloseAndDeleteStream(entry);
    // Notify the renderer that the state of the input stream has changed.
    Send(new AudioInputMsg_NotifyStreamStateChanged(stream_id,
                                                    kAudioStreamPaused));
  }

  // Delete the session entry.
  session_entries_.erase(it);
}

void AudioInputRendererHost::StopAndDeleteDevice(int session_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  media_stream::AudioInputDeviceManager* audio_input_man =
      media_stream::MediaStreamManager::GetForResourceContext(
          resource_context_, audio_manager_)->audio_input_device_manager();
  audio_input_man->Stop(session_id);

  // Delete the session entry.
  session_entries_.erase(session_id);
}

void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (!entry->pending_close) {
    entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
                                        this, entry));
    entry->pending_close = true;
  }
}

void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Delete the entry when this method goes out of scope.
  scoped_ptr<AudioEntry> entry_deleter(entry);

  // Erase the entry from the map.
  audio_entries_.erase(entry->stream_id);
}

void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Sends the error message first before we close the stream because
  // |entry| is destroyed in DeleteEntry().
  SendErrorMessage(entry->stream_id);
  CloseAndDeleteStream(entry);
}

AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
    int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  AudioEntryMap::iterator i = audio_entries_.find(stream_id);
  if (i != audio_entries_.end())
    return i->second;
  return NULL;
}

AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
    media::AudioInputController* controller) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // Iterate the map of entries.
  // TODO(hclam): Implement a faster look up method.
  for (AudioEntryMap::iterator i = audio_entries_.begin();
       i != audio_entries_.end(); ++i) {
    if (controller == i->second->controller.get())
      return i->second;
  }
  return NULL;
}

int AudioInputRendererHost::LookupSessionById(int stream_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  for (SessionEntryMap::iterator it = session_entries_.begin();
       it != session_entries_.end(); ++it) {
    if (stream_id == it->second) {
      return it->first;
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>/* Copyright 2017 Istio Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/istio/control/tcp/attributes_builder.h"

#include "include/istio/utils/attribute_names.h"
#include "include/istio/utils/attributes_builder.h"

namespace istio {
namespace control {
namespace tcp {
namespace {
// Connection events for TCP connection.
const std::string kConnectionOpen("open");
const std::string kConnectionContinue("continue");
const std::string kConnectionClose("close");
}  // namespace

void AttributesBuilder::ExtractCheckAttributes(CheckData* check_data) {
  utils::AttributesBuilder builder(&request_->attributes);

  std::string source_ip;
  int source_port;
  // TODO(kuat): there is no way to propagate source IP in TCP, so we auto-set
  // it
  if (check_data->GetSourceIpPort(&source_ip, &source_port)) {
    builder.AddBytes(utils::AttributeName::kSourceIp, source_ip);
  }

  // TODO(diemtvu): add TCP authn filter similar to http case, and use authn
  // result output here instead.
  std::string source_user;
  if (check_data->GetSourceUser(&source_user)) {
    // TODO(diemtvu): remove kSourceUser once migration to source.principal is
    // over. https://github.com/istio/istio/issues/4689
    builder.AddString(utils::AttributeName::kSourceUser, source_user);
    builder.AddString(utils::AttributeName::kSourcePrincipal, source_user);
  }
  builder.AddBool(utils::AttributeName::kConnectionMtls,
                  check_data->IsMutualTLS());

  std::string requested_server_name = check_data->GetRequestedServerName());
  if (!requested_server_name.empty()) {
    builder.AddString(utils::AttributeName::kConnectionRequestedServerName,
                      requested_server_name);
  }

  builder.AddTimestamp(utils::AttributeName::kContextTime,
                       std::chrono::system_clock::now());
  builder.AddString(utils::AttributeName::kContextProtocol, "tcp");
  builder.AddString(utils::AttributeName::kConnectionEvent, kConnectionOpen);

  // Get unique downstream connection ID, which is <uuid>-<connection id>.
  std::string connection_id = check_data->GetConnectionId();
  builder.AddString(utils::AttributeName::kConnectionId, connection_id);
}

void AttributesBuilder::ExtractReportAttributes(
    ReportData* report_data, bool is_final_report,
    ReportData::ReportInfo* last_report_info) {
  utils::AttributesBuilder builder(&request_->attributes);

  ReportData::ReportInfo info;
  report_data->GetReportInfo(&info);
  builder.AddInt64(utils::AttributeName::kConnectionReceviedBytes,
                   info.received_bytes - last_report_info->received_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionReceviedTotalBytes,
                   info.received_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionSendBytes,
                   info.send_bytes - last_report_info->send_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionSendTotalBytes,
                   info.send_bytes);

  if (is_final_report) {
    builder.AddDuration(utils::AttributeName::kConnectionDuration,
                        info.duration);
    if (!request_->check_status.ok()) {
      builder.AddInt64(utils::AttributeName::kCheckErrorCode,
                       request_->check_status.error_code());
      builder.AddString(utils::AttributeName::kCheckErrorMessage,
                        request_->check_status.ToString());
    }
    builder.AddString(utils::AttributeName::kConnectionEvent, kConnectionClose);
  } else {
    last_report_info->received_bytes = info.received_bytes;
    last_report_info->send_bytes = info.send_bytes;
    builder.AddString(utils::AttributeName::kConnectionEvent,
                      kConnectionContinue);
  }

  std::string dest_ip;
  int dest_port;
  // Do not overwrite destination IP and port if it has already been set.
  if (report_data->GetDestinationIpPort(&dest_ip, &dest_port)) {
    if (!builder.HasAttribute(utils::AttributeName::kDestinationIp)) {
      builder.AddBytes(utils::AttributeName::kDestinationIp, dest_ip);
    }
    if (!builder.HasAttribute(utils::AttributeName::kDestinationPort)) {
      builder.AddInt64(utils::AttributeName::kDestinationPort, dest_port);
    }
  }

  std::string uid;
  if (report_data->GetDestinationUID(&uid)) {
    builder.AddString(utils::AttributeName::kDestinationUID, uid);
  }

  builder.AddTimestamp(utils::AttributeName::kContextTime,
                       std::chrono::system_clock::now());
}

}  // namespace tcp
}  // namespace control
}  // namespace istio
<commit_msg>fixed a compilation error<commit_after>/* Copyright 2017 Istio Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/istio/control/tcp/attributes_builder.h"

#include "include/istio/utils/attribute_names.h"
#include "include/istio/utils/attributes_builder.h"

namespace istio {
namespace control {
namespace tcp {
namespace {
// Connection events for TCP connection.
const std::string kConnectionOpen("open");
const std::string kConnectionContinue("continue");
const std::string kConnectionClose("close");
}  // namespace

void AttributesBuilder::ExtractCheckAttributes(CheckData* check_data) {
  utils::AttributesBuilder builder(&request_->attributes);

  std::string source_ip;
  int source_port;
  // TODO(kuat): there is no way to propagate source IP in TCP, so we auto-set
  // it
  if (check_data->GetSourceIpPort(&source_ip, &source_port)) {
    builder.AddBytes(utils::AttributeName::kSourceIp, source_ip);
  }

  // TODO(diemtvu): add TCP authn filter similar to http case, and use authn
  // result output here instead.
  std::string source_user;
  if (check_data->GetSourceUser(&source_user)) {
    // TODO(diemtvu): remove kSourceUser once migration to source.principal is
    // over. https://github.com/istio/istio/issues/4689
    builder.AddString(utils::AttributeName::kSourceUser, source_user);
    builder.AddString(utils::AttributeName::kSourcePrincipal, source_user);
  }
  builder.AddBool(utils::AttributeName::kConnectionMtls,
                  check_data->IsMutualTLS());

  std::string requested_server_name = check_data->GetRequestedServerName();
  if (!requested_server_name.empty()) {
    builder.AddString(utils::AttributeName::kConnectionRequestedServerName,
                      requested_server_name);
  }

  builder.AddTimestamp(utils::AttributeName::kContextTime,
                       std::chrono::system_clock::now());
  builder.AddString(utils::AttributeName::kContextProtocol, "tcp");
  builder.AddString(utils::AttributeName::kConnectionEvent, kConnectionOpen);

  // Get unique downstream connection ID, which is <uuid>-<connection id>.
  std::string connection_id = check_data->GetConnectionId();
  builder.AddString(utils::AttributeName::kConnectionId, connection_id);
}

void AttributesBuilder::ExtractReportAttributes(
    ReportData* report_data, bool is_final_report,
    ReportData::ReportInfo* last_report_info) {
  utils::AttributesBuilder builder(&request_->attributes);

  ReportData::ReportInfo info;
  report_data->GetReportInfo(&info);
  builder.AddInt64(utils::AttributeName::kConnectionReceviedBytes,
                   info.received_bytes - last_report_info->received_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionReceviedTotalBytes,
                   info.received_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionSendBytes,
                   info.send_bytes - last_report_info->send_bytes);
  builder.AddInt64(utils::AttributeName::kConnectionSendTotalBytes,
                   info.send_bytes);

  if (is_final_report) {
    builder.AddDuration(utils::AttributeName::kConnectionDuration,
                        info.duration);
    if (!request_->check_status.ok()) {
      builder.AddInt64(utils::AttributeName::kCheckErrorCode,
                       request_->check_status.error_code());
      builder.AddString(utils::AttributeName::kCheckErrorMessage,
                        request_->check_status.ToString());
    }
    builder.AddString(utils::AttributeName::kConnectionEvent, kConnectionClose);
  } else {
    last_report_info->received_bytes = info.received_bytes;
    last_report_info->send_bytes = info.send_bytes;
    builder.AddString(utils::AttributeName::kConnectionEvent,
                      kConnectionContinue);
  }

  std::string dest_ip;
  int dest_port;
  // Do not overwrite destination IP and port if it has already been set.
  if (report_data->GetDestinationIpPort(&dest_ip, &dest_port)) {
    if (!builder.HasAttribute(utils::AttributeName::kDestinationIp)) {
      builder.AddBytes(utils::AttributeName::kDestinationIp, dest_ip);
    }
    if (!builder.HasAttribute(utils::AttributeName::kDestinationPort)) {
      builder.AddInt64(utils::AttributeName::kDestinationPort, dest_port);
    }
  }

  std::string uid;
  if (report_data->GetDestinationUID(&uid)) {
    builder.AddString(utils::AttributeName::kDestinationUID, uid);
  }

  builder.AddTimestamp(utils::AttributeName::kContextTime,
                       std::chrono::system_clock::now());
}

}  // namespace tcp
}  // namespace control
}  // namespace istio
<|endoftext|>