<commit_before>// Copyright (c) 2006-2009 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 "chrome/browser/shell_integration.h"

#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_paths.h"
#include "googleurl/src/gurl.h"

namespace {

const char* GetDesktopName() {
#if defined(GOOGLE_CHROME_BUILD)
  return "google-chrome.desktop";
#else  // CHROMIUM_BUILD
  static const char* name = NULL;
  if (!name) {
    // Allow $CHROME_DESKTOP to override the built-in value, so that development
    // versions can set themselves as the default without interfering with
    // non-official, packaged versions using the built-in value.
    name = getenv("CHROME_DESKTOP");
    if (!name)
      name = "chromium-browser.desktop";
  }
  return name;
#endif
}

bool GetDesktopShortcutTemplate(std::string* output) {
  std::vector<std::string> search_paths;

  const char* xdg_data_home = getenv("XDG_DATA_HOME");
  if (xdg_data_home)
    search_paths.push_back(xdg_data_home);

  const char* xdg_data_dirs = getenv("XDG_DATA_DIRS");
  if (xdg_data_dirs) {
    StringTokenizer tokenizer(xdg_data_dirs, ":");
    while (tokenizer.GetNext()) {
      search_paths.push_back(tokenizer.token());
    }
  }

  std::string template_filename(GetDesktopName());
  for (std::vector<std::string>::const_iterator i = search_paths.begin();
       i != search_paths.end(); ++i) {
    FilePath path = FilePath(*i).Append(template_filename);
    if (file_util::PathExists(path))
      return file_util::ReadFileToString(path, output);
  }

  return false;
}

class CreateDesktopShortcutTask : public Task {
 public:
  CreateDesktopShortcutTask(const GURL& url, const string16& title)
      : url_(url),
        title_(title) {
  }

  virtual void Run() {
    // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
    FilePath desktop_path;
    if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
      return;
    desktop_path =
        desktop_path.Append(ShellIntegration::GetDesktopShortcutFilename(url_));

    if (file_util::PathExists(desktop_path))
      return;

    std::string template_contents;
    if (!GetDesktopShortcutTemplate(&template_contents))
      return;

    std::string contents = ShellIntegration::GetDesktopFileContents(
        template_contents, url_, title_);
    int bytes_written = file_util::WriteFile(desktop_path, contents.data(),
                                             contents.length());
    if (bytes_written != static_cast<int>(contents.length())) {
      file_util::Delete(desktop_path, false);
    }
  }

 private:
  const GURL url_;  // URL of the web application.
  const string16 title_;  // Title displayed to the user.

  DISALLOW_COPY_AND_ASSIGN(CreateDesktopShortcutTask);
};

}  // namespace

// We delegate the difficult of setting the default browser in Linux desktop
// environments to a new xdg utility, xdg-settings. We'll have to include a copy
// of it for this to work, obviously, but that's actually the suggested approach
// for xdg utilities anyway.

bool ShellIntegration::SetAsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("set");
  argv.push_back("default-web-browser");
  argv.push_back(GetDesktopName());

  // xdg-settings internally runs xdg-mime, which uses mv to move newly-created
  // files on top of originals after making changes to them. In the event that
  // the original files are owned by another user (e.g. root, which can happen
  // if they are updated within sudo), mv will prompt the user to confirm if
  // standard input is a terminal (otherwise it just does it). So make sure it's
  // not, to avoid locking everything up waiting for mv.
  int devnull = open("/dev/null", O_RDONLY);
  if (devnull < 0)
    return false;
  base::file_handle_mapping_vector no_stdin;
  no_stdin.push_back(std::make_pair(devnull, STDIN_FILENO));

  base::ProcessHandle handle;
  if (!base::LaunchApp(argv, no_stdin, false, &handle)) {
    close(devnull);
    return false;
  }
  close(devnull);

  int success_code;
  base::WaitForExitCode(handle, &success_code);
  return success_code == EXIT_SUCCESS;
}

bool ShellIntegration::IsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("check");
  argv.push_back("default-web-browser");
  argv.push_back(GetDesktopName());

  std::string reply;
  if (!base::GetAppOutput(CommandLine(argv), &reply)) {
    // If xdg-settings fails, we assume that we should pretend we're the default
    // browser to avoid giving repeated prompts to set ourselves as the default.
    // TODO(mdm): Really, being the default browser should be a ternary query:
    // yes, no, and "don't know" so the UI can reflect this more accurately.
    return true;
  }

  // Allow any reply that starts with "yes".
  return reply.find("yes") == 0;
}

bool ShellIntegration::IsFirefoxDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("get");
  argv.push_back("default-web-browser");

  std::string browser;
  // We don't care about the return value here.
  base::GetAppOutput(CommandLine(argv), &browser);
  return browser.find("irefox") != std::string::npos;
}

FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
  std::wstring filename = UTF8ToWide(url.spec()) + L".desktop";
  file_util::ReplaceIllegalCharacters(&filename, '_');

  // Return BaseName to be absolutely sure we're not vulnerable to a directory
  // traversal attack.
  return FilePath::FromWStringHack(filename).BaseName();
}

std::string ShellIntegration::GetDesktopFileContents(
    const std::string& template_contents, const GURL& url,
    const string16& title) {
  // See http://standards.freedesktop.org/desktop-entry-spec/latest/
  std::string output_buffer;
  StringTokenizer tokenizer(template_contents, "\n");
  while (tokenizer.GetNext()) {
    // TODO(phajdan.jr): Add the icon.

    if (tokenizer.token().substr(0, 5) == "Exec=") {
      std::string exec_path = tokenizer.token().substr(5);
      StringTokenizer exec_tokenizer(exec_path, " ");
      std::string final_path;
      while (exec_tokenizer.GetNext()) {
        if (exec_tokenizer.token() != "%U")
          final_path += exec_tokenizer.token() + " ";
      }
      std::string app_switch(StringPrintf("\"--app=%s\"",
                                          url.spec().c_str()));
      ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%");
      output_buffer += std::string("Exec=") + final_path + app_switch + "\n";
    } else if (tokenizer.token().substr(0, 5) == "Name=") {
      std::string final_title = UTF16ToUTF8(title);
      // Make sure no endline characters can slip in and possibly introduce
      // additional lines (like Exec, which makes it a security risk). Also
      // use the URL as a default when the title is empty.
      if (final_title.empty() ||
          final_title.find("\n") != std::string::npos ||
          final_title.find("\r") != std::string::npos)
        final_title = url.spec();
      output_buffer += StringPrintf("Name=%s\n", final_title.c_str());
    } else if (tokenizer.token().substr(0, 8) == "Comment=") {
      // Skip the line.
    } else {
      output_buffer += tokenizer.token() + "\n";
    }
  }
  return output_buffer;
}

void ShellIntegration::CreateDesktopShortcut(const GURL& url,
                                             const string16& title) {
  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      new CreateDesktopShortcutTask(url, title));
}
<commit_msg>Linux: use switches::kApp instead of "--app" when creating .desktop files. BUG=none TEST=none<commit_after>// Copyright (c) 2006-2009 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 "chrome/browser/shell_integration.h"

#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "googleurl/src/gurl.h"

namespace {

const char* GetDesktopName() {
#if defined(GOOGLE_CHROME_BUILD)
  return "google-chrome.desktop";
#else  // CHROMIUM_BUILD
  static const char* name = NULL;
  if (!name) {
    // Allow $CHROME_DESKTOP to override the built-in value, so that development
    // versions can set themselves as the default without interfering with
    // non-official, packaged versions using the built-in value.
    name = getenv("CHROME_DESKTOP");
    if (!name)
      name = "chromium-browser.desktop";
  }
  return name;
#endif
}

bool GetDesktopShortcutTemplate(std::string* output) {
  std::vector<std::string> search_paths;

  const char* xdg_data_home = getenv("XDG_DATA_HOME");
  if (xdg_data_home)
    search_paths.push_back(xdg_data_home);

  const char* xdg_data_dirs = getenv("XDG_DATA_DIRS");
  if (xdg_data_dirs) {
    StringTokenizer tokenizer(xdg_data_dirs, ":");
    while (tokenizer.GetNext()) {
      search_paths.push_back(tokenizer.token());
    }
  }

  std::string template_filename(GetDesktopName());
  for (std::vector<std::string>::const_iterator i = search_paths.begin();
       i != search_paths.end(); ++i) {
    FilePath path = FilePath(*i).Append(template_filename);
    if (file_util::PathExists(path))
      return file_util::ReadFileToString(path, output);
  }

  return false;
}

class CreateDesktopShortcutTask : public Task {
 public:
  CreateDesktopShortcutTask(const GURL& url, const string16& title)
      : url_(url),
        title_(title) {
  }

  virtual void Run() {
    // TODO(phajdan.jr): Report errors from this function, possibly as infobars.
    FilePath desktop_path;
    if (!PathService::Get(chrome::DIR_USER_DESKTOP, &desktop_path))
      return;
    desktop_path =
        desktop_path.Append(ShellIntegration::GetDesktopShortcutFilename(url_));

    if (file_util::PathExists(desktop_path))
      return;

    std::string template_contents;
    if (!GetDesktopShortcutTemplate(&template_contents))
      return;

    std::string contents = ShellIntegration::GetDesktopFileContents(
        template_contents, url_, title_);
    int bytes_written = file_util::WriteFile(desktop_path, contents.data(),
                                             contents.length());
    if (bytes_written != static_cast<int>(contents.length())) {
      file_util::Delete(desktop_path, false);
    }
  }

 private:
  const GURL url_;  // URL of the web application.
  const string16 title_;  // Title displayed to the user.

  DISALLOW_COPY_AND_ASSIGN(CreateDesktopShortcutTask);
};

}  // namespace

// We delegate the difficult of setting the default browser in Linux desktop
// environments to a new xdg utility, xdg-settings. We'll have to include a copy
// of it for this to work, obviously, but that's actually the suggested approach
// for xdg utilities anyway.

bool ShellIntegration::SetAsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("set");
  argv.push_back("default-web-browser");
  argv.push_back(GetDesktopName());

  // xdg-settings internally runs xdg-mime, which uses mv to move newly-created
  // files on top of originals after making changes to them. In the event that
  // the original files are owned by another user (e.g. root, which can happen
  // if they are updated within sudo), mv will prompt the user to confirm if
  // standard input is a terminal (otherwise it just does it). So make sure it's
  // not, to avoid locking everything up waiting for mv.
  int devnull = open("/dev/null", O_RDONLY);
  if (devnull < 0)
    return false;
  base::file_handle_mapping_vector no_stdin;
  no_stdin.push_back(std::make_pair(devnull, STDIN_FILENO));

  base::ProcessHandle handle;
  if (!base::LaunchApp(argv, no_stdin, false, &handle)) {
    close(devnull);
    return false;
  }
  close(devnull);

  int success_code;
  base::WaitForExitCode(handle, &success_code);
  return success_code == EXIT_SUCCESS;
}

bool ShellIntegration::IsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("check");
  argv.push_back("default-web-browser");
  argv.push_back(GetDesktopName());

  std::string reply;
  if (!base::GetAppOutput(CommandLine(argv), &reply)) {
    // If xdg-settings fails, we assume that we should pretend we're the default
    // browser to avoid giving repeated prompts to set ourselves as the default.
    // TODO(mdm): Really, being the default browser should be a ternary query:
    // yes, no, and "don't know" so the UI can reflect this more accurately.
    return true;
  }

  // Allow any reply that starts with "yes".
  return reply.find("yes") == 0;
}

bool ShellIntegration::IsFirefoxDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("get");
  argv.push_back("default-web-browser");

  std::string browser;
  // We don't care about the return value here.
  base::GetAppOutput(CommandLine(argv), &browser);
  return browser.find("irefox") != std::string::npos;
}

FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
  std::wstring filename = UTF8ToWide(url.spec()) + L".desktop";
  file_util::ReplaceIllegalCharacters(&filename, '_');

  // Return BaseName to be absolutely sure we're not vulnerable to a directory
  // traversal attack.
  return FilePath::FromWStringHack(filename).BaseName();
}

std::string ShellIntegration::GetDesktopFileContents(
    const std::string& template_contents, const GURL& url,
    const string16& title) {
  // See http://standards.freedesktop.org/desktop-entry-spec/latest/
  std::string output_buffer;
  StringTokenizer tokenizer(template_contents, "\n");
  while (tokenizer.GetNext()) {
    // TODO(phajdan.jr): Add the icon.

    if (tokenizer.token().substr(0, 5) == "Exec=") {
      std::string exec_path = tokenizer.token().substr(5);
      StringTokenizer exec_tokenizer(exec_path, " ");
      std::string final_path;
      while (exec_tokenizer.GetNext()) {
        if (exec_tokenizer.token() != "%U")
          final_path += exec_tokenizer.token() + " ";
      }
      std::wstring app_switch_wide(switches::kApp);
      std::string app_switch(StringPrintf("\"--%s=%s\"",
                                          WideToUTF8(app_switch_wide).c_str(),
                                          url.spec().c_str()));
      ReplaceSubstringsAfterOffset(&app_switch, 0, "%", "%%");
      output_buffer += std::string("Exec=") + final_path + app_switch + "\n";
    } else if (tokenizer.token().substr(0, 5) == "Name=") {
      std::string final_title = UTF16ToUTF8(title);
      // Make sure no endline characters can slip in and possibly introduce
      // additional lines (like Exec, which makes it a security risk). Also
      // use the URL as a default when the title is empty.
      if (final_title.empty() ||
          final_title.find("\n") != std::string::npos ||
          final_title.find("\r") != std::string::npos)
        final_title = url.spec();
      output_buffer += StringPrintf("Name=%s\n", final_title.c_str());
    } else if (tokenizer.token().substr(0, 8) == "Comment=") {
      // Skip the line.
    } else {
      output_buffer += tokenizer.token() + "\n";
    }
  }
  return output_buffer;
}

void ShellIntegration::CreateDesktopShortcut(const GURL& url,
                                             const string16& title) {
  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      new CreateDesktopShortcutTask(url, title));
}
<|endoftext|>


<commit_before>//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a JITEventListener object that calls into OProfile to tell
// it about JITted functions.  For now, we only record function names and sizes,
// but eventually we'll also record line number information.
//
// See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
// definition of the interface we're using.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "oprofile-jit-event-listener"
#include "llvm/Function.h"
#include "llvm/Metadata.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Errno.h"
#include "llvm/Config/config.h"
#include <stddef.h>
using namespace llvm;

#if USE_OPROFILE

#include <opagent.h>

namespace {

class OProfileJITEventListener : public JITEventListener {
  op_agent_t Agent;
public:
  OProfileJITEventListener();
  ~OProfileJITEventListener();

  virtual void NotifyFunctionEmitted(const Function &F,
                                     void *FnStart, size_t FnSize,
                                     const EmittedFunctionDetails &Details);
  virtual void NotifyFreeingMachineCode(void *OldPtr);
};

OProfileJITEventListener::OProfileJITEventListener()
    : Agent(op_open_agent()) {
  if (Agent == NULL) {
    const std::string err_str = sys::StrError();
    DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
  } else {
    DEBUG(dbgs() << "Connected to OProfile agent.\n");
  }
}

OProfileJITEventListener::~OProfileJITEventListener() {
  if (Agent != NULL) {
    if (op_close_agent(Agent) == -1) {
      const std::string err_str = sys::StrError();
      DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
                   << err_str << "\n");
    } else {
      DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
    }
  }
}

class FilenameCache {
  // Holds the filename of each Scope, so that we can pass a null-terminated
  // string into oprofile.  Use an AssertingVH rather than a ValueMap because we
  // shouldn't be modifying any MDNodes while this map is alive.
  DenseMap<AssertingVH<MDNode>, std::string> Filenames;

 public:
  const char *getFilename(DIScope Scope) {
    std::string &Filename = Filenames[Scope.getNode()];
    if (Filename.empty()) {
      Filename = Scope.getFilename();
    }
    return Filename.c_str();
  }
};

static debug_line_info LineStartToOProfileFormat(
    const MachineFunction &MF, FilenameCache &Filenames,
    uintptr_t Address, DebugLoc Loc) {
  debug_line_info Result;
  Result.vma = Address;
  DILocation DILoc = MF.getDILocation(Loc);
  Result.lineno = DILoc.getLineNumber();
  Result.filename = Filenames.getFilename(DILoc.getScope());
  DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
               << Result.filename << ":" << Result.lineno << "\n");
  return Result;
}

// Adds the just-emitted function to the symbol table.
void OProfileJITEventListener::NotifyFunctionEmitted(
    const Function &F, void *FnStart, size_t FnSize,
    const EmittedFunctionDetails &Details) {
  assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
  if (op_write_native_code(Agent, F.getName().data(),
                           reinterpret_cast<uint64_t>(FnStart),
                           FnStart, FnSize) == -1) {
    DEBUG(dbgs() << "Failed to tell OProfile about native function "
          << F.getName() << " at ["
          << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
    return;
  }

  // Now we convert the line number information from the address/DebugLoc format
  // in Details to the address/filename/lineno format that OProfile expects.
  // OProfile 0.9.4 (and maybe later versions) has a bug that causes it to
  // ignore line numbers for addresses above 4G.
  FilenameCache Filenames;
  std::vector<debug_line_info> LineInfo;
  LineInfo.reserve(1 + Details.LineStarts.size());
  if (!Details.MF->getDefaultDebugLoc().isUnknown()) {
    LineInfo.push_back(LineStartToOProfileFormat(
        *Details.MF, Filenames,
        reinterpret_cast<uintptr_t>(FnStart),
        Details.MF->getDefaultDebugLoc()));
  }
  for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
           I = Details.LineStarts.begin(), E = Details.LineStarts.end();
       I != E; ++I) {
    LineInfo.push_back(LineStartToOProfileFormat(
        *Details.MF, Filenames, I->Address, I->Loc));
  }
  if (!LineInfo.empty()) {
    if (op_write_debug_line_info(Agent, FnStart,
                                 LineInfo.size(), &*LineInfo.begin()) == -1) {
      DEBUG(dbgs()
            << "Failed to tell OProfile about line numbers for native function "
            << F.getName() << " at ["
            << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
    }
  }
}

// Removes the being-deleted function from the symbol table.
void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
  assert(FnStart && "Invalid function pointer");
  if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) {
    DEBUG(dbgs()
          << "Failed to tell OProfile about unload of native function at "
          << FnStart << "\n");
  }
}

}  // anonymous namespace.

namespace llvm {
JITEventListener *createOProfileJITEventListener() {
  return new OProfileJITEventListener;
}
}

#else  // USE_OPROFILE

namespace llvm {
// By defining this to return NULL, we can let clients call it unconditionally,
// even if they haven't configured with the OProfile libraries.
JITEventListener *createOProfileJITEventListener() {
  return NULL;
}
}  // namespace llvm

#endif  // USE_OPROFILE
<commit_msg>Fix OProfileJITEventListener build for new DebugLoc.<commit_after>//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a JITEventListener object that calls into OProfile to tell
// it about JITted functions.  For now, we only record function names and sizes,
// but eventually we'll also record line number information.
//
// See http://oprofile.sourceforge.net/doc/devel/jit-interface.html for the
// definition of the interface we're using.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "oprofile-jit-event-listener"
#include "llvm/Function.h"
#include "llvm/Metadata.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Errno.h"
#include "llvm/Config/config.h"
#include <stddef.h>
using namespace llvm;

#if USE_OPROFILE

#include <opagent.h>

namespace {

class OProfileJITEventListener : public JITEventListener {
  op_agent_t Agent;
public:
  OProfileJITEventListener();
  ~OProfileJITEventListener();

  virtual void NotifyFunctionEmitted(const Function &F,
                                     void *FnStart, size_t FnSize,
                                     const EmittedFunctionDetails &Details);
  virtual void NotifyFreeingMachineCode(void *OldPtr);
};

OProfileJITEventListener::OProfileJITEventListener()
    : Agent(op_open_agent()) {
  if (Agent == NULL) {
    const std::string err_str = sys::StrError();
    DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n");
  } else {
    DEBUG(dbgs() << "Connected to OProfile agent.\n");
  }
}

OProfileJITEventListener::~OProfileJITEventListener() {
  if (Agent != NULL) {
    if (op_close_agent(Agent) == -1) {
      const std::string err_str = sys::StrError();
      DEBUG(dbgs() << "Failed to disconnect from OProfile agent: "
                   << err_str << "\n");
    } else {
      DEBUG(dbgs() << "Disconnected from OProfile agent.\n");
    }
  }
}

class FilenameCache {
  // Holds the filename of each Scope, so that we can pass a null-terminated
  // string into oprofile.  Use an AssertingVH rather than a ValueMap because we
  // shouldn't be modifying any MDNodes while this map is alive.
  DenseMap<AssertingVH<MDNode>, std::string> Filenames;

 public:
  const char *getFilename(MDNode *Scope) {
    std::string &Filename = Filenames[Scope];
    if (Filename.empty()) {
      Filename = DIScope(Scope).getFilename();
    }
    return Filename.c_str();
  }
};

static debug_line_info LineStartToOProfileFormat(
    const MachineFunction &MF, FilenameCache &Filenames,
    uintptr_t Address, DebugLoc Loc) {
  debug_line_info Result;
  Result.vma = Address;
  Result.lineno = Loc.getLine();
  Result.filename = Filenames.getFilename(
    Loc.getScope(MF.getFunction()->getContext()));
  DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to "
               << Result.filename << ":" << Result.lineno << "\n");
  return Result;
}

// Adds the just-emitted function to the symbol table.
void OProfileJITEventListener::NotifyFunctionEmitted(
    const Function &F, void *FnStart, size_t FnSize,
    const EmittedFunctionDetails &Details) {
  assert(F.hasName() && FnStart != 0 && "Bad symbol to add");
  if (op_write_native_code(Agent, F.getName().data(),
                           reinterpret_cast<uint64_t>(FnStart),
                           FnStart, FnSize) == -1) {
    DEBUG(dbgs() << "Failed to tell OProfile about native function "
          << F.getName() << " at ["
          << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
    return;
  }

  // Now we convert the line number information from the address/DebugLoc format
  // in Details to the address/filename/lineno format that OProfile expects.
  // OProfile 0.9.4 (and maybe later versions) has a bug that causes it to
  // ignore line numbers for addresses above 4G.
  FilenameCache Filenames;
  std::vector<debug_line_info> LineInfo;
  LineInfo.reserve(1 + Details.LineStarts.size());
  if (!Details.MF->getDefaultDebugLoc().isUnknown()) {
    LineInfo.push_back(LineStartToOProfileFormat(
        *Details.MF, Filenames,
        reinterpret_cast<uintptr_t>(FnStart),
        Details.MF->getDefaultDebugLoc()));
  }
  for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator
           I = Details.LineStarts.begin(), E = Details.LineStarts.end();
       I != E; ++I) {
    LineInfo.push_back(LineStartToOProfileFormat(
        *Details.MF, Filenames, I->Address, I->Loc));
  }
  if (!LineInfo.empty()) {
    if (op_write_debug_line_info(Agent, FnStart,
                                 LineInfo.size(), &*LineInfo.begin()) == -1) {
      DEBUG(dbgs()
            << "Failed to tell OProfile about line numbers for native function "
            << F.getName() << " at ["
            << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n");
    }
  }
}

// Removes the being-deleted function from the symbol table.
void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) {
  assert(FnStart && "Invalid function pointer");
  if (op_unload_native_code(Agent, reinterpret_cast<uint64_t>(FnStart)) == -1) {
    DEBUG(dbgs()
          << "Failed to tell OProfile about unload of native function at "
          << FnStart << "\n");
  }
}

}  // anonymous namespace.

namespace llvm {
JITEventListener *createOProfileJITEventListener() {
  return new OProfileJITEventListener;
}
}

#else  // USE_OPROFILE

namespace llvm {
// By defining this to return NULL, we can let clients call it unconditionally,
// even if they haven't configured with the OProfile libraries.
JITEventListener *createOProfileJITEventListener() {
  return NULL;
}
}  // namespace llvm

#endif  // USE_OPROFILE
<|endoftext|>


<commit_before>#ifndef IMAGE_CLOUD_COMMON_PIPELINE_IMAGE_H_
#define IMAGE_CLOUD_COMMON_PIPELINE_IMAGE_H_

#include <assert.h>
#include <opencv2/opencv.hpp>

namespace image_cloud{
	inline void convert_to_grey(const cv::Mat &in_unknown, cv::Mat &grey){
		// Convert Greyscale
		if (in_unknown.channels() != 1) {
			cvtColor(in_unknown, grey, CV_BGR2GRAY);
			assert(grey.channels() == 1);
		} else {
			in_unknown.copyTo(grey);
		}
	}

	inline void create_empty_grey_mat(cv::Mat &image, int rows, int cols){
		image.create(rows, cols, CV_8U);
		image = cv::Mat::zeros(rows, cols, CV_8U);
	}

	/**	Create inverse transformed image
	 * 	Grayscale the image
	 * 	Edge Filter
	 * 	Inverse distance transformation
	 */
	inline void create_inverse_transformed(const cv::Mat& in, cv::Mat &out){
		cv::Mat grey,edge;

		create_empty_grey_mat(edge, in.rows, in.cols);
		create_empty_grey_mat(out, in.rows, in.cols);

		// Convert Greyscale
		convert_to_grey(in, grey);

		// Edge filter
		filter_2d::edge_max<uchar>( grey, edge);

		// Inverse distance transform
		filter_2d::inverse_distance_transformation<uchar,uchar>(edge, out);
	}
}
#endif
<commit_msg>added switches for edge and blur filters<commit_after>#ifndef IMAGE_CLOUD_COMMON_PIPELINE_IMAGE_H_
#define IMAGE_CLOUD_COMMON_PIPELINE_IMAGE_H_

#include <assert.h>
#include <opencv2/opencv.hpp>

#include <image_cloud/common/calibration/pipeline/enums.h>

namespace image_cloud{
	inline void convert_to_grey(const cv::Mat &in_unknown, cv::Mat &grey){
		// Convert Greyscale
		if (in_unknown.channels() != 1) {
			cvtColor(in_unknown, grey, CV_BGR2GRAY);
			assert(grey.channels() == 1);
		} else {
			in_unknown.copyTo(grey);
		}
	}

	inline void create_empty_grey_mat(cv::Mat &image, int rows, int cols){
		image.create(rows, cols, CV_8U);
		image = cv::Mat::zeros(rows, cols, CV_8U);
	}

	/**	Create inverse transformed image
	 * 	Grayscale the image
	 * 	Edge Filter
	 * 	Inverse distance transformation
	 */
	inline void create_inverse_transformed(const cv::Mat& in, cv::Mat &out, image_filter::edge::Edge filter = image_filter::edge::MAX ){
		cv::Mat grey,edge;

		create_empty_grey_mat(edge, in.rows, in.cols);
		create_empty_grey_mat(out, in.rows, in.cols);

		// Convert Greyscale
		convert_to_grey(in, grey);

		// Edge filter
		switch (filter) {
			default:
			case image_filter::edge::OFF:
				grey.copyTo(edge);
				break;
			case image_filter::edge::CANNY:
				cv::Canny( grey, edge, 30, 100, 3, 	false );
			break;
			case image_filter::edge::LAPLACE:
				cv::Laplacian( grey, edge, 3, 1, 0 );
			break;
			case image_filter::edge::MAX:
				filter_2d::edge_max<uchar>( grey, edge);
				break;

		}

		// Inverse distance transform
		filter_2d::inverse_distance_transformation<uchar,uchar>(edge, out);
	}

	inline void create_blured_image(const cv::Mat& in, cv::Mat &out, image_filter::blur::Blur filter = image_filter::blur::BLUR){
		switch(filter){
			default:
			case ::image_filter::blur::OFF:
				in.copyTo(out);
				break;
			case ::image_filter::blur::BILATERAL:
				cv::bilateralFilter( in, out, 2, 2*2, 1);
				break;
			case ::image_filter::blur::BLUR:
				cv::blur( in, out, cv::Size(2,2), cv::Point(-1,-1) );
				break;
			case ::image_filter::blur::GAUSSIAN:
				cv::GaussianBlur( in, out, cv::Size(2,2), 0, 0);
				break;
			case ::image_filter::blur::MEDIAN:
				cv::medianBlur( in, out, 2);
				break;
		}
	}
}
#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrVkVaryingHandler.h"

/** Returns the number of locations take up by a given GrSLType. We assume that all
    scalar values are 32 bits. */
static inline int grsltype_to_location_size(GrSLType type) {
    switch(type) {
        case kVoid_GrSLType:
            return 0;
        case kFloat_GrSLType:
            return 1;
        case kVec2f_GrSLType:
            return 1;
        case kVec3f_GrSLType:
            return 1;
        case kVec4f_GrSLType:
            return 1;
        case kVec2i_GrSLType:
            return 1;
        case kVec3i_GrSLType:
            return 1;
        case kVec4i_GrSLType:
            return 1;
        case kMat22f_GrSLType:
            return 2;
        case kMat33f_GrSLType:
            return 3;
        case kMat44f_GrSLType:
            return 4;
        case kTexture2DSampler_GrSLType:
            return 0;
        case kITexture2DSampler_GrSLType:
             return 0;
        case kTextureExternalSampler_GrSLType:
             return 0;
        case kTexture2DRectSampler_GrSLType:
             return 0;
        case kBufferSampler_GrSLType:
             return 0;
        case kBool_GrSLType:
             return 1;
        case kInt_GrSLType:
             return 1;
        case kUint_GrSLType:
             return 1;
        case kTexture2D_GrSLType:
             return 0;
        case kSampler_GrSLType:
             return 0;
        case kImageStorage2D_GrSLType:
            return 0;
        case kIImageStorage2D_GrSLType:
            return 0;
    }
    SkFAIL("Unexpected type");
    return -1;
}

void finalize_helper(GrVkVaryingHandler::VarArray& vars) {
    int locationIndex = 0;
    for (int i = 0; i < vars.count(); ++i) {
        GrShaderVar& var = vars[i];
        SkString location;
        location.appendf("location = %d", locationIndex);
        var.addLayoutQualifier(location.c_str());

        int elementSize = grsltype_to_location_size(var.getType());
        SkASSERT(elementSize);
        int numElements = 1;
        if (var.isArray()) {
           numElements = var.getArrayCount();
        }
        locationIndex += elementSize * numElements;
    }
    // Vulkan requires at least 64 locations to be supported for both vertex output and fragment
    // input. If we ever hit this assert, then we'll need to add a cap to actually check the
    // supported input and output values and adjust our supported shaders based on those values.
    SkASSERT(locationIndex <= 64);
}

void GrVkVaryingHandler::onFinalize() {
    finalize_helper(fVertexInputs);
    finalize_helper(fVertexOutputs);
    finalize_helper(fGeomInputs);
    finalize_helper(fGeomOutputs);
    finalize_helper(fFragInputs);
    finalize_helper(fFragOutputs);
}
<commit_msg>vk: Fix geometry-shader input varying locations<commit_after>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrVkVaryingHandler.h"

/** Returns the number of locations take up by a given GrSLType. We assume that all
    scalar values are 32 bits. */
static inline int grsltype_to_location_size(GrSLType type) {
    switch(type) {
        case kVoid_GrSLType:
            return 0;
        case kFloat_GrSLType:
            return 1;
        case kVec2f_GrSLType:
            return 1;
        case kVec3f_GrSLType:
            return 1;
        case kVec4f_GrSLType:
            return 1;
        case kVec2i_GrSLType:
            return 1;
        case kVec3i_GrSLType:
            return 1;
        case kVec4i_GrSLType:
            return 1;
        case kMat22f_GrSLType:
            return 2;
        case kMat33f_GrSLType:
            return 3;
        case kMat44f_GrSLType:
            return 4;
        case kTexture2DSampler_GrSLType:
            return 0;
        case kITexture2DSampler_GrSLType:
             return 0;
        case kTextureExternalSampler_GrSLType:
             return 0;
        case kTexture2DRectSampler_GrSLType:
             return 0;
        case kBufferSampler_GrSLType:
             return 0;
        case kBool_GrSLType:
             return 1;
        case kInt_GrSLType:
             return 1;
        case kUint_GrSLType:
             return 1;
        case kTexture2D_GrSLType:
             return 0;
        case kSampler_GrSLType:
             return 0;
        case kImageStorage2D_GrSLType:
            return 0;
        case kIImageStorage2D_GrSLType:
            return 0;
    }
    SkFAIL("Unexpected type");
    return -1;
}

void finalize_helper(GrVkVaryingHandler::VarArray& vars) {
    int locationIndex = 0;
    for (int i = 0; i < vars.count(); ++i) {
        GrShaderVar& var = vars[i];
        SkString location;
        location.appendf("location = %d", locationIndex);
        var.addLayoutQualifier(location.c_str());

        int elementSize = grsltype_to_location_size(var.getType());
        SkASSERT(elementSize > 0);
        int numElements = 1;
        if (var.isArray() && !var.isUnsizedArray()) {
            numElements = var.getArrayCount();
        }
        SkASSERT(numElements > 0);
        locationIndex += elementSize * numElements;
    }
    // Vulkan requires at least 64 locations to be supported for both vertex output and fragment
    // input. If we ever hit this assert, then we'll need to add a cap to actually check the
    // supported input and output values and adjust our supported shaders based on those values.
    SkASSERT(locationIndex <= 64);
}

void GrVkVaryingHandler::onFinalize() {
    finalize_helper(fVertexInputs);
    finalize_helper(fVertexOutputs);
    finalize_helper(fGeomInputs);
    finalize_helper(fGeomOutputs);
    finalize_helper(fFragInputs);
    finalize_helper(fFragOutputs);
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2019 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <functional>
#include <optional>
#include <string_view>

#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>

#include "auth/authenticated_user.hh"
#include "bytes.hh"
#include "seastarx.hh"

namespace auth {

///
/// A stateful SASL challenge which supports many authentication schemes (depending on the implementation).
///
class sasl_challenge {
public:
    virtual ~sasl_challenge() = default;

    virtual bytes evaluate_response(bytes_view client_response) = 0;

    virtual bool is_complete() const = 0;

    virtual future<authenticated_user> get_authenticated_user() const = 0;
};

class plain_text_password_challenge : public sasl_challenge {
public:
    using completion_callback = std::function<future<authenticated_user>(std::string_view, std::string_view)>;

    plain_text_password_challenge(completion_callback f) : _when_complete(std::move(f)) {
    }

    virtual bytes evaluate_response(bytes_view) override;

    virtual bool is_complete() const override;

    virtual future<authenticated_user> get_authenticated_user() const override;

private:
    std::optional<sstring> _username, _password;
    completion_callback _when_complete;
};

}
<commit_msg>auth: Make a ctor `explicit`<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2019 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <functional>
#include <optional>
#include <string_view>

#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>

#include "auth/authenticated_user.hh"
#include "bytes.hh"
#include "seastarx.hh"

namespace auth {

///
/// A stateful SASL challenge which supports many authentication schemes (depending on the implementation).
///
class sasl_challenge {
public:
    virtual ~sasl_challenge() = default;

    virtual bytes evaluate_response(bytes_view client_response) = 0;

    virtual bool is_complete() const = 0;

    virtual future<authenticated_user> get_authenticated_user() const = 0;
};

class plain_text_password_challenge : public sasl_challenge {
public:
    using completion_callback = std::function<future<authenticated_user>(std::string_view, std::string_view)>;

    explicit plain_text_password_challenge(completion_callback f) : _when_complete(std::move(f)) {
    }

    virtual bytes evaluate_response(bytes_view) override;

    virtual bool is_complete() const override;

    virtual future<authenticated_user> get_authenticated_user() const override;

private:
    std::optional<sstring> _username, _password;
    completion_callback _when_complete;
};

}
<|endoftext|>


<commit_before>// Core ros functionality like ros::init and spin
#include <ros/ros.h>
// ROS Trajectory Action server definition
#include <control_msgs/FollowJointTrajectoryAction.h>
// Means by which we communicate with above action-server
#include <actionlib/client/simple_action_client.h>

// Includes the descartes robot model we will be using
#include <descartes_moveit/ikfast_moveit_state_adapter.h>

// Includes the descartes trajectory type we will be using
#include <descartes_trajectory/axial_symmetric_pt.h>
#include <descartes_trajectory/cart_trajectory_pt.h>

// Includes the planner we will be using
#include <descartes_planner/dense_planner.h>

// Includes the utility function for converting to trajectory_msgs::JointTrajectory's
#include <descartes_utilities/ros_conversions.h>

#include <ros/package.h>
#include <fstream>
#include <tf/transform_listener.h>
#include <tf_conversions/tf_eigen.h>

/**
 * Makes a dummy trajectory for the robot to follow.
 */
std::vector<descartes_core::TrajectoryPtPtr> makePath();

/**
 * Sends a ROS trajectory to the robot controller
 */
bool executeTrajectory(const trajectory_msgs::JointTrajectory& trajectory);

int main(int argc, char** argv)
{
  // Initialize ROS
  ros::init(argc, argv, "descartes_tutorial");
  ros::NodeHandle nh;

  // Since we're not calling ros::spin() and doing the planning in a callback, but rather just handling this
  // inline, we need to create an async spinner if our publishers are to work. Note that many MoveIt components
  // will also not work without an active spinner and Descartes uses moveit for its "groups" and "scene" descriptions
  ros::AsyncSpinner spinner (1);
  spinner.start();

  // 1. First thing first, let's create a kinematic model of the robot. In Descartes, this is used to do things
  // like forward kinematics (joints -> pose), inverse kinematics (pose -> many joints), and collision checking.

  // All of the existing planners (as of Nov 2017) have been designed with the idea that you have "closed form"
  // kinematics. This means that the default solvers in MoveIt (KDL) will NOT WORK WELL. I encourage you to produce
  // an ikfast model for your robot (see MoveIt tutorial) or use the OPW kinematics package if you have a spherical
  // wrist industrial robot. See the readme for references.

  // This package assumes that the move group you are using is pointing to an IKFast kinematics plugin in its
  // kinematics.yaml file. By default, it assumes that the underlying kinematics are from 'base_link' to 'tool0'.
  // If you have renamed these, please set the 'ikfast_base_frame' and 'ikfast_tool_frame' parameter (not in the
  // private namespace) to the base and tool frame used to generate the IKFast model.
  descartes_core::RobotModelPtr model (new descartes_moveit::IkFastMoveitStateAdapter());

  // Name of description on parameter server. Typically just "robot_description". Used to initialize
  // moveit model.
  const std::string robot_description = "robot_description";

  // name of the kinematic group you defined when running MoveitSetupAssistant. For many industrial robots this will be
  // "manipulator"
  const std::string group_name = "puzzle";

  // Name of frame in which you are expressing poses. Typically "world_frame" or "base_link".
  const std::string world_frame = "world";

  // tool center point frame (name of link associated with tool). The robot's flange is typically "tool0" but yours
  // could be anything. We typically have our tool's positive Z-axis point outward from the grinder, welder, etc.
  const std::string tcp_frame = "part";

  // Before you can use a model, you must call initialize. This will load robot models and sanity check the model.
  if (!model->initialize(robot_description, group_name, world_frame, tcp_frame))
  {
    ROS_INFO("Could not initialize robot model");
    return -1;
  }

  model->setCheckCollisions(true); // Let's turn on collision checking.

  // 2. The next thing to do is to generate a path for the robot to follow. The description of this path is one of the
  // cool things about Descartes. The source of this path is where this library ties into your application: it could
  // come from CAD or from surfaces that were "scanned".

  // Make the path by calling a helper function. See makePath()'s definition for more discussion about paths.
  std::vector<descartes_core::TrajectoryPtPtr> points = makePath();

  // 3. Now we create a planner that can fuse your kinematic world with the points you want to move the robot
  // along. There are a couple of planners now. DensePlanner is the naive, brute force approach to solving the
  // trajectory. SparsePlanner may be faster for some problems (especially very dense ones), but has recieved
  // less overall testing and evaluation.
  descartes_planner::DensePlanner planner;

  // Like the model, you also need to call initialize on the planner
  if (!planner.initialize(model))
  {
    ROS_ERROR("Failed to initialize planner");
    return -2;
  }

  // 4. Now, for the planning itself. This typically happens in two steps. First, call planPath(). This function takes
  // your input trajectory and expands it into a large kinematic "graph". Failures at this point indicate that the
  // input path may not have solutions at a given point (because of reach/collision) or has two points with no way
  // to connect them.
  auto start_tm = ros::WallTime::now();
  if (!planner.planPath(points))
  {
    ROS_ERROR("Could not solve for a valid path");
    return -3;
  }

  // After expanding the graph, we now call 'getPath()' which searches the graph for a minimum cost path and returns
  // the result. Failures here (assuming planPath was good) indicate that your path has solutions at every waypoint
  // but constraints prevent a solution through the whole path. Usually this means a singularity is hanging out in the
  // middle of your path: the robot can solve all the points but not in the same arm configuration.
  auto search_start_tm = ros::WallTime::now();
  std::vector<descartes_core::TrajectoryPtPtr> result;
  if (!planner.getPath(result))
  {
    ROS_ERROR("Could not retrieve path");
    return -4;
  }

  auto end_tm = ros::WallTime::now();

  ROS_INFO_STREAM("Graph building (s): " << (search_start_tm - start_tm).toSec());
  ROS_INFO_STREAM("Graph search (s): " << (end_tm - search_start_tm).toSec());
  ROS_INFO_STREAM("Total time (s): " << (end_tm - start_tm).toSec());

  // 5. Translate the result into something that you can execute. In ROS land, this means that we turn the result into
  // a trajectory_msgs::JointTrajectory that's executed through a control_msgs::FollowJointTrajectoryAction. If you
  // have your own execution interface, you can get joint values out of the results in the same way.

  // get joint names - this could be from the robot model, or from the parameter server.
  std::vector<std::string> names;
  nh.getParam("controller_joint_names", names);

  // Create a JointTrajectory
  trajectory_msgs::JointTrajectory joint_solution;
  joint_solution.joint_names = names;

  // Define a default velocity. Descartes points without specified timing will use this value to limit the
  // fastest moving joint. This usually effects the first point in your path the most.
  const static double default_joint_vel = 0.5; // rad/s
  if (!descartes_utilities::toRosJointPoints(*model, result, default_joint_vel, joint_solution.points))
  {
    ROS_ERROR("Unable to convert Descartes trajectory to joint points");
    return -5;
  }

  // 6. Send the ROS trajectory to the robot for execution
  if (!executeTrajectory(joint_solution))
  {
    ROS_ERROR("Could not execute trajectory!");
    return -6;
  }

  // Wait till user kills the process (Control-C)
  ROS_INFO("Done!");
  return 0;
}

descartes_core::TrajectoryPtPtr makeCartesianPoint(const Eigen::Affine3d& pose, double dt)
{
  using namespace descartes_core;
  using namespace descartes_trajectory;

  return TrajectoryPtPtr( new CartTrajectoryPt( TolerancedFrame(pose), TimingConstraint(dt)) );
}

descartes_core::TrajectoryPtPtr makeTolerancedCartesianPoint(const Eigen::Affine3d& pose, double dt)
{
  using namespace descartes_core;
  using namespace descartes_trajectory;
  return TrajectoryPtPtr( new AxialSymmetricPt(pose, 0.1, AxialSymmetricPt::Z_AXIS, TimingConstraint(dt)) );
}

EigenSTL::vector_Affine3d makePuzzleToolPoses()
{
  EigenSTL::vector_Affine3d path;
  std::ifstream indata;

  std::string filename = ros::package::getPath("tutorial2_support") + "/config/puzzle_bent.csv";

  indata.open(filename);

  std::string line;
  int lnum = 0;
  while (std::getline(indata, line))
  {
      ++lnum;
      if (lnum < 3)
        continue;

      std::stringstream lineStream(line);
      std::string  cell;
      Eigen::VectorXd xyzijk(6);
      int i = -2;
      while (std::getline(lineStream, cell, ','))
      {
        ++i;
        if (i == -1)
          continue;

        xyzijk(i) = std::stod(cell);
      }

      Eigen::Vector3d pos = xyzijk.head<3>();
      pos = pos / 1000.0;
      Eigen::Vector3d norm = xyzijk.tail<3>();
      norm.normalize();

      Eigen::Vector3d temp_x = (-1 * pos).normalized();
      Eigen::Vector3d y_axis = (norm.cross(temp_x)).normalized();
      Eigen::Vector3d x_axis = (y_axis.cross(norm)).normalized();
      Eigen::Affine3d pose;
      pose.matrix().col(0).head<3>() = x_axis;
      pose.matrix().col(1).head<3>() = y_axis;
      pose.matrix().col(2).head<3>() = norm;
      pose.matrix().col(3).head<3>() = pos;

      path.push_back(pose);
  }
  indata.close();

  return path;
}

std::vector<descartes_core::TrajectoryPtPtr>
makeDescartesTrajectory(const EigenSTL::vector_Affine3d& path)
{
  using namespace descartes_core;
  using namespace descartes_trajectory;

  std::vector<descartes_core::TrajectoryPtPtr> descartes_path; // return value

  // need to get the transform between grinder_frame and base_link;
  tf::StampedTransform grinder_frame;
  tf::TransformListener listener;
  ros::Duration(1.0).sleep();
  Eigen::Affine3d gf;
  listener.lookupTransform("world", "grinder_frame", ros::Time(0), grinder_frame);
  tf::transformTFToEigen(grinder_frame, gf);

  Frame wobj_base(gf);
  Frame tool_base = Frame::Identity();
  TolerancedFrame wobj_pt = Frame::Identity();

  for (auto& point : path)
  {
    auto p = point;
    TolerancedFrame tool_pt(p);
    tool_pt.orientation_tolerance.z_lower -= M_PI;
    tool_pt.orientation_tolerance.z_upper += M_PI;

    boost::shared_ptr<CartTrajectoryPt> pt(new CartTrajectoryPt(wobj_base, wobj_pt, tool_base, tool_pt, 0, M_PI/180.0, descartes_core::TimingConstraint(0.25)));
    descartes_path.push_back(pt);
  }
  return descartes_path;
}

std::vector<descartes_core::TrajectoryPtPtr> makePath()
{
  EigenSTL::vector_Affine3d tool_poses = makePuzzleToolPoses();
//  visualizePuzzlePath(tool_poses);
  return makeDescartesTrajectory(tool_poses);
}

bool executeTrajectory(const trajectory_msgs::JointTrajectory& trajectory)
{
  // Create a Follow Joint Trajectory Action Client
  actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction> ac ("joint_trajectory_action", true);
  if (!ac.waitForServer(ros::Duration(2.0)))
  {
    ROS_ERROR("Could not connect to action server");
    return false;
  }

  control_msgs::FollowJointTrajectoryGoal goal;
  goal.trajectory = trajectory;
  goal.goal_time_tolerance = ros::Duration(1.0);

  return ac.sendGoalAndWait(goal) == actionlib::SimpleClientGoalState::SUCCEEDED;
}
<commit_msg>Added more documentation<commit_after>// Core ros functionality like ros::init and spin
#include <ros/ros.h>
// ROS Trajectory Action server definition
#include <control_msgs/FollowJointTrajectoryAction.h>
// Means by which we communicate with above action-server
#include <actionlib/client/simple_action_client.h>

// Includes the descartes robot model we will be using
#include <descartes_moveit/ikfast_moveit_state_adapter.h>

// Includes the descartes trajectory type we will be using
#include <descartes_trajectory/axial_symmetric_pt.h>
#include <descartes_trajectory/cart_trajectory_pt.h>

// Includes the planner we will be using
#include <descartes_planner/dense_planner.h>

// Includes the utility function for converting to trajectory_msgs::JointTrajectory's
#include <descartes_utilities/ros_conversions.h>

// For reading the position of the grinder from TF
#include <tf/transform_listener.h>
#include <tf_conversions/tf_eigen.h>

// For loading the pose file from a local package
#include <ros/package.h>
#include <fstream>
/**
 * Makes a dummy trajectory for the robot to follow.
 */
std::vector<descartes_core::TrajectoryPtPtr> makePath();

/**
 * Sends a ROS trajectory to the robot controller
 */
bool executeTrajectory(const trajectory_msgs::JointTrajectory& trajectory);

int main(int argc, char** argv)
{
  // Initialize ROS
  ros::init(argc, argv, "descartes_tutorial");
  ros::NodeHandle nh;

  // I won't be repeating too many comments, so please take a look back at the first tutorial for an explanation of
  // the basics.
  ros::AsyncSpinner spinner (1);
  spinner.start();

  // This package assumes that the move group you are using is pointing to an IKFast kinematics plugin in its
  // kinematics.yaml file. By default, it assumes that the underlying kinematics are from 'base_link' to 'tool0'.
  // We're using a group that does not begin or end at these links, but they do exist in the model.
  // If you have renamed these, please set the 'ikfast_base_frame' and 'ikfast_tool_frame' parameter (not in the
  // private namespace) to the base and tool frame used to generate the IKFast model.
  descartes_core::RobotModelPtr model (new descartes_moveit::IkFastMoveitStateAdapter());

  const std::string robot_description = "robot_description";

  // We have made a special move group which goes from the base link of the robot to the reference frame of the mounted
  // part that the robot is holding.
  const std::string group_name = "puzzle";

  // Name of frame in which you are expressing poses.
  const std::string world_frame = "world";

  // In this demo, "part" is a reference frame located on the part that the robot is holding. It's a frame that we can
  // precisely locate w.r.t the robot, and in which we can export the poses representing the edge of the part.
  const std::string tcp_frame = "part";

  if (!model->initialize(robot_description, group_name, world_frame, tcp_frame))
  {
    ROS_INFO("Could not initialize robot model");
    return -1;
  }

  model->setCheckCollisions(true); // Let's turn on collision checking.

  // Here we load a path by reading a file of poses generated on the perimeter of the part being held by the robot.
  // These were generated from the CAD model. This is the interesting bit of this tutorial.
  std::vector<descartes_core::TrajectoryPtPtr> points = makePath();

  descartes_planner::DensePlanner planner;

  if (!planner.initialize(model))
  {
    ROS_ERROR("Failed to initialize planner");
    return -2;
  }

  auto start_tm = ros::WallTime::now();
  if (!planner.planPath(points))
  {
    ROS_ERROR("Could not solve for a valid path");
    return -3;
  }

  auto search_start_tm = ros::WallTime::now();
  std::vector<descartes_core::TrajectoryPtPtr> result;
  if (!planner.getPath(result))
  {
    ROS_ERROR("Could not retrieve path");
    return -4;
  }

  auto end_tm = ros::WallTime::now();

  ROS_INFO_STREAM("Graph building (s): " << (search_start_tm - start_tm).toSec());
  ROS_INFO_STREAM("Graph search (s): " << (end_tm - search_start_tm).toSec());
  ROS_INFO_STREAM("Total time (s): " << (end_tm - start_tm).toSec());

  // Translate the result into something that you can execute.
  std::vector<std::string> names;
  nh.getParam("controller_joint_names", names);

  // Create a JointTrajectory
  trajectory_msgs::JointTrajectory joint_solution;
  joint_solution.joint_names = names;

  // Define a default velocity. Descartes points without specified timing will use this value to limit the
  // fastest moving joint. This usually effects the first point in your path the most.
  const static double default_joint_vel = 0.5; // rad/s
  if (!descartes_utilities::toRosJointPoints(*model, result, default_joint_vel, joint_solution.points))
  {
    ROS_ERROR("Unable to convert Descartes trajectory to joint points");
    return -5;
  }

  // 6. Send the ROS trajectory to the robot for execution
  if (!executeTrajectory(joint_solution))
  {
    ROS_ERROR("Could not execute trajectory!");
    return -6;
  }

  // Wait till user kills the process (Control-C)
  ROS_INFO("Done!");
  return 0;
}

/**
 * @brief Loads a specific file containing the perimeter of the puzzle part generated from CAD. The frames
 * are exported in the "puzzle" frame, so we can coordinate the motion of the robot with this part.
 */
static EigenSTL::vector_Affine3d makePuzzleToolPoses()
{
  EigenSTL::vector_Affine3d path; // results
  std::ifstream indata; // input file

  // You could load your parts from anywhere, but we are transporting them with the git repo
  std::string filename = ros::package::getPath("tutorial2_support") + "/config/puzzle_bent.csv";

  // In a non-trivial app, you'll of course want to check that calls like 'open' succeeded
  indata.open(filename);

  std::string line;
  int lnum = 0;
  while (std::getline(indata, line))
  {
      ++lnum;
      if (lnum < 3)
        continue;

      std::stringstream lineStream(line);
      std::string  cell;
      Eigen::Matrix<double, 6, 1> xyzijk;
      int i = -2;
      while (std::getline(lineStream, cell, ','))
      {
        ++i;
        if (i == -1)
          continue;

        xyzijk(i) = std::stod(cell);
      }

      Eigen::Vector3d pos = xyzijk.head<3>();
      pos = pos / 1000.0; // Most things in ROS use meters as the unit of length. Our part was exported in mm.
      Eigen::Vector3d norm = xyzijk.tail<3>();
      norm.normalize();

      // This code computes two extra directions to turn the normal direction into a full defined frame. Descartes
      // will search around this frame for extra poses, so the exact values do not matter as long they are valid.
      Eigen::Vector3d temp_x = (-1 * pos).normalized();
      Eigen::Vector3d y_axis = (norm.cross(temp_x)).normalized();
      Eigen::Vector3d x_axis = (y_axis.cross(norm)).normalized();
      Eigen::Affine3d pose;
      pose.matrix().col(0).head<3>() = x_axis;
      pose.matrix().col(1).head<3>() = y_axis;
      pose.matrix().col(2).head<3>() = norm;
      pose.matrix().col(3).head<3>() = pos;

      path.push_back(pose);
  }
  indata.close();

  return path;
}

std::vector<descartes_core::TrajectoryPtPtr>
makeDescartesTrajectory(const EigenSTL::vector_Affine3d& path)
{
  using namespace descartes_core;
  using namespace descartes_trajectory;

  std::vector<descartes_core::TrajectoryPtPtr> descartes_path; // return value

  // This is where the magic happens. We have a tool path, but its in a coordinate frame that is local
  // to the part. We'll use a special constructor of CartTrajectoryPt to tell Descartes about this soon,
  // but first we need to figure out where the grinder is in our "world". You might have this hard coded,
  // but here we're going to lookup its position. Note that we are looking up the frame of the static tool
  // in the base frame of the Descartes model given in the initialize() function in main().
  tf::TransformListener listener;
  tf::StampedTransform grinder_frame;
  listener.waitForTransform("world", "grinder_frame", ros::Time(0), ros::Duration(5.0));
  listener.lookupTransform("world", "grinder_frame", ros::Time(0), grinder_frame);

  // Descartes uses eigen, so let's convert the data type
  Eigen::Affine3d gf;
  tf::transformTFToEigen(grinder_frame, gf);

  // When you tell Descartes about a "cartesian" frame, you can specify 4 "supporting" frames, and all are
  // identity unless otherwise stated:
  // 1. 'wobj_base': A fixed frame from the base of the robot to the base of a part.
  // 2. 'wobj_pt': The point at which the 'tool_pt' should be put, specified in the frame of 'wobj_base'.
  //               This point can have tolerances associated with it.
  // 3. 'tool_base': A fixed frame from the tool of the robot (e.g. tool0) to a reference point on the tool.
  // 4. 'tool_pt': The point which is put on 'wobj_pt' specified in the frame of 'tool_base'. This point can
  //               have tolerances associated with it.
  //
  // NOTE: I'm pretty sure the math is broken if you specify tolerances for BOTH 'wobj_pt' and 'tool_pt' at the
  // same time. I recommend just using one toleranced frame.

  Frame wobj_base(gf); // Here we say our wobj_base is the grinder pose
  Frame tool_base = Frame::Identity(); // That our tool base is identity. This is because the URDF frame "puzzle" already
                                       // puts us in the right frame. If we didn't have this, or it changed a lot, we
                                       // could use this value to set the base frame for our CAD points
  TolerancedFrame wobj_pt = Frame::Identity(); // Here we keep the base frame identical to the grinder pose.

  // Now we translate our poses to Descartes points
  for (const auto& point : path)
  {
    // Each 'point' represents a point on the edge of the puzzle part. The tool poses are exported in such a way that
    // the Z of each point is parallel with the grinder, so turning around Z is okay.
    TolerancedFrame tool_pt(point);
    tool_pt.orientation_tolerance.z_lower = -M_PI; // Search -PI to PI (so 360 degrees)
    tool_pt.orientation_tolerance.z_upper = M_PI;

    boost::shared_ptr<CartTrajectoryPt> pt(
          new CartTrajectoryPt(wobj_base, wobj_pt, tool_base, tool_pt, // Here we specify our frames
                               0, // Don't search in cartesian space. We want the points to be exact.
                               M_PI/90.0, // Do search our rotation in 2 degree increments.
                               descartes_core::TimingConstraint(0.25))); // Make every point 0.25 seconds apart
    descartes_path.push_back(pt);
  }
  return descartes_path;
}

std::vector<descartes_core::TrajectoryPtPtr> makePath()
{
  EigenSTL::vector_Affine3d tool_poses = makePuzzleToolPoses();
  visualizePoses(tool_poses);
  return makeDescartesTrajectory(tool_poses);
}

bool executeTrajectory(const trajectory_msgs::JointTrajectory& trajectory)
{
  // Create a Follow Joint Trajectory Action Client
  actionlib::SimpleActionClient<control_msgs::FollowJointTrajectoryAction> ac ("joint_trajectory_action", true);
  if (!ac.waitForServer(ros::Duration(2.0)))
  {
    ROS_ERROR("Could not connect to action server");
    return false;
  }

  control_msgs::FollowJointTrajectoryGoal goal;
  goal.trajectory = trajectory;
  goal.goal_time_tolerance = ros::Duration(1.0);

  return ac.sendGoalAndWait(goal) == actionlib::SimpleClientGoalState::SUCCEEDED;
}
<|endoftext|>


<commit_before>// This file is part of Playslave-C++.
// Playslave-C++ is licenced under the MIT license: see LICENSE.txt.

/**
 * @file
 * Implementation of the AudioOutput class.
 * @see audio/audio_output.hpp
 */

extern "C" {
#ifdef WIN32
#define inline __inline
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef WIN32
#undef inline
#endif
}

#include <cassert>
#include <climits>
#include <algorithm>
#include <string>

#include "portaudiocpp/PortAudioCpp.hxx"

#include "../errors.hpp"
#include "../sample_formats.hpp"
#include "../messages.h"

#include "audio_output.hpp"
#include "audio_decoder.hpp"

#include "../ringbuffer/ringbuffer.hpp"

const size_t AudioOutput::RINGBUF_POWER = 16;

AudioOutput::AudioOutput(const std::string &path, const StreamConfigurator &c)
{
	this->av = decltype(this->av)(new AudioDecoder(path));
	this->out_strm = decltype(this->out_strm)(
	                c.Configure(*this, *(this->av)));
	this->ring_buf = decltype(this->ring_buf)(
	                new RingBuf(RINGBUF_POWER, ByteCountForSampleCount(1L)));

	this->position_sample_count = 0;

	ClearFrame();
}

AudioOutput::~AudioOutput()
{
	this->out_strm = nullptr;
	Debug("closed output stream");
}

void AudioOutput::Start()
{
	this->out_strm->start();
	Debug("audio started");
}

void AudioOutput::Stop()
{
	this->out_strm->abort();
	Debug("audio stopped");

	// TODO: Possibly recover from dropping frames due to abort.
}

bool AudioOutput::IsStopped() { return !this->out_strm->isActive(); }

std::chrono::microseconds AudioOutput::CurrentPositionMicroseconds()
{
	return this->av->PositionMicrosecondsForSampleCount(
	                this->position_sample_count);
}

std::uint64_t AudioOutput::ByteCountForSampleCount(std::uint64_t samples) const
{
	return this->av->ByteCountForSampleCount(samples);
}

std::uint64_t AudioOutput::SampleCountForByteCount(std::uint64_t bytes) const
{
	return this->av->SampleCountForByteCount(bytes);
}

void AudioOutput::SeekToPositionMicroseconds(
                std::chrono::microseconds microseconds)
{
	this->av->SeekToPositionMicroseconds(microseconds);
	this->position_sample_count =
	                this->av->SampleCountForPositionMicroseconds(
	                                microseconds);

	ClearFrame();
	this->ring_buf->Flush();
}

void AudioOutput::ClearFrame()
{
	this->frame.clear();
	this->frame_iterator = this->frame.end();
	this->file_ended = false;
}

bool AudioOutput::Update()
{
	bool more_frames_available = DecodeIfFrameEmpty();

	if (!FrameFinished()) {
		WriteAllAvailableToRingBuffer();
	}

	this->file_ended = !more_frames_available;
	return more_frames_available;
}

bool AudioOutput::DecodeIfFrameEmpty()
{
	// Either the current frame is in progress, or has been emptied.
	// AdvanceFrameIterator() establishes this assertion by emptying a
	// frame as soon as it finishes.
	assert(this->frame.empty() || !FrameFinished());

	bool more_frames_available = true;

	if (FrameFinished()) {
		AudioDecoder::DecodeResult result = this->av->Decode();

		this->frame = result.second;
		this->frame_iterator = this->frame.begin();

		more_frames_available = result.first !=
		                        AudioDecoder::DecodeState::END_OF_FILE;
	}

	return more_frames_available;
}

bool AudioOutput::FileEnded() { return this->file_ended; }

void AudioOutput::WriteAllAvailableToRingBuffer()
{
	std::uint64_t count = RingBufferTransferCount();
	if (0 < count) {
		WriteToRingBuffer(count);
	}
}

void AudioOutput::WriteToRingBuffer(std::uint64_t sample_count)
{
	// This should have been established by WriteAllAvailableToRingBuffer.
	assert(0 < sample_count);

	std::uint64_t written_count = this->ring_buf->Write(
	                &(*this->frame_iterator), sample_count);
	if (written_count != sample_count) {
		throw InternalError(MSG_OUTPUT_RINGWRITE);
	}
	assert(0 < written_count);

	AdvanceFrameIterator(written_count);
}

bool AudioOutput::FrameFinished()
{
	return this->frame.end() <= this->frame_iterator;
}

void AudioOutput::AdvanceFrameIterator(std::uint64_t sample_count)
{
	auto byte_count = ByteCountForSampleCount(sample_count);
	assert(sample_count <= byte_count);
	assert(0 < byte_count);

	std::advance(this->frame_iterator, byte_count);

	// We empty the frame once we're done with it.  This
	// maintains FrameFinished(), as an empty frame is a finished one.
	if (FrameFinished()) {
		ClearFrame();
		assert(FrameFinished());
	}

	// The frame iterator should be somewhere between the beginning and
	// end of the frame, unless the frame was emptied.
	assert(this->frame.empty() ||
	       (this->frame.begin() < this->frame_iterator &&
	        this->frame_iterator < this->frame.end()));
}

std::uint64_t AudioOutput::RingBufferWriteCapacity()
{
	return this->ring_buf->WriteCapacity();
}

std::uint64_t AudioOutput::RingBufferReadCapacity()
{
	return this->ring_buf->ReadCapacity();
}

std::uint64_t AudioOutput::RingBufferTransferCount()
{
	assert(!this->frame.empty());

	long bytes = std::distance(this->frame_iterator, this->frame.end());
	assert(0 <= bytes);

	std::uint64_t samples = SampleCountForByteCount(
	                static_cast<std::uint64_t>(bytes));
	return std::min(samples, RingBufferWriteCapacity());
}

int AudioOutput::paCallbackFun(const void *, void *out,
                               unsigned long frames_per_buf,
                               const PaStreamCallbackTimeInfo *,
                               PaStreamCallbackFlags)
{
	char *cout = static_cast<char *>(out);

	std::pair<PaStreamCallbackResult, unsigned long> result =
	                std::make_pair(paContinue, 0);

	while (result.first == paContinue && result.second < frames_per_buf) {
		result = PlayCallbackStep(cout, frames_per_buf, result);
	}
	return static_cast<int>(result.first);
}

PlayCallbackStepResult AudioOutput::PlayCallbackStep(
                char *out, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	unsigned long avail = this->ring_buf->ReadCapacity();

	auto fn = (avail == 0) ? &AudioOutput::PlayCallbackFailure
	                       : &AudioOutput::PlayCallbackSuccess;
	return (this->*fn)(out, avail, frames_per_buf, in);
}

PlayCallbackStepResult AudioOutput::PlayCallbackSuccess(
                char *out, unsigned long avail, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	auto samples_pa_wants = frames_per_buf - in.second;
	auto samples_read = ReadSamplesToOutput(out, avail, samples_pa_wants);

	return std::make_pair(paContinue, in.second + samples_read);
}

PlayCallbackStepResult AudioOutput::PlayCallbackFailure(
                char *out, unsigned long, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	decltype(in) result;

	if (FileEnded()) {
		result = std::make_pair(paComplete, in.second);
	} else {
		// Make up some silence to plug the gap.
		memset(out, 0, ByteCountForSampleCount(frames_per_buf));
		result = std::make_pair(paContinue, frames_per_buf);
	}

	return result;
}

unsigned long AudioOutput::ReadSamplesToOutput(char *&output,
                                               unsigned long output_capacity,
                                               unsigned long buffered_count)
{
	long transfer_sample_count = static_cast<long>(
	                std::min({output_capacity, buffered_count,
	                          static_cast<unsigned long>(LONG_MAX)}));

	output += this->ring_buf->Read(output, transfer_sample_count);

	this->position_sample_count += transfer_sample_count;
	return transfer_sample_count;
}
<commit_msg>Remove ffmpeg imports in AudioOutput.<commit_after>// This file is part of Playslave-C++.
// Playslave-C++ is licenced under the MIT license: see LICENSE.txt.

/**
 * @file
 * Implementation of the AudioOutput class.
 * @see audio/audio_output.hpp
 */

#include <cassert>
#include <climits>
#include <algorithm>
#include <string>

#include "portaudiocpp/PortAudioCpp.hxx"

#include "../errors.hpp"
#include "../sample_formats.hpp"
#include "../messages.h"

#include "audio_output.hpp"
#include "audio_decoder.hpp"

#include "../ringbuffer/ringbuffer.hpp"

const size_t AudioOutput::RINGBUF_POWER = 16;

AudioOutput::AudioOutput(const std::string &path, const StreamConfigurator &c)
{
	this->av = decltype(this->av)(new AudioDecoder(path));
	this->out_strm = decltype(this->out_strm)(
	                c.Configure(*this, *(this->av)));
	this->ring_buf = decltype(this->ring_buf)(
	                new RingBuf(RINGBUF_POWER, ByteCountForSampleCount(1L)));

	this->position_sample_count = 0;

	ClearFrame();
}

AudioOutput::~AudioOutput()
{
	this->out_strm = nullptr;
	Debug("closed output stream");
}

void AudioOutput::Start()
{
	this->out_strm->start();
	Debug("audio started");
}

void AudioOutput::Stop()
{
	this->out_strm->abort();
	Debug("audio stopped");

	// TODO: Possibly recover from dropping frames due to abort.
}

bool AudioOutput::IsStopped() { return !this->out_strm->isActive(); }

std::chrono::microseconds AudioOutput::CurrentPositionMicroseconds()
{
	return this->av->PositionMicrosecondsForSampleCount(
	                this->position_sample_count);
}

std::uint64_t AudioOutput::ByteCountForSampleCount(std::uint64_t samples) const
{
	return this->av->ByteCountForSampleCount(samples);
}

std::uint64_t AudioOutput::SampleCountForByteCount(std::uint64_t bytes) const
{
	return this->av->SampleCountForByteCount(bytes);
}

void AudioOutput::SeekToPositionMicroseconds(
                std::chrono::microseconds microseconds)
{
	this->av->SeekToPositionMicroseconds(microseconds);
	this->position_sample_count =
	                this->av->SampleCountForPositionMicroseconds(
	                                microseconds);

	ClearFrame();
	this->ring_buf->Flush();
}

void AudioOutput::ClearFrame()
{
	this->frame.clear();
	this->frame_iterator = this->frame.end();
	this->file_ended = false;
}

bool AudioOutput::Update()
{
	bool more_frames_available = DecodeIfFrameEmpty();

	if (!FrameFinished()) {
		WriteAllAvailableToRingBuffer();
	}

	this->file_ended = !more_frames_available;
	return more_frames_available;
}

bool AudioOutput::DecodeIfFrameEmpty()
{
	// Either the current frame is in progress, or has been emptied.
	// AdvanceFrameIterator() establishes this assertion by emptying a
	// frame as soon as it finishes.
	assert(this->frame.empty() || !FrameFinished());

	bool more_frames_available = true;

	if (FrameFinished()) {
		AudioDecoder::DecodeResult result = this->av->Decode();

		this->frame = result.second;
		this->frame_iterator = this->frame.begin();

		more_frames_available = result.first !=
		                        AudioDecoder::DecodeState::END_OF_FILE;
	}

	return more_frames_available;
}

bool AudioOutput::FileEnded() { return this->file_ended; }

void AudioOutput::WriteAllAvailableToRingBuffer()
{
	std::uint64_t count = RingBufferTransferCount();
	if (0 < count) {
		WriteToRingBuffer(count);
	}
}

void AudioOutput::WriteToRingBuffer(std::uint64_t sample_count)
{
	// This should have been established by WriteAllAvailableToRingBuffer.
	assert(0 < sample_count);

	std::uint64_t written_count = this->ring_buf->Write(
	                &(*this->frame_iterator), sample_count);
	if (written_count != sample_count) {
		throw InternalError(MSG_OUTPUT_RINGWRITE);
	}
	assert(0 < written_count);

	AdvanceFrameIterator(written_count);
}

bool AudioOutput::FrameFinished()
{
	return this->frame.end() <= this->frame_iterator;
}

void AudioOutput::AdvanceFrameIterator(std::uint64_t sample_count)
{
	auto byte_count = ByteCountForSampleCount(sample_count);
	assert(sample_count <= byte_count);
	assert(0 < byte_count);

	std::advance(this->frame_iterator, byte_count);

	// We empty the frame once we're done with it.  This
	// maintains FrameFinished(), as an empty frame is a finished one.
	if (FrameFinished()) {
		ClearFrame();
		assert(FrameFinished());
	}

	// The frame iterator should be somewhere between the beginning and
	// end of the frame, unless the frame was emptied.
	assert(this->frame.empty() ||
	       (this->frame.begin() < this->frame_iterator &&
	        this->frame_iterator < this->frame.end()));
}

std::uint64_t AudioOutput::RingBufferWriteCapacity()
{
	return this->ring_buf->WriteCapacity();
}

std::uint64_t AudioOutput::RingBufferReadCapacity()
{
	return this->ring_buf->ReadCapacity();
}

std::uint64_t AudioOutput::RingBufferTransferCount()
{
	assert(!this->frame.empty());

	long bytes = std::distance(this->frame_iterator, this->frame.end());
	assert(0 <= bytes);

	std::uint64_t samples = SampleCountForByteCount(
	                static_cast<std::uint64_t>(bytes));
	return std::min(samples, RingBufferWriteCapacity());
}

int AudioOutput::paCallbackFun(const void *, void *out,
                               unsigned long frames_per_buf,
                               const PaStreamCallbackTimeInfo *,
                               PaStreamCallbackFlags)
{
	char *cout = static_cast<char *>(out);

	std::pair<PaStreamCallbackResult, unsigned long> result =
	                std::make_pair(paContinue, 0);

	while (result.first == paContinue && result.second < frames_per_buf) {
		result = PlayCallbackStep(cout, frames_per_buf, result);
	}
	return static_cast<int>(result.first);
}

PlayCallbackStepResult AudioOutput::PlayCallbackStep(
                char *out, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	unsigned long avail = this->ring_buf->ReadCapacity();

	auto fn = (avail == 0) ? &AudioOutput::PlayCallbackFailure
	                       : &AudioOutput::PlayCallbackSuccess;
	return (this->*fn)(out, avail, frames_per_buf, in);
}

PlayCallbackStepResult AudioOutput::PlayCallbackSuccess(
                char *out, unsigned long avail, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	auto samples_pa_wants = frames_per_buf - in.second;
	auto samples_read = ReadSamplesToOutput(out, avail, samples_pa_wants);

	return std::make_pair(paContinue, in.second + samples_read);
}

PlayCallbackStepResult AudioOutput::PlayCallbackFailure(
                char *out, unsigned long, unsigned long frames_per_buf,
                PlayCallbackStepResult in)
{
	decltype(in) result;

	if (FileEnded()) {
		result = std::make_pair(paComplete, in.second);
	} else {
		// Make up some silence to plug the gap.
		memset(out, 0, ByteCountForSampleCount(frames_per_buf));
		result = std::make_pair(paContinue, frames_per_buf);
	}

	return result;
}

unsigned long AudioOutput::ReadSamplesToOutput(char *&output,
                                               unsigned long output_capacity,
                                               unsigned long buffered_count)
{
	long transfer_sample_count = static_cast<long>(
	                std::min({output_capacity, buffered_count,
	                          static_cast<unsigned long>(LONG_MAX)}));

	output += this->ring_buf->Read(output, transfer_sample_count);

	this->position_sample_count += transfer_sample_count;
	return transfer_sample_count;
}
<|endoftext|>


<commit_before>//----------------------------  mapping_c1.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  mapping_c1.cc  ---------------------------

#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <grid/tria_boundary.h>
#include <fe/mapping_c1.h>
#include <cmath>

template <int dim>
MappingC1<dim>::MappingC1 ()
		:
		MappingQ<dim> (3)
{
  Assert (dim > 1, ExcImpossibleInDim(dim));
};

#if deal_II_dimension == 1

template <>
void
MappingC1<1>::add_line_support_points (const Triangulation<1>::cell_iterator &,
				       std::vector<Point<1> > &) const
{
  const unsigned int dim = 1;
  Assert (dim > 1, ExcImpossibleInDim(dim));
};

#endif

#if deal_II_dimension == 2

template <>
void
MappingC1<2>::add_line_support_points (const Triangulation<2>::cell_iterator &cell,
				       std::vector<Point<2> > &a) const
{
  const unsigned int dim = 2;
  std::vector<Point<dim> > line_points (2);

				       // loop over each of the lines,
				       // and if it is at the
				       // boundary, then first get the
				       // boundary description and
				       // second compute the points on
				       // it. if not at the boundary,
				       // get the respective points
				       // from another function
  for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no)
    {
      const Triangulation<dim>::line_iterator line = cell->line(line_no);

      if (line->at_boundary())
	{
					   // first get the tangential
					   // vectors at the two
					   // vertices of this line
					   // from the boundary
					   // description
	  const Boundary<dim> &boundary
	    = line->get_triangulation().get_boundary(line->boundary_indicator());

	  Boundary<dim>::FaceVertexTangents face_vertex_tangents;
	  boundary.get_tangents_at_vertices (line, face_vertex_tangents);

					   // then transform them into
					   // interpolation points for
					   // a cubic polynomial
					   //
					   // for this, note that if
					   // we describe the boundary
					   // curve as a polynomial in
					   // tangential coordinate
					   // @p{t=0..1} (along the
					   // line) and @p{s} in
					   // normal direction, then
					   // the cubic mapping is
					   // such that @p{s = a*t**3
					   // + b*t**2 + c*t + d}, and
					   // we want to determine the
					   // interpolation points at
					   // @p{t=1/3} and
					   // @p{t=2/3}. Since at
					   // @p{t=0,1} we want a
					   // vertex which is actually
					   // at the boundary, we know
					   // that @p{d=0} and
					   // @p{a=-b-c}. As
					   // side-conditions, we want
					   // that the derivatives at
					   // @p{t=0} and @p{t=1},
					   // i.e. at the vertices
					   // match those returned by
					   // the boundary. We then
					   // have that
					   // @p{s(1/3)=1/27(2b+8c)}
					   // and
					   // @p{s(2/3)=4/27b+10/27c}.
					   //
					   // The task is then first
					   // to determine the
					   // coefficients from the
					   // tangentials. for that,
					   // first rotate the
					   // tangentials of @p{s(t)}
					   // into the global
					   // coordinate system. they
					   // are @p{A (1,c)} and @p{A
					   // (1,b)} with @p{A} the
					   // rotation matrix, since
					   // the tangentials in the
					   // coordinate system
					   // relative to the line are
					   // @p{(1,c)} and @p{(1,b)}
					   // at the two vertices,
					   // respectively. We then
					   // have to make sure by
					   // matching @p{b,c} that
					   // these tangentials are
					   // parallel to those
					   // returned by the boundary
					   // object
	  const Tensor<1,2> coordinate_vector = line->vertex(1) - line->vertex(0);
	  const double      h                 = std::sqrt(coordinate_vector * coordinate_vector);
	  Tensor<1,2> coordinate_axis = coordinate_vector;
	  coordinate_axis /= h;

	  const double alpha = std::atan2(coordinate_axis[1], coordinate_axis[0]);
	  const double b = ((face_vertex_tangents.tangents[0][0][0] * sin(alpha)
			     -face_vertex_tangents.tangents[0][0][1] * cos(alpha)) /
			    (face_vertex_tangents.tangents[0][0][0] * cos(alpha)
			     +face_vertex_tangents.tangents[0][0][1] * sin(alpha))),
		       c = ((face_vertex_tangents.tangents[1][0][0] * sin(alpha)
			     -face_vertex_tangents.tangents[1][0][1] * cos(alpha)) /
			    (face_vertex_tangents.tangents[1][0][0] * cos(alpha)
			     +face_vertex_tangents.tangents[1][0][1] * sin(alpha)));

					   // next evaluate the so
					   // determined cubic
					   // polynomial at the points
					   // 1/3 and 2/3, first in
					   // unit coordinates
	  const Point<2> new_unit_points[2] = { Point<2>(1./3., 1./27.*(2*b+8*c)),
						  Point<2>(2./3., 4./27.*b+10./27.*c) };
					   // then transform these
					   // points to real
					   // coordinates by rotating,
					   // scaling and shifting
	  for (unsigned int i=0; i<2; ++i)
	    {
	      Point<2> real_point (cos(alpha) * new_unit_points[i][0]
				   - sin(alpha) * new_unit_points[i][1],
				   sin(alpha) * new_unit_points[i][0]
				   + cos(alpha) * new_unit_points[i][1]);
	      real_point *= h;
	      real_point += line->vertex(0);
	      a.push_back (real_point);
	    };
	}
      else
					 // not at boundary
	{
	  static const StraightBoundary<dim> straight_boundary;
	  straight_boundary.get_intermediate_points_on_line (line, line_points);
	  a.insert (a.end(), line_points.begin(), line_points.end());
	};
    };
};

#endif

template <int dim>
void
MappingC1<dim>::add_line_support_points (const typename Triangulation<dim>::cell_iterator &cell,
					 typename std::vector<Point<dim> > &a) const
{
  Assert (false, ExcNotImplemented());
};

#if deal_II_dimension == 1

template <>
void
MappingC1<1>::add_quad_support_points (const Triangulation<1>::cell_iterator &,
				       std::vector<Point<1> > &) const
{
  const unsigned int dim = 1;
  Assert (dim > 2, ExcImpossibleInDim(dim));
};

#endif

#if deal_II_dimension == 2

template <>
void
MappingC1<2>::add_quad_support_points (const Triangulation<2>::cell_iterator &,
				       std::vector<Point<2> > &) const
{
  const unsigned int dim = 2;
  Assert (dim > 2, ExcImpossibleInDim(dim));
};

#endif

template <int dim>
void
MappingC1<dim>::add_quad_support_points (const typename Triangulation<dim>::cell_iterator &,
					 typename std::vector<Point<dim> > &) const
{
  Assert (false, ExcNotImplemented());
};

// explicit instantiations
template class MappingC1<deal_II_dimension>;
<commit_msg>Avoid warning.<commit_after>//----------------------------  mapping_c1.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  mapping_c1.cc  ---------------------------

#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <grid/tria_boundary.h>
#include <fe/mapping_c1.h>
#include <cmath>

template <int dim>
MappingC1<dim>::MappingC1 ()
		:
		MappingQ<dim> (3)
{
  Assert (dim > 1, ExcImpossibleInDim(dim));
};

#if deal_II_dimension == 1

template <>
void
MappingC1<1>::add_line_support_points (const Triangulation<1>::cell_iterator &,
				       std::vector<Point<1> > &) const
{
  const unsigned int dim = 1;
  Assert (dim > 1, ExcImpossibleInDim(dim));
};

#endif

#if deal_II_dimension == 2

template <>
void
MappingC1<2>::add_line_support_points (const Triangulation<2>::cell_iterator &cell,
				       std::vector<Point<2> > &a) const
{
  const unsigned int dim = 2;
  std::vector<Point<dim> > line_points (2);

				       // loop over each of the lines,
				       // and if it is at the
				       // boundary, then first get the
				       // boundary description and
				       // second compute the points on
				       // it. if not at the boundary,
				       // get the respective points
				       // from another function
  for (unsigned int line_no=0; line_no<GeometryInfo<dim>::lines_per_cell; ++line_no)
    {
      const Triangulation<dim>::line_iterator line = cell->line(line_no);

      if (line->at_boundary())
	{
					   // first get the tangential
					   // vectors at the two
					   // vertices of this line
					   // from the boundary
					   // description
	  const Boundary<dim> &boundary
	    = line->get_triangulation().get_boundary(line->boundary_indicator());

	  Boundary<dim>::FaceVertexTangents face_vertex_tangents;
	  boundary.get_tangents_at_vertices (line, face_vertex_tangents);

					   // then transform them into
					   // interpolation points for
					   // a cubic polynomial
					   //
					   // for this, note that if
					   // we describe the boundary
					   // curve as a polynomial in
					   // tangential coordinate
					   // @p{t=0..1} (along the
					   // line) and @p{s} in
					   // normal direction, then
					   // the cubic mapping is
					   // such that @p{s = a*t**3
					   // + b*t**2 + c*t + d}, and
					   // we want to determine the
					   // interpolation points at
					   // @p{t=1/3} and
					   // @p{t=2/3}. Since at
					   // @p{t=0,1} we want a
					   // vertex which is actually
					   // at the boundary, we know
					   // that @p{d=0} and
					   // @p{a=-b-c}. As
					   // side-conditions, we want
					   // that the derivatives at
					   // @p{t=0} and @p{t=1},
					   // i.e. at the vertices
					   // match those returned by
					   // the boundary. We then
					   // have that
					   // @p{s(1/3)=1/27(2b+8c)}
					   // and
					   // @p{s(2/3)=4/27b+10/27c}.
					   //
					   // The task is then first
					   // to determine the
					   // coefficients from the
					   // tangentials. for that,
					   // first rotate the
					   // tangentials of @p{s(t)}
					   // into the global
					   // coordinate system. they
					   // are @p{A (1,c)} and @p{A
					   // (1,b)} with @p{A} the
					   // rotation matrix, since
					   // the tangentials in the
					   // coordinate system
					   // relative to the line are
					   // @p{(1,c)} and @p{(1,b)}
					   // at the two vertices,
					   // respectively. We then
					   // have to make sure by
					   // matching @p{b,c} that
					   // these tangentials are
					   // parallel to those
					   // returned by the boundary
					   // object
	  const Tensor<1,2> coordinate_vector = line->vertex(1) - line->vertex(0);
	  const double      h                 = std::sqrt(coordinate_vector * coordinate_vector);
	  Tensor<1,2> coordinate_axis = coordinate_vector;
	  coordinate_axis /= h;

	  const double alpha = std::atan2(coordinate_axis[1], coordinate_axis[0]);
	  const double b = ((face_vertex_tangents.tangents[0][0][0] * sin(alpha)
			     -face_vertex_tangents.tangents[0][0][1] * cos(alpha)) /
			    (face_vertex_tangents.tangents[0][0][0] * cos(alpha)
			     +face_vertex_tangents.tangents[0][0][1] * sin(alpha))),
		       c = ((face_vertex_tangents.tangents[1][0][0] * sin(alpha)
			     -face_vertex_tangents.tangents[1][0][1] * cos(alpha)) /
			    (face_vertex_tangents.tangents[1][0][0] * cos(alpha)
			     +face_vertex_tangents.tangents[1][0][1] * sin(alpha)));

					   // next evaluate the so
					   // determined cubic
					   // polynomial at the points
					   // 1/3 and 2/3, first in
					   // unit coordinates
	  const Point<2> new_unit_points[2] = { Point<2>(1./3., 1./27.*(2*b+8*c)),
						  Point<2>(2./3., 4./27.*b+10./27.*c) };
					   // then transform these
					   // points to real
					   // coordinates by rotating,
					   // scaling and shifting
	  for (unsigned int i=0; i<2; ++i)
	    {
	      Point<2> real_point (cos(alpha) * new_unit_points[i][0]
				   - sin(alpha) * new_unit_points[i][1],
				   sin(alpha) * new_unit_points[i][0]
				   + cos(alpha) * new_unit_points[i][1]);
	      real_point *= h;
	      real_point += line->vertex(0);
	      a.push_back (real_point);
	    };
	}
      else
					 // not at boundary
	{
	  static const StraightBoundary<dim> straight_boundary;
	  straight_boundary.get_intermediate_points_on_line (line, line_points);
	  a.insert (a.end(), line_points.begin(), line_points.end());
	};
    };
};

#endif

template <int dim>
void
MappingC1<dim>::add_line_support_points (const typename Triangulation<dim>::cell_iterator &,
					 typename std::vector<Point<dim> > &) const
{
  Assert (false, ExcNotImplemented());
};

#if deal_II_dimension == 1

template <>
void
MappingC1<1>::add_quad_support_points (const Triangulation<1>::cell_iterator &,
				       std::vector<Point<1> > &) const
{
  const unsigned int dim = 1;
  Assert (dim > 2, ExcImpossibleInDim(dim));
};

#endif

#if deal_II_dimension == 2

template <>
void
MappingC1<2>::add_quad_support_points (const Triangulation<2>::cell_iterator &,
				       std::vector<Point<2> > &) const
{
  const unsigned int dim = 2;
  Assert (dim > 2, ExcImpossibleInDim(dim));
};

#endif

template <int dim>
void
MappingC1<dim>::add_quad_support_points (const typename Triangulation<dim>::cell_iterator &,
					 typename std::vector<Point<dim> > &) const
{
  Assert (false, ExcNotImplemented());
};

// explicit instantiations
template class MappingC1<deal_II_dimension>;
<|endoftext|>