<commit_before>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include "dbusgateway.h"
#include "pelagicontain-common.h"

DBusGateway::DBusGateway(ProxyType type, const std::string &gatewayDir, const std::string &name) :
    Gateway(ID), m_type(type), m_pid(-1), m_infp(-1), m_outfp(-1),
    m_hasBeenConfigured(false), m_dbusProxyStarted(false)
{
    if (m_type == SessionProxy) {
        m_socket = gatewayDir
                + std::string("/sess_")
                + name
                + std::string(".sock");
    } else {
        m_socket = gatewayDir
                + std::string("/sys_")
                + name
                + std::string(".sock");
    }
}

DBusGateway::~DBusGateway()
{
}

bool DBusGateway::setConfig(const std::string &config)
{
    JSonElement rootElement(config);

    if ( !rootElement.isArray() ) {
        return false;
    }

    std::vector<JSonElement> elements;
    rootElement.readChildren(elements);

    if (elements.size() > 1) {
        // TODO : remove that limitation
        log_error() << "The DBUS gateway currently supports only 1 configuration snippet";
        return false;
    }

    if (elements.size() == 1) {
        m_config = elements[0].dump();
    }

    if (m_config.length() > 1) {
        m_hasBeenConfigured = true;
        return true;
    }

    return false;
}

bool DBusGateway::activate()
{
    if (!m_hasBeenConfigured) {
        log_warning() << "'Activate' called on non-configured gateway " << id();
        return false;
    }

    // set DBUS ENV
    std::string variable = "DBUS_";
    if (m_type == SessionProxy) {
        variable += "SESSION";
    } else {
        variable += "SYSTEM";
    }
    variable += "_BUS_ADDRESS";

    std::string value = "unix:path=/gateways/";
    value += socketName();
    setEnvironmentVariable(variable, value);

    // Open pipe
    std::string command = "dbus-proxy ";
    command += m_socket + " " + typeString();
    log_debug() << command;
    m_pid = makePopenCall(command, &m_infp, &m_outfp);
    if (m_pid == -1) {
        log_error() << "Failed to launch " << command;
        return false;
    } else {
        log_debug() << "Started dbus-proxy: " << m_pid;
        m_dbusProxyStarted = true;
    }

    size_t count = sizeof(char) * m_config.length();

    ssize_t written = write(m_infp,
            m_config.c_str(),
            count);

    // writing didn't work at all
    if (written == -1) {
        log_error() << "Failed to write to STDIN of dbus-proxy: " << strerror(errno);
        return false;
    }

    // writing has written exact amout of bytes
    if (written == (ssize_t)count) {
        close(m_infp);
        m_infp = -1;
        // dbus-proxy might take some time to create the bus socket
        if ( isSocketCreated() ) {
            log_debug() << "Found D-Bus socket: " << m_socket;
        } else {
            log_error() << "Did not find any D-Bus socket: " << m_socket;
            return false;
        }
        return true;
    }

    // something went wrong during the write
    log_error() << "Failed to write to STDIN of dbus-proxy!";

    return false;
}

bool DBusGateway::isSocketCreated() const
{
    int maxCount = 1000;
    int count = 0;
    do {
        if (count >= maxCount) {
            return false;
        }
        count++;
        usleep(1000 * 10);
    } while (access(m_socket.c_str(), F_OK) == -1);
    return true;
}

bool DBusGateway::teardown()
{
    bool success = true;

    if (m_dbusProxyStarted) {
        if (m_pid != -1) {
            if ( !makePcloseCall(m_pid, m_infp, m_outfp) ) {
                log_error() << "makePcloseCall() returned error";
                success = false;
            }
        } else {
            log_error() << "Failed to close connection to dbus-proxy!";
            success = false;
        }

        if (unlink( m_socket.c_str() ) == -1) {
            log_error() << "Could not remove " << m_socket << ": " << strerror(errno);
            success = false;
        }
    }

    return success;
}

const char *DBusGateway::typeString()
{
    if (m_type == SessionProxy) {
        return "session";
    } else {
        return "system";
    }
}

std::string DBusGateway::socketName()
{
    // Return the filename after stripping directory info
    std::string socket( m_socket.c_str() );
    return socket.substr(socket.rfind('/') + 1);
}

pid_t DBusGateway::makePopenCall(const std::string &command,
        int *infp,
        int *outfp)
{
    int READ = 0;
    int WRITE = 1;

    int stdinfp[2], stdoutfp[2];
    pid_t pid;

    if (pipe(stdinfp) != 0 || pipe(stdoutfp) != 0) {
        log_error() << "Failed to open STDIN and STDOUT to dbus-proxy";
        return -1;
    }

    pid = fork();

    if (pid < 0) {
        return pid;
    } else if (pid == 0) {
        close(stdinfp[WRITE]);
        dup2(stdinfp[READ], READ);
        close(stdoutfp[READ]);
        dup2(stdoutfp[WRITE], WRITE);

        // Set group id to the same as pid, that way we can kill the
        // shells children on close.
        setpgid(0, 0);

        execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
        log_error() << "execl : " << strerror(errno);
        exit(1);
    }

    if (infp == NULL) {
        close(stdinfp[WRITE]);
    } else {
        *infp = stdinfp[WRITE];
    }

    if (outfp == NULL) {
        close(stdoutfp[READ]);
    } else {
        *outfp = stdoutfp[READ];
    }

    return pid;
}

bool DBusGateway::makePcloseCall(pid_t pid, int infp, int outfp)
{
    if (infp > -1) {
        if (close(infp) == -1) {
            log_warning() << "Failed to close STDIN to dbus-proxy";
        }
    }
    if (outfp != -1) {
        if (close(outfp) == -1) {
            log_warning() << "Failed to close STDOUT to dbus-proxy";
        }
    }

    // the negative pid mekes it to kill the whole group, not only the shell
    int killed = kill(-pid, SIGKILL);

    return (killed == 0);
}
<commit_msg>dbusgateway.cpp: restore functionality for multiple snippets<commit_after>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include "dbusgateway.h"
#include "pelagicontain-common.h"

DBusGateway::DBusGateway(ProxyType type, const std::string &gatewayDir, const std::string &name) :
    Gateway(ID), m_type(type), m_pid(-1), m_infp(-1), m_outfp(-1),
    m_hasBeenConfigured(false), m_dbusProxyStarted(false)
{
    if (m_type == SessionProxy) {
        m_socket = gatewayDir
                + std::string("/sess_")
                + name
                + std::string(".sock");
    } else {
        m_socket = gatewayDir
                + std::string("/sys_")
                + name
                + std::string(".sock");
    }
}

DBusGateway::~DBusGateway()
{
}

bool DBusGateway::setConfig(const std::string &config)
{
    m_config = config;
    if (m_config.length() > 1) {
        m_hasBeenConfigured = true;
        return true;
    }

    return false;
}

bool DBusGateway::activate()
{
    if (!m_hasBeenConfigured) {
        log_warning() << "'Activate' called on non-configured gateway " << id();
        return false;
    }

    // set DBUS ENV
    std::string variable = "DBUS_";
    if (m_type == SessionProxy) {
        variable += "SESSION";
    } else {
        variable += "SYSTEM";
    }
    variable += "_BUS_ADDRESS";

    std::string value = "unix:path=/gateways/";
    value += socketName();
    setEnvironmentVariable(variable, value);

    // Open pipe
    std::string command = "dbus-proxy ";
    command += m_socket + " " + typeString();
    log_debug() << command;
    m_pid = makePopenCall(command, &m_infp, &m_outfp);
    if (m_pid == -1) {
        log_error() << "Failed to launch " << command;
        return false;
    } else {
        log_debug() << "Started dbus-proxy: " << m_pid;
        m_dbusProxyStarted = true;
    }

    size_t count = sizeof(char) * m_config.length();

    ssize_t written = write(m_infp,
            m_config.c_str(),
            count);

    // writing didn't work at all
    if (written == -1) {
        log_error() << "Failed to write to STDIN of dbus-proxy: " << strerror(errno);
        return false;
    }

    // writing has written exact amout of bytes
    if (written == (ssize_t)count) {
        close(m_infp);
        m_infp = -1;
        // dbus-proxy might take some time to create the bus socket
        if ( isSocketCreated() ) {
            log_debug() << "Found D-Bus socket: " << m_socket;
        } else {
            log_error() << "Did not find any D-Bus socket: " << m_socket;
            return false;
        }
        return true;
    }

    // something went wrong during the write
    log_error() << "Failed to write to STDIN of dbus-proxy!";

    return false;
}

bool DBusGateway::isSocketCreated() const
{
    int maxCount = 1000;
    int count = 0;
    do {
        if (count >= maxCount) {
            return false;
        }
        count++;
        usleep(1000 * 10);
    } while (access(m_socket.c_str(), F_OK) == -1);
    return true;
}

bool DBusGateway::teardown()
{
    bool success = true;

    if (m_dbusProxyStarted) {
        if (m_pid != -1) {
            if ( !makePcloseCall(m_pid, m_infp, m_outfp) ) {
                log_error() << "makePcloseCall() returned error";
                success = false;
            }
        } else {
            log_error() << "Failed to close connection to dbus-proxy!";
            success = false;
        }

        if (unlink( m_socket.c_str() ) == -1) {
            log_error() << "Could not remove " << m_socket << ": " << strerror(errno);
            success = false;
        }
    }

    return success;
}

const char *DBusGateway::typeString()
{
    if (m_type == SessionProxy) {
        return "session";
    } else {
        return "system";
    }
}

std::string DBusGateway::socketName()
{
    // Return the filename after stripping directory info
    std::string socket( m_socket.c_str() );
    return socket.substr(socket.rfind('/') + 1);
}

pid_t DBusGateway::makePopenCall(const std::string &command,
        int *infp,
        int *outfp)
{
    int READ = 0;
    int WRITE = 1;

    int stdinfp[2], stdoutfp[2];
    pid_t pid;

    if (pipe(stdinfp) != 0 || pipe(stdoutfp) != 0) {
        log_error() << "Failed to open STDIN and STDOUT to dbus-proxy";
        return -1;
    }

    pid = fork();

    if (pid < 0) {
        return pid;
    } else if (pid == 0) {
        close(stdinfp[WRITE]);
        dup2(stdinfp[READ], READ);
        close(stdoutfp[READ]);
        dup2(stdoutfp[WRITE], WRITE);

        // Set group id to the same as pid, that way we can kill the
        // shells children on close.
        setpgid(0, 0);

        execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
        log_error() << "execl : " << strerror(errno);
        exit(1);
    }

    if (infp == NULL) {
        close(stdinfp[WRITE]);
    } else {
        *infp = stdinfp[WRITE];
    }

    if (outfp == NULL) {
        close(stdoutfp[READ]);
    } else {
        *outfp = stdoutfp[READ];
    }

    return pid;
}

bool DBusGateway::makePcloseCall(pid_t pid, int infp, int outfp)
{
    if (infp > -1) {
        if (close(infp) == -1) {
            log_warning() << "Failed to close STDIN to dbus-proxy";
        }
    }
    if (outfp != -1) {
        if (close(outfp) == -1) {
            log_warning() << "Failed to close STDOUT to dbus-proxy";
        }
    }

    // the negative pid mekes it to kill the whole group, not only the shell
    int killed = kill(-pid, SIGKILL);

    return (killed == 0);
}
<|endoftext|>


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

#include "content/renderer/media/webrtc_audio_renderer.h"

#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "content/renderer/media/audio_device_factory.h"
#include "content/renderer/media/webrtc_audio_device_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "media/audio/audio_output_device.h"
#include "media/audio/audio_parameters.h"
#include "media/audio/sample_rates.h"
#include "media/base/audio_hardware_config.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "media/audio/win/core_audio_util_win.h"
#endif

namespace content {

namespace {

// Supported hardware sample rates for output sides.
#if defined(OS_WIN) || defined(OS_MACOSX)
// AudioHardwareConfig::GetOutputSampleRate() asks the audio layer for its
// current sample rate (set by the user) on Windows and Mac OS X.  The listed
// rates below adds restrictions and Initialize() will fail if the user selects
// any rate outside these ranges.
const int kValidOutputRates[] = {96000, 48000, 44100, 32000, 16000};
#elif defined(OS_LINUX) || defined(OS_OPENBSD)
const int kValidOutputRates[] = {48000, 44100};
#elif defined(OS_ANDROID)
// TODO(leozwang): We want to use native sampling rate on Android to achieve
// low latency, currently 16000 is used to work around audio problem on some
// Android devices.
const int kValidOutputRates[] = {48000, 44100, 16000};
#else
const int kValidOutputRates[] = {44100};
#endif

// TODO(xians): Merge the following code to WebRtcAudioCapturer, or remove.
enum AudioFramesPerBuffer {
  k160,
  k320,
  k440,  // WebRTC works internally with 440 audio frames at 44.1kHz.
  k480,
  k640,
  k880,
  k960,
  k1440,
  k1920,
  kUnexpectedAudioBufferSize  // Must always be last!
};

// Helper method to convert integral values to their respective enum values
// above, or kUnexpectedAudioBufferSize if no match exists.
AudioFramesPerBuffer AsAudioFramesPerBuffer(int frames_per_buffer) {
  switch (frames_per_buffer) {
    case 160: return k160;
    case 320: return k320;
    case 440: return k440;
    case 480: return k480;
    case 640: return k640;
    case 880: return k880;
    case 960: return k960;
    case 1440: return k1440;
    case 1920: return k1920;
  }
  return kUnexpectedAudioBufferSize;
}

void AddHistogramFramesPerBuffer(int param) {
  AudioFramesPerBuffer afpb = AsAudioFramesPerBuffer(param);
  if (afpb != kUnexpectedAudioBufferSize) {
    UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
                              afpb, kUnexpectedAudioBufferSize);
  } else {
    // Report unexpected sample rates using a unique histogram name.
    UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputFramesPerBufferUnexpected", param);
  }
}

}  // namespace

WebRtcAudioRenderer::WebRtcAudioRenderer(int source_render_view_id)
    : state_(UNINITIALIZED),
      source_render_view_id_(source_render_view_id),
      source_(NULL),
      play_ref_count_(0),
      audio_delay_milliseconds_(0),
      frame_duration_milliseconds_(0),
      fifo_io_ratio_(1) {
}

WebRtcAudioRenderer::~WebRtcAudioRenderer() {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK_EQ(state_, UNINITIALIZED);
  buffer_.reset();
}

bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
  DVLOG(1) << "WebRtcAudioRenderer::Initialize()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, UNINITIALIZED);
  DCHECK(source);
  DCHECK(!sink_);
  DCHECK(!source_);

  // Use mono on all platforms but Windows for now.
  // TODO(henrika): Tracking at http://crbug.com/166771.
  media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_MONO;
#if defined(OS_WIN)
  channel_layout = media::CHANNEL_LAYOUT_STEREO;
#endif

  // Ask the renderer for the default audio output hardware sample-rate.
  media::AudioHardwareConfig* hardware_config =
      RenderThreadImpl::current()->GetAudioHardwareConfig();
  int sample_rate = hardware_config->GetOutputSampleRate();
  DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate",
                            sample_rate, media::kUnexpectedAudioSampleRate);

  // Verify that the reported output hardware sample rate is supported
  // on the current platform.
  if (std::find(&kValidOutputRates[0],
                &kValidOutputRates[0] + arraysize(kValidOutputRates),
                sample_rate) ==
                    &kValidOutputRates[arraysize(kValidOutputRates)]) {
    DLOG(ERROR) << sample_rate << " is not a supported output rate.";
    return false;
  }

  // Set up audio parameters for the source, i.e., the WebRTC client.
  // The WebRTC client only supports multiples of 10ms as buffer size where
  // 10ms is preferred for lowest possible delay.

  media::AudioParameters source_params;
  int buffer_size = 0;

  if (sample_rate % 8000 == 0) {
    buffer_size = (sample_rate / 100);
  } else if (sample_rate == 44100) {
    // The resampler in WebRTC does not support 441 as input. We hard code
    // the size to 440 (~0.9977ms) instead and rely on the internal jitter
    // buffer in WebRTC to deal with the resulting drift.
    // TODO(henrika): ensure that WebRTC supports 44100Hz and use 441 instead.
    buffer_size = 440;
  } else {
    return false;
  }

  int channels = ChannelLayoutToChannelCount(channel_layout);
  source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                      channel_layout, channels, 0,
                      sample_rate, 16, buffer_size);

  // Set up audio parameters for the sink, i.e., the native audio output stream.
  // We strive to open up using native parameters to achieve best possible
  // performance and to ensure that no FIFO is needed on the browser side to
  // match the client request. Any mismatch between the source and the sink is
  // taken care of in this class instead using a pull FIFO.

  media::AudioParameters sink_params;

  buffer_size = hardware_config->GetOutputBufferSize();
  sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                    channel_layout, channels, 0, sample_rate, 16, buffer_size);

  // Create a FIFO if re-buffering is required to match the source input with
  // the sink request. The source acts as provider here and the sink as
  // consumer.
  if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) {
    DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
             << " to " << sink_params.frames_per_buffer();
    audio_fifo_.reset(new media::AudioPullFifo(
        source_params.channels(),
        source_params.frames_per_buffer(),
        base::Bind(
            &WebRtcAudioRenderer::SourceCallback,
            base::Unretained(this))));

    // The I/O ratio is used in delay calculations where one scheme is used
    // for |fifo_io_ratio_| > 1 and another scheme for < 1.0.
    fifo_io_ratio_ = static_cast<double>(source_params.frames_per_buffer()) /
        sink_params.frames_per_buffer();
  }

  frame_duration_milliseconds_ = base::Time::kMillisecondsPerSecond /
      static_cast<double>(source_params.sample_rate());

  // Allocate local audio buffers based on the parameters above.
  // It is assumed that each audio sample contains 16 bits and each
  // audio frame contains one or two audio samples depending on the
  // number of channels.
  buffer_.reset(
      new int16[source_params.frames_per_buffer() * source_params.channels()]);

  source_ = source;
  source->SetRenderFormat(source_params);

  // Configure the audio rendering client and start rendering.
  sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_);
  sink_->Initialize(sink_params, this);
  sink_->Start();

  // User must call Play() before any audio can be heard.
  state_ = PAUSED;

  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout",
                            source_params.channel_layout(),
                            media::CHANNEL_LAYOUT_MAX);
  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
                            source_params.frames_per_buffer(),
                            kUnexpectedAudioBufferSize);
  AddHistogramFramesPerBuffer(source_params.frames_per_buffer());

  return true;
}

void WebRtcAudioRenderer::Start() {
  // TODO(xians): refactor to make usage of Start/Stop more symmetric.
  NOTIMPLEMENTED();
}

void WebRtcAudioRenderer::Play() {
  DVLOG(1) << "WebRtcAudioRenderer::Play()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  DCHECK(play_ref_count_ == 0 || state_ == PLAYING);
  ++play_ref_count_;
  state_ = PLAYING;

  if (audio_fifo_) {
    audio_delay_milliseconds_ = 0;
    audio_fifo_->Clear();
  }
}

void WebRtcAudioRenderer::Pause() {
  DVLOG(1) << "WebRtcAudioRenderer::Pause()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  DCHECK_EQ(state_, PLAYING);
  DCHECK_GT(play_ref_count_, 0);
  if (!--play_ref_count_)
    state_ = PAUSED;
}

void WebRtcAudioRenderer::Stop() {
  DVLOG(1) << "WebRtcAudioRenderer::Stop()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  source_->RemoveAudioRenderer(this);
  source_ = NULL;
  sink_->Stop();
  state_ = UNINITIALIZED;
}

void WebRtcAudioRenderer::SetVolume(float volume) {
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  sink_->SetVolume(volume);
}

base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const {
  return base::TimeDelta();
}

bool WebRtcAudioRenderer::IsLocalRenderer() const {
  return false;
}

int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus,
                                int audio_delay_milliseconds) {
  base::AutoLock auto_lock(lock_);
  if (!source_)
    return 0;

  DVLOG(2) << "WebRtcAudioRenderer::Render()";
  DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds;

  if (fifo_io_ratio_ > 1.0)
    audio_delay_milliseconds_ += audio_delay_milliseconds;
  else
    audio_delay_milliseconds_ = audio_delay_milliseconds;

  if (audio_fifo_)
    audio_fifo_->Consume(audio_bus, audio_bus->frames());
  else
    SourceCallback(0, audio_bus);

  return (state_ == PLAYING) ? audio_bus->frames() : 0;
}

void WebRtcAudioRenderer::OnRenderError() {
  NOTIMPLEMENTED();
  LOG(ERROR) << "OnRenderError()";
}

// Called by AudioPullFifo when more data is necessary.
void WebRtcAudioRenderer::SourceCallback(
    int fifo_frame_delay, media::AudioBus* audio_bus) {
  DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
           << fifo_frame_delay << ", "
           << audio_bus->frames() << ")";

  int output_delay_milliseconds = audio_delay_milliseconds_;
  output_delay_milliseconds += frame_duration_milliseconds_ * fifo_frame_delay;
  DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;

  // We need to keep render data for the |source_| regardless of |state_|,
  // otherwise the data will be buffered up inside |source_|.
  source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()),
                      audio_bus->channels(), audio_bus->frames(),
                      output_delay_milliseconds);

  if (fifo_io_ratio_ > 1.0)
    audio_delay_milliseconds_ = 0;

  // Avoid filling up the audio bus if we are not playing; instead
  // return here and ensure that the returned value in Render() is 0.
  if (state_ != PLAYING) {
    audio_bus->Zero();
    return;
  }

  // De-interleave each channel and convert to 32-bit floating-point
  // with nominal range -1.0 -> +1.0 to match the callback format.
  audio_bus->FromInterleaved(buffer_.get(),
                             audio_bus->frames(),
                             sizeof(buffer_[0]));
}

}  // namespace content
<commit_msg>Adds support for 192kHz native output sample rate for WebRTC clients<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media/webrtc_audio_renderer.h"

#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "content/renderer/media/audio_device_factory.h"
#include "content/renderer/media/webrtc_audio_device_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "media/audio/audio_output_device.h"
#include "media/audio/audio_parameters.h"
#include "media/audio/sample_rates.h"
#include "media/base/audio_hardware_config.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "media/audio/win/core_audio_util_win.h"
#endif

namespace content {

namespace {

// Supported hardware sample rates for output sides.
#if defined(OS_WIN) || defined(OS_MACOSX)
// AudioHardwareConfig::GetOutputSampleRate() asks the audio layer for its
// current sample rate (set by the user) on Windows and Mac OS X.  The listed
// rates below adds restrictions and Initialize() will fail if the user selects
// any rate outside these ranges.
const int kValidOutputRates[] = {96000, 48000, 44100, 32000, 16000};
#elif defined(OS_LINUX) || defined(OS_OPENBSD)
const int kValidOutputRates[] = {48000, 44100};
#elif defined(OS_ANDROID)
// TODO(leozwang): We want to use native sampling rate on Android to achieve
// low latency, currently 16000 is used to work around audio problem on some
// Android devices.
const int kValidOutputRates[] = {48000, 44100, 16000};
#else
const int kValidOutputRates[] = {44100};
#endif

// TODO(xians): Merge the following code to WebRtcAudioCapturer, or remove.
enum AudioFramesPerBuffer {
  k160,
  k320,
  k440,  // WebRTC works internally with 440 audio frames at 44.1kHz.
  k480,
  k640,
  k880,
  k960,
  k1440,
  k1920,
  kUnexpectedAudioBufferSize  // Must always be last!
};

// Helper method to convert integral values to their respective enum values
// above, or kUnexpectedAudioBufferSize if no match exists.
AudioFramesPerBuffer AsAudioFramesPerBuffer(int frames_per_buffer) {
  switch (frames_per_buffer) {
    case 160: return k160;
    case 320: return k320;
    case 440: return k440;
    case 480: return k480;
    case 640: return k640;
    case 880: return k880;
    case 960: return k960;
    case 1440: return k1440;
    case 1920: return k1920;
  }
  return kUnexpectedAudioBufferSize;
}

void AddHistogramFramesPerBuffer(int param) {
  AudioFramesPerBuffer afpb = AsAudioFramesPerBuffer(param);
  if (afpb != kUnexpectedAudioBufferSize) {
    UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
                              afpb, kUnexpectedAudioBufferSize);
  } else {
    // Report unexpected sample rates using a unique histogram name.
    UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputFramesPerBufferUnexpected", param);
  }
}

}  // namespace

WebRtcAudioRenderer::WebRtcAudioRenderer(int source_render_view_id)
    : state_(UNINITIALIZED),
      source_render_view_id_(source_render_view_id),
      source_(NULL),
      play_ref_count_(0),
      audio_delay_milliseconds_(0),
      frame_duration_milliseconds_(0),
      fifo_io_ratio_(1) {
}

WebRtcAudioRenderer::~WebRtcAudioRenderer() {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK_EQ(state_, UNINITIALIZED);
  buffer_.reset();
}

bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
  DVLOG(1) << "WebRtcAudioRenderer::Initialize()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, UNINITIALIZED);
  DCHECK(source);
  DCHECK(!sink_);
  DCHECK(!source_);

  // Use mono on all platforms but Windows for now.
  // TODO(henrika): Tracking at http://crbug.com/166771.
  media::ChannelLayout channel_layout = media::CHANNEL_LAYOUT_MONO;
#if defined(OS_WIN)
  channel_layout = media::CHANNEL_LAYOUT_STEREO;
#endif

  // Ask the renderer for the default audio output hardware sample-rate.
  media::AudioHardwareConfig* hardware_config =
      RenderThreadImpl::current()->GetAudioHardwareConfig();
  int sample_rate = hardware_config->GetOutputSampleRate();
  DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;

  // WebRTC does not yet support higher rates than 96000 on the client side
  // and 48000 is the preferred sample rate. Therefore, if 192000 is detected,
  // we change the rate to 48000 instead. The consequence is that the native
  // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz
  // which will then be resampled by the audio converted on the browser side
  // to match the native audio layer.
  if (sample_rate == 192000) {
    DVLOG(1) << "Resampling from 48000 to 192000 is required";
    sample_rate = 48000;
  }
  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate",
                            sample_rate, media::kUnexpectedAudioSampleRate);

  // Verify that the reported output hardware sample rate is supported
  // on the current platform.
  if (std::find(&kValidOutputRates[0],
                &kValidOutputRates[0] + arraysize(kValidOutputRates),
                sample_rate) ==
                    &kValidOutputRates[arraysize(kValidOutputRates)]) {
    DLOG(ERROR) << sample_rate << " is not a supported output rate.";
    return false;
  }

  // Set up audio parameters for the source, i.e., the WebRTC client.
  // The WebRTC client only supports multiples of 10ms as buffer size where
  // 10ms is preferred for lowest possible delay.

  media::AudioParameters source_params;
  int buffer_size = 0;

  if (sample_rate % 8000 == 0) {
    buffer_size = (sample_rate / 100);
  } else if (sample_rate == 44100) {
    // The resampler in WebRTC does not support 441 as input. We hard code
    // the size to 440 (~0.9977ms) instead and rely on the internal jitter
    // buffer in WebRTC to deal with the resulting drift.
    // TODO(henrika): ensure that WebRTC supports 44100Hz and use 441 instead.
    buffer_size = 440;
  } else {
    return false;
  }

  int channels = ChannelLayoutToChannelCount(channel_layout);
  source_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                      channel_layout, channels, 0,
                      sample_rate, 16, buffer_size);

  // Set up audio parameters for the sink, i.e., the native audio output stream.
  // We strive to open up using native parameters to achieve best possible
  // performance and to ensure that no FIFO is needed on the browser side to
  // match the client request. Any mismatch between the source and the sink is
  // taken care of in this class instead using a pull FIFO.

  media::AudioParameters sink_params;

  buffer_size = hardware_config->GetOutputBufferSize();
  sink_params.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                    channel_layout, channels, 0, sample_rate, 16, buffer_size);

  // Create a FIFO if re-buffering is required to match the source input with
  // the sink request. The source acts as provider here and the sink as
  // consumer.
  if (source_params.frames_per_buffer() != sink_params.frames_per_buffer()) {
    DVLOG(1) << "Rebuffering from " << source_params.frames_per_buffer()
             << " to " << sink_params.frames_per_buffer();
    audio_fifo_.reset(new media::AudioPullFifo(
        source_params.channels(),
        source_params.frames_per_buffer(),
        base::Bind(
            &WebRtcAudioRenderer::SourceCallback,
            base::Unretained(this))));

    // The I/O ratio is used in delay calculations where one scheme is used
    // for |fifo_io_ratio_| > 1 and another scheme for < 1.0.
    fifo_io_ratio_ = static_cast<double>(source_params.frames_per_buffer()) /
        sink_params.frames_per_buffer();
  }

  frame_duration_milliseconds_ = base::Time::kMillisecondsPerSecond /
      static_cast<double>(source_params.sample_rate());

  // Allocate local audio buffers based on the parameters above.
  // It is assumed that each audio sample contains 16 bits and each
  // audio frame contains one or two audio samples depending on the
  // number of channels.
  buffer_.reset(
      new int16[source_params.frames_per_buffer() * source_params.channels()]);

  source_ = source;
  source->SetRenderFormat(source_params);

  // Configure the audio rendering client and start rendering.
  sink_ = AudioDeviceFactory::NewOutputDevice(source_render_view_id_);
  sink_->Initialize(sink_params, this);
  sink_->Start();

  // User must call Play() before any audio can be heard.
  state_ = PAUSED;

  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputChannelLayout",
                            source_params.channel_layout(),
                            media::CHANNEL_LAYOUT_MAX);
  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
                            source_params.frames_per_buffer(),
                            kUnexpectedAudioBufferSize);
  AddHistogramFramesPerBuffer(source_params.frames_per_buffer());

  return true;
}

void WebRtcAudioRenderer::Start() {
  // TODO(xians): refactor to make usage of Start/Stop more symmetric.
  NOTIMPLEMENTED();
}

void WebRtcAudioRenderer::Play() {
  DVLOG(1) << "WebRtcAudioRenderer::Play()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  DCHECK(play_ref_count_ == 0 || state_ == PLAYING);
  ++play_ref_count_;
  state_ = PLAYING;

  if (audio_fifo_) {
    audio_delay_milliseconds_ = 0;
    audio_fifo_->Clear();
  }
}

void WebRtcAudioRenderer::Pause() {
  DVLOG(1) << "WebRtcAudioRenderer::Pause()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  DCHECK_EQ(state_, PLAYING);
  DCHECK_GT(play_ref_count_, 0);
  if (!--play_ref_count_)
    state_ = PAUSED;
}

void WebRtcAudioRenderer::Stop() {
  DVLOG(1) << "WebRtcAudioRenderer::Stop()";
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  source_->RemoveAudioRenderer(this);
  source_ = NULL;
  sink_->Stop();
  state_ = UNINITIALIZED;
}

void WebRtcAudioRenderer::SetVolume(float volume) {
  DCHECK(thread_checker_.CalledOnValidThread());
  base::AutoLock auto_lock(lock_);
  if (state_ == UNINITIALIZED)
    return;

  sink_->SetVolume(volume);
}

base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const {
  return base::TimeDelta();
}

bool WebRtcAudioRenderer::IsLocalRenderer() const {
  return false;
}

int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus,
                                int audio_delay_milliseconds) {
  base::AutoLock auto_lock(lock_);
  if (!source_)
    return 0;

  DVLOG(2) << "WebRtcAudioRenderer::Render()";
  DVLOG(2) << "audio_delay_milliseconds: " << audio_delay_milliseconds;

  if (fifo_io_ratio_ > 1.0)
    audio_delay_milliseconds_ += audio_delay_milliseconds;
  else
    audio_delay_milliseconds_ = audio_delay_milliseconds;

  if (audio_fifo_)
    audio_fifo_->Consume(audio_bus, audio_bus->frames());
  else
    SourceCallback(0, audio_bus);

  return (state_ == PLAYING) ? audio_bus->frames() : 0;
}

void WebRtcAudioRenderer::OnRenderError() {
  NOTIMPLEMENTED();
  LOG(ERROR) << "OnRenderError()";
}

// Called by AudioPullFifo when more data is necessary.
void WebRtcAudioRenderer::SourceCallback(
    int fifo_frame_delay, media::AudioBus* audio_bus) {
  DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
           << fifo_frame_delay << ", "
           << audio_bus->frames() << ")";

  int output_delay_milliseconds = audio_delay_milliseconds_;
  output_delay_milliseconds += frame_duration_milliseconds_ * fifo_frame_delay;
  DVLOG(2) << "output_delay_milliseconds: " << output_delay_milliseconds;

  // We need to keep render data for the |source_| regardless of |state_|,
  // otherwise the data will be buffered up inside |source_|.
  source_->RenderData(reinterpret_cast<uint8*>(buffer_.get()),
                      audio_bus->channels(), audio_bus->frames(),
                      output_delay_milliseconds);

  if (fifo_io_ratio_ > 1.0)
    audio_delay_milliseconds_ = 0;

  // Avoid filling up the audio bus if we are not playing; instead
  // return here and ensure that the returned value in Render() is 0.
  if (state_ != PLAYING) {
    audio_bus->Zero();
    return;
  }

  // De-interleave each channel and convert to 32-bit floating-point
  // with nominal range -1.0 -> +1.0 to match the callback format.
  audio_bus->FromInterleaved(buffer_.get(),
                             audio_bus->frames(),
                             sizeof(buffer_[0]));
}

}  // namespace content
<|endoftext|>


<commit_before>#include "profilerui.h"
#include "ui_profilerui.h"
#include <qpainter.h>
#include <qpixmap.h>

static const int MAX_FRAMES = 200;

ProfileModel::Block::Block()
{
	m_frames.reserve(MAX_FRAMES);
	for(int i = 0; i < MAX_FRAMES; ++i)
	{
		m_frames.push_back(0);
	}
}

ProfileModel::ProfileModel()
{
	Lumix::g_profiler.getFrameListeners().bind<ProfileModel, &ProfileModel::onFrame>(this);
	m_root = NULL;
	m_frame = 0;
}

void ProfileModel::cloneBlock(Block* my_block, Lumix::Profiler::Block* remote_block)
{
	ASSERT(my_block->m_name == remote_block->m_name);
	my_block->m_frames.push_back(remote_block->getLength());
	if (my_block->m_frames.size() > MAX_FRAMES)
	{
		my_block->m_frames.pop_front();
	}
	if(!my_block->m_first_child && remote_block->m_first_child)
	{
		Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
		Block* last_new_child = NULL;
		while(remote_child)
		{
			Block* my_child = new Block;
			my_child->m_function = remote_child->m_function;
			my_child->m_name = remote_child->m_name;
			my_child->m_parent = my_block;
			my_child->m_next = NULL;
			my_child->m_first_child = NULL;
			if(last_new_child)
			{
				last_new_child->m_next = my_child;
			}
			else
			{
				my_block->m_first_child = my_child;
			}
			last_new_child = my_child;
			cloneBlock(my_child, remote_child);
			remote_child = remote_child->m_next;
		}
	}
	else if(my_block->m_first_child)
	{
		Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
		Block* my_child = my_block->m_first_child;
		while(remote_child)
		{
			if(my_child->m_name != remote_child->m_name && my_child->m_function != remote_child->m_function)
			{
				Block* new_child = new Block;
				new_child->m_function = remote_child->m_function;
				new_child->m_name = remote_child->m_name;
				new_child->m_parent = my_block;
				new_child->m_next = my_child;
				new_child->m_first_child = NULL;
				my_child = new_child;
				if(my_child == my_block->m_first_child)
				{
					my_block->m_first_child = new_child;
				}
			}
			cloneBlock(my_child, remote_child);
			remote_child = remote_child->m_next;
			my_child = my_child->m_next;
		}
	}
}

void ProfileModel::onFrame()
{
	if(!m_root && Lumix::g_profiler.getRootBlock())
	{
		m_root = new Block;
		m_root->m_function = Lumix::g_profiler.getRootBlock()->m_function;
		m_root->m_name = Lumix::g_profiler.getRootBlock()->m_name;
		m_root->m_parent = NULL;
		m_root->m_next = NULL;
		m_root->m_first_child = NULL;

	}
	if(m_root)
	{
		cloneBlock(m_root, Lumix::g_profiler.getRootBlock());
	}
	static int hit = 0;
	++hit;
	int count = 0;
	Block* child = m_root->m_first_child;
	while(child)
	{
		++count;
		child = child->m_next;
	}
	if(hit % 10 == 0)
	{
		emit dataChanged(createIndex(0, 0, m_root), createIndex(count, 0, m_root));
	}
}

QVariant ProfileModel::headerData(int section, Qt::Orientation, int role) const
{
	if(role == Qt::DisplayRole)
	{
		switch(section)
		{
			case Values::FUNCTION:
				return "Function";
			case Values::NAME:
				return "Name";
			case Values::LENGTH:
				return "Length (ms)";
			default:
				ASSERT(false);
				return QVariant();
		}
	}
	return QVariant();
}

QModelIndex ProfileModel::index(int row, int column, const QModelIndex& parent) const
{
	if(!hasIndex(row, column, parent))
	{
		return QModelIndex();
	}
	Block* block = NULL;
	if(parent.internalPointer() != NULL)
	{
		block = static_cast<Block*>(parent.internalPointer());
	}
	else
	{
		return createIndex(0, column, m_root);
	}

	int index = row;
	Block* child = block->m_first_child;
	while(child && index > 0)
	{
		child = child->m_next;
		--index;
	}

	return createIndex(row, column, child);
}

QModelIndex ProfileModel::parent(const QModelIndex& index) const
{
	if (!index.isValid() || !index.internalPointer())
	{
		return QModelIndex();
	}

	Block* child = static_cast<Block*>(index.internalPointer());
	Block* parent = child->m_parent;

	if (parent == NULL)
	{
		return QModelIndex();
	}

	int row = 0;
	Block* row_sibling = parent->m_first_child;
	while(row_sibling && row_sibling != child)
	{
		row_sibling = row_sibling->m_next;
		++row;
	}
	ASSERT(row_sibling);
	return createIndex(row, 0, parent);
}

int ProfileModel::rowCount(const QModelIndex& parent_index) const
{
	Block* parent;
	if (parent_index.column() > 0 || Lumix::g_profiler.getRootBlock() == NULL)
		return 0;

	if (!parent_index.isValid() || !parent_index.internalPointer())
	{
		return 1;
	}
	else
	{
		parent = static_cast<Block*>(parent_index.internalPointer());
	}

	int count = 0;
	Block* child = parent->m_first_child;
	while(child)
	{
		++count;
		child = child->m_next;
	}
	return count;
}

int ProfileModel::columnCount(const QModelIndex&) const
{
	return (int)Values::COUNT;
}

QVariant ProfileModel::data(const QModelIndex& index, int role) const
{
	if (!index.isValid() || !index.internalPointer())
	{
		return QVariant();
	}

	if (role != Qt::DisplayRole)
	{
		return QVariant();
	}
	Block* block = static_cast<Block*>(index.internalPointer());
	switch(index.column())
	{
		case Values::FUNCTION:
			return block->m_function;
		case Values::NAME:
			return block->m_name;
		case Values::LENGTH:
			{
				return m_frame >= 0 && m_frame < block->m_frames.size() ? block->m_frames[m_frame] : 0;
			}
		default:
			ASSERT(false);
			return QVariant();
	}
}

ProfilerUI::ProfilerUI(QWidget* parent)
	: QDockWidget(parent)
	, m_ui(new Ui::ProfilerUI)
{
	m_model = new ProfileModel;
	m_ui->setupUi(this);
	m_ui->profileTreeView->setModel(m_model);
	m_ui->profileTreeView->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
	m_ui->profileTreeView->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
	m_ui->profileTreeView->header()->setSectionResizeMode(2, QHeaderView::ResizeMode::ResizeToContents);
	connect(m_model, &QAbstractItemModel::dataChanged, this, &ProfilerUI::on_dataChanged);
	connect(m_ui->graphView, &ProfilerGraph::frameSet, this, &ProfilerUI::on_frameSet);
	m_ui->graphView->setModel(m_model);
}

void ProfilerUI::on_dataChanged()
{
	m_ui->graphView->update();
}

ProfilerUI::~ProfilerUI()
{
	delete m_ui;
	delete m_model;
}

void ProfilerUI::on_recordCheckBox_stateChanged(int)
{
	Lumix::g_profiler.toggleRecording();
	m_ui->profileTreeView->setModel(NULL);
	m_ui->profileTreeView->setModel(m_model);
	m_ui->profileTreeView->update();
}

void ProfilerUI::on_frameSet()
{
	m_ui->recordCheckBox->setChecked(false);
	m_ui->profileTreeView->update();
	m_model->setFrame(m_ui->graphView->getFrame());
}

void ProfilerUI::on_profileTreeView_clicked(const QModelIndex &index)
{
	if(index.internalPointer() != NULL)
	{
		m_ui->graphView->setBlock(static_cast<ProfileModel::Block*>(index.internalPointer()));
		m_ui->graphView->update();
	}
}
<commit_msg>fixed profiler ui<commit_after>#include "profilerui.h"
#include "ui_profilerui.h"
#include <qpainter.h>
#include <qpixmap.h>

static const int MAX_FRAMES = 200;

ProfileModel::Block::Block()
{
	m_frames.reserve(MAX_FRAMES);
	for(int i = 0; i < MAX_FRAMES; ++i)
	{
		m_frames.push_back(0);
	}
}

ProfileModel::ProfileModel()
{
	Lumix::g_profiler.getFrameListeners().bind<ProfileModel, &ProfileModel::onFrame>(this);
	m_root = NULL;
	m_frame = 0;
}

void ProfileModel::cloneBlock(Block* my_block, Lumix::Profiler::Block* remote_block)
{
	ASSERT(my_block->m_name == remote_block->m_name);
	my_block->m_frames.push_back(remote_block->getLength());
	if (my_block->m_frames.size() > MAX_FRAMES)
	{
		my_block->m_frames.pop_front();
	}
	if(!my_block->m_first_child && remote_block->m_first_child)
	{
		Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
		Block* last_new_child = NULL;
		while(remote_child)
		{
			Block* my_child = new Block;
			my_child->m_function = remote_child->m_function;
			my_child->m_name = remote_child->m_name;
			my_child->m_parent = my_block;
			my_child->m_next = NULL;
			my_child->m_first_child = NULL;
			if(last_new_child)
			{
				last_new_child->m_next = my_child;
			}
			else
			{
				my_block->m_first_child = my_child;
			}
			last_new_child = my_child;
			cloneBlock(my_child, remote_child);
			remote_child = remote_child->m_next;
		}
	}
	else if(my_block->m_first_child)
	{
		Lumix::Profiler::Block* remote_child = remote_block->m_first_child;
		Block* my_child = my_block->m_first_child;
		Block* prev_my_child = NULL;
		while(remote_child)
		{
			if(my_child->m_name != remote_child->m_name || my_child->m_function != remote_child->m_function)
			{
				Block* new_child = new Block;
				new_child->m_function = remote_child->m_function;
				new_child->m_name = remote_child->m_name;
				new_child->m_parent = my_block;
				new_child->m_next = my_child;
				new_child->m_first_child = NULL;
				if(my_child == my_block->m_first_child)
				{
					my_block->m_first_child = new_child;
					new_child->m_next = my_child;
				}
				else
				{
					new_child->m_next = my_child;
					prev_my_child->m_next = new_child;
				}
				my_child = new_child;
			}
			cloneBlock(my_child, remote_child);
			remote_child = remote_child->m_next;
			prev_my_child = my_child;
			my_child = my_child->m_next;
		}
	}
}

void ProfileModel::onFrame()
{
	if(!m_root && Lumix::g_profiler.getRootBlock())
	{
		m_root = new Block;
		m_root->m_function = Lumix::g_profiler.getRootBlock()->m_function;
		m_root->m_name = Lumix::g_profiler.getRootBlock()->m_name;
		m_root->m_parent = NULL;
		m_root->m_next = NULL;
		m_root->m_first_child = NULL;

	}
	if(m_root)
	{
		cloneBlock(m_root, Lumix::g_profiler.getRootBlock());
	}
	static int hit = 0;
	++hit;
	int count = 0;
	Block* child = m_root->m_first_child;
	while(child)
	{
		++count;
		child = child->m_next;
	}
	if(hit % 10 == 0)
	{
		emit dataChanged(createIndex(0, 0, m_root), createIndex(count, 0, m_root));
	}
}

QVariant ProfileModel::headerData(int section, Qt::Orientation, int role) const
{
	if(role == Qt::DisplayRole)
	{
		switch(section)
		{
			case Values::FUNCTION:
				return "Function";
			case Values::NAME:
				return "Name";
			case Values::LENGTH:
				return "Length (ms)";
			default:
				ASSERT(false);
				return QVariant();
		}
	}
	return QVariant();
}

QModelIndex ProfileModel::index(int row, int column, const QModelIndex& parent) const
{
	if(!hasIndex(row, column, parent))
	{
		return QModelIndex();
	}
	Block* block = NULL;
	if(parent.internalPointer() != NULL)
	{
		block = static_cast<Block*>(parent.internalPointer());
	}
	else
	{
		return createIndex(0, column, m_root);
	}

	int index = row;
	Block* child = block->m_first_child;
	while(child && index > 0)
	{
		child = child->m_next;
		--index;
	}

	return createIndex(row, column, child);
}

QModelIndex ProfileModel::parent(const QModelIndex& index) const
{
	if (!index.isValid() || !index.internalPointer())
	{
		return QModelIndex();
	}

	Block* child = static_cast<Block*>(index.internalPointer());
	Block* parent = child->m_parent;

	if (parent == NULL)
	{
		return QModelIndex();
	}

	int row = 0;
	Block* row_sibling = parent->m_first_child;
	while(row_sibling && row_sibling != child)
	{
		row_sibling = row_sibling->m_next;
		++row;
	}
	ASSERT(row_sibling);
	return createIndex(row, 0, parent);
}

int ProfileModel::rowCount(const QModelIndex& parent_index) const
{
	Block* parent;
	if (parent_index.column() > 0 || Lumix::g_profiler.getRootBlock() == NULL)
		return 0;

	if (!parent_index.isValid() || !parent_index.internalPointer())
	{
		return 1;
	}
	else
	{
		parent = static_cast<Block*>(parent_index.internalPointer());
	}

	int count = 0;
	Block* child = parent->m_first_child;
	while(child)
	{
		++count;
		child = child->m_next;
	}
	return count;
}

int ProfileModel::columnCount(const QModelIndex&) const
{
	return (int)Values::COUNT;
}

QVariant ProfileModel::data(const QModelIndex& index, int role) const
{
	if (!index.isValid() || !index.internalPointer())
	{
		return QVariant();
	}

	if (role != Qt::DisplayRole)
	{
		return QVariant();
	}
	Block* block = static_cast<Block*>(index.internalPointer());
	switch(index.column())
	{
		case Values::FUNCTION:
			return block->m_function;
		case Values::NAME:
			return block->m_name;
		case Values::LENGTH:
			{
				return m_frame >= 0 && m_frame < block->m_frames.size() ? block->m_frames[m_frame] : 0;
			}
		default:
			ASSERT(false);
			return QVariant();
	}
}

ProfilerUI::ProfilerUI(QWidget* parent)
	: QDockWidget(parent)
	, m_ui(new Ui::ProfilerUI)
{
	m_model = new ProfileModel;
	m_ui->setupUi(this);
	m_ui->profileTreeView->setModel(m_model);
	m_ui->profileTreeView->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
	m_ui->profileTreeView->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
	m_ui->profileTreeView->header()->setSectionResizeMode(2, QHeaderView::ResizeMode::ResizeToContents);
	connect(m_model, &QAbstractItemModel::dataChanged, this, &ProfilerUI::on_dataChanged);
	connect(m_ui->graphView, &ProfilerGraph::frameSet, this, &ProfilerUI::on_frameSet);
	m_ui->graphView->setModel(m_model);
}

void ProfilerUI::on_dataChanged()
{
	m_ui->graphView->update();
}

ProfilerUI::~ProfilerUI()
{
	delete m_ui;
	delete m_model;
}

void ProfilerUI::on_recordCheckBox_stateChanged(int)
{
	Lumix::g_profiler.toggleRecording();
	m_ui->profileTreeView->setModel(NULL);
	m_ui->profileTreeView->setModel(m_model);
	m_ui->profileTreeView->update();
}

void ProfilerUI::on_frameSet()
{
	m_ui->recordCheckBox->setChecked(false);
	m_ui->profileTreeView->update();
	m_model->setFrame(m_ui->graphView->getFrame());
}

void ProfilerUI::on_profileTreeView_clicked(const QModelIndex &index)
{
	if(index.internalPointer() != NULL)
	{
		m_ui->graphView->setBlock(static_cast<ProfileModel::Block*>(index.internalPointer()));
		m_ui->graphView->update();
	}
}
<|endoftext|>


<commit_before>//
// Created by Umur Gedik on 5/4/16.
//

#include <sstream>
#include <vector>
#include <regex>
#include "EntryTypeParser.h"

string EntryTypeParser::Parse(const string &content)
{
    istringstream stream{content};
    vector<string> lines;

    string line;
    while (getline(stream, line)) {
        lines.emplace_back(line);
    }

    if (m_options.line_based) {
        if (m_options.line_number <= lines.size()) {
            return lines[m_options.line_number - 1];
        }
    }

    if (m_options.regex_based) {
        string regex_subject = content;
        smatch match;
        regex parser{m_options.regex};

        if (m_options.search_in_line && m_options.line_number <= lines.size()) {
            regex_subject = lines[m_options.line_number - 1];
        }

        if (regex_search(regex_subject, match, parser)) {
            return match[1];
        }
    }

    return "";
}<commit_msg>fix: if issue type is not found fallback to feature<commit_after>//
// Created by Umur Gedik on 5/4/16.
//

#include <sstream>
#include <vector>
#include <regex>
#include "EntryTypeParser.h"

string EntryTypeParser::Parse(const string &content)
{
    istringstream stream{content};
    vector<string> lines;

    string line;
    while (getline(stream, line)) {
        lines.emplace_back(line);
    }

    if (m_options.line_based) {
        if (m_options.line_number <= lines.size()) {
            return lines[m_options.line_number - 1];
        }
    }

    if (m_options.regex_based) {
        string regex_subject = content;
        smatch match;
        regex parser{m_options.regex};

        if (m_options.search_in_line && m_options.line_number <= lines.size()) {
            regex_subject = lines[m_options.line_number - 1];
        }

        if (regex_search(regex_subject, match, parser)) {
            return match[1];
        }
    }

    return "feature";
}<|endoftext|>


<commit_before>//
//  spot.cpp
//  emptyExample
//
//  Created by Mark van de Korput on 16-05-18.
//
//

#include "spot.hpp"

using namespace of2030::effects;

Spot::Spot(){
    setType(EffectType::SPOT);
}

// virtual void setup(Context &context);
void Spot::draw(Context &context){
    int spotNumber = context.effect_setting.getValue("number", (int)1);
    string prefix = "spot" + ofToString(spotNumber);

//    // screen must be spot-enabled
//    if(!(context.screen_setting.hasValue("spot"+ofToString(spotNumber)+"_x"))
//       return;

    ofVec2f resolution(context.fbo->getWidth(), context.fbo->getHeight());

    ofVec2f spotPos = context.screen_setting.getValue(prefix, ofVec2f(-10.0f)) * resolution;
    ofVec2f spotSize = context.screen_setting.getValue(prefix+"size", ofVec2f(0.0f)) * resolution;

    if(!shader){
        // draw without shader stuff
        ofSetColor(255);
        // ofDrawRectangle(0, 0, resolution.x, resolution.y);
        ofDrawEllipse(spotPos.x, spotPos.y, spotSize.x, spotSize.y);
        return;
    }

    shader->begin();

    //    shader->setUniform2f("iResolution", resolution);
    shader->setUniform2f("iSpotPos", spotPos);
    shader->setUniform2f("iSpotSize", spotSize);
    shader->setUniform1f("iGain", context.effect_setting.getValue("gain", 1.0f));

    // quarter; 1 means top right, 2 means bottom right, 3 bottom left, 4 means top left, zero means none
    int q = std::floor(context.effect_setting.getValue("quarter_on", 0.0f));
    shader->setUniform1i("iQuarterOn", q);
    q = std::floor(context.effect_setting.getValue("quarter_off", 0.0f));
    shader->setUniform1i("iQuarterOff", q);

    spotPos = spotPos - spotSize * 0.5;
    ofSetColor(255);
    ofDrawRectangle(0.0f, 0.0f, resolution.x, resolution.y); //spotPos.x, spotPos.y, spotSize.x, spotSize.y);

    shader->end();
}<commit_msg>spots positioning<commit_after>//
//  spot.cpp
//  emptyExample
//
//  Created by Mark van de Korput on 16-05-18.
//
//

#include "spot.hpp"

using namespace of2030::effects;

Spot::Spot(){
    setType(EffectType::SPOT);
}

// virtual void setup(Context &context);
void Spot::draw(Context &context){
    int spotNumber = context.effect_setting.getValue("number", (int)1);
    string prefix = "spot" + ofToString(spotNumber);

//    // screen must be spot-enabled
//    if(!(context.screen_setting.hasValue("spot"+ofToString(spotNumber)+"_x"))
//       return;

    ofVec2f resolution(context.fbo->getWidth(), context.fbo->getHeight());

    ofVec2f spotPos = context.screen_setting.getValue(prefix, ofVec2f(-10.0f)) * resolution;
    ofVec2f spotSize = context.screen_setting.getValue(prefix+"size", ofVec2f(0.0f)) * resolution;

    ofVec2f scrWorldSize(context.screen_setting.getValue("world_width", 2.67f),
                         -context.screen_setting.getValue("world_height", 2.0f));
    ofVec2f fxSpotPos = context.effect_setting.getValue("pos", ofVec2f(0.0f, 0.0f));

    // spot reposition according to effect setting
    spotPos += fxSpotPos * scrWorldSize * resolution * 0.01;

    if(!shader){
        // draw without shader stuff
        ofSetColor(255);
        // ofDrawRectangle(0, 0, resolution.x, resolution.y);
        ofDrawEllipse(spotPos.x, spotPos.y, spotSize.x, spotSize.y);
        return;
    }

    shader->begin();

    //    shader->setUniform2f("iResolution", resolution);
    shader->setUniform2f("iSpotPos", spotPos);
    shader->setUniform2f("iSpotSize", spotSize);
    shader->setUniform1f("iGain", context.effect_setting.getValue("gain", 1.0f));

    // quarter; 1 means top right, 2 means bottom right, 3 bottom left, 4 means top left, zero means none
    int q = std::floor(context.effect_setting.getValue("quarter_on", 0.0f));
    shader->setUniform1i("iQuarterOn", q);
    q = std::floor(context.effect_setting.getValue("quarter_off", 0.0f));
    shader->setUniform1i("iQuarterOff", q);

    spotPos = spotPos - spotSize * 0.5;
    ofSetColor(255);
    ofDrawRectangle(0.0f, 0.0f, resolution.x, resolution.y); //spotPos.x, spotPos.y, spotSize.x, spotSize.y);

    shader->end();
}<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		uint32_t	crcd_;
		uint32_t	crrd_;
		uint32_t	d2md_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint32_t	wdm_st_[4];
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), crcd_(0), crrd_(0), d2md_(0),
			wdm_ch_(0), wdm_pos_(0), wdm_st_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		uint32_t get_crcd() const { return crcd_; }

		uint32_t get_crrd() const { return crrd_; }

		uint32_t get_d2md() const { return d2md_; }

		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		uint32_t get_wdm_st(uint32_t ch) const { return wdm_st_[ch & 3]; }

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						crcd_ = v;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						crrd_ = v;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						d2md_ = v;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
// std::cout << "WDM capture END" << std::endl;
							++wdm_st_[wdm_ch_ & 3];
						}
						t = d;
					}
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
		}
	};
}
<commit_msg>update: recv satte manage<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

		//=================================================================//
		/*!
			@brief  モジュール・ステータス構造体
		*/
		//=================================================================//
		struct mod_status {
			uint32_t	crcd_;
			uint32_t	crcd_id_;

			uint32_t	crrd_;
			uint32_t	crrd_id_;

			uint32_t	d2md_;
			uint32_t	d2md_id_;

			mod_status() :
				crcd_(0), crcd_id_(0),
				crrd_(0), crrd_id_(0),
				d2md_(0), d2md_id_(0)
			{ }
		};

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		mod_status	mod_status_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint32_t	wdm_st_[4];
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), mod_status_(),
			wdm_ch_(0), wdm_pos_(0), wdm_st_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モジュール・ステータスの取得
			@return モジュール・ステータス
		*/
		//-----------------------------------------------------------------//
		const mod_status& get_mod_status() const { return mod_status_; }

		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		uint32_t get_wdm_st(uint32_t ch) const { return wdm_st_[ch & 3]; }

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crcd_ = v;
						++mod_status_.crcd_id_;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crrd_ = v;
						++mod_status_.crrd_id_;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.d2md_ = v;
						++mod_status_.d2md_id_;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
// std::cout << "WDM capture END" << std::endl;
							++wdm_st_[wdm_ch_ & 3];
						}
						t = d;
					}
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
		}
	};
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

// デバッグ・エミュレーションを行う場合有効にする
#define DEBUG_EMU

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

		//=================================================================//
		/*!
			@brief  モジュール・ステータス構造体
		*/
		//=================================================================//
		struct mod_status {
			uint32_t	crm_id_;

			uint32_t	crcd_;
			uint32_t	crcd_id_;

			uint32_t	crrd_;
			uint32_t	crrd_id_;

			uint32_t	d2md_;
			uint32_t	d2md_id_;

			uint32_t	wdm_id_[4];

			uint32_t	treg_id_[2];

			mod_status() :
				crm_id_(0),
				crcd_(0), crcd_id_(0),
				crrd_(0), crrd_id_(0),
				d2md_(0), d2md_id_(0),
				wdm_id_{ 0 }, treg_id_{ 0 }
			{ }
		};

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		mod_status	mod_status_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

		uint32_t	treg_ch_;
		uint32_t	treg_pos_;
		uint16_t	treg_buff_[WAVE_BUFF_SIZE * 2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), mod_status_(),
			wdm_ch_(0), wdm_pos_(0), wdm_buff_{ 0 },
			treg_ch_(0), treg_pos_(0), treg_buff_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モジュール・ステータスの取得
			@return モジュール・ステータス
		*/
		//-----------------------------------------------------------------//
		const mod_status& get_mod_status() const { return mod_status_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の取得
			@param[in]	ch	チャネル
			@return 波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  熱抵抗波形の取得
			@param[in]	ch	チャネル（前半:0、後半:1）
			@return 熱抵抗波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_treg(uint32_t ch) const {
			return &treg_buff_[WAVE_BUFF_SIZE * (ch & 1)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
#ifdef DEBUG_EMU
			connect_ = true;
			return true;
#endif
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
#ifdef DEBUG_EMU

#else
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crcd_ = v;
						++mod_status_.crcd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crrd_ = v;
						++mod_status_.crrd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.d2md_ = v;
						++mod_status_.d2md_id_;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.wdm_id_[wdm_ch_ & 3];
						}
						t = d;
					}
				} else if(s.find("TRCH") == 0) {  // 熱抵抗チャネル (0, 1)
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					treg_ch_ = v;
					treg_pos_ = 0;
// std::cout << "TRCH: " << treg_ch_ << std::endl;
				} else if(s.find("TRMW") == 0) {  // 熱抵抗波形 (0, 1)
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = treg_pos_ % WAVE_BUFF_SIZE;
						treg_buff_[(treg_ch_ & 1) * WAVE_BUFF_SIZE + pos] = v;
						++treg_pos_;
						if(treg_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.treg_id_[treg_ch_ & 3];
// std::cout << "TRMW: " << treg_ch_ << std::endl;
						}
						t = d;
					}
				}
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
#ifdef DEBUG_EMU
			if(text.find("CRR?1") != std::string::npos) {
				double a = 50.0;
				a *= 2.0;
				a /= 778.2;
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crrd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crrd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("CRC?1") != std::string::npos) {
				double a = 0.33;
				a /= 1e6;
				a = 1.0 / (2.0 * 3.141592654 * 1000.0 * a);
				a *= 2.0;
				a /= 778.2 * 2.0;  // 778.2 mV P-P
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crcd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crcd_id_;
				++mod_status_.crm_id_;
			}
			std::cout << text << std::endl;
			return;
#else
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
#endif
		}
	};
}
<commit_msg>update: debug emulation mode<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

// デバッグ・エミュレーションを行う場合有効にする
#define DEBUG_EMU

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

		//=================================================================//
		/*!
			@brief  モジュール・ステータス構造体
		*/
		//=================================================================//
		struct mod_status {
			uint32_t	crm_id_;

			uint32_t	crcd_;
			uint32_t	crcd_id_;

			uint32_t	crrd_;
			uint32_t	crrd_id_;

			uint32_t	d2md_;
			uint32_t	d2md_id_;

			uint32_t	wdm_id_[4];

			uint32_t	treg_id_[2];

			mod_status() :
				crm_id_(0),
				crcd_(0), crcd_id_(0),
				crrd_(0), crrd_id_(0),
				d2md_(0), d2md_id_(0),
				wdm_id_{ 0 }, treg_id_{ 0 }
			{ }
		};

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		mod_status	mod_status_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

		uint32_t	treg_ch_;
		uint32_t	treg_pos_;
		uint16_t	treg_buff_[WAVE_BUFF_SIZE * 2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), mod_status_(),
			wdm_ch_(0), wdm_pos_(0), wdm_buff_{ 0 },
			treg_ch_(0), treg_pos_(0), treg_buff_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モジュール・ステータスの取得
			@return モジュール・ステータス
		*/
		//-----------------------------------------------------------------//
		const mod_status& get_mod_status() const { return mod_status_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の取得
			@param[in]	ch	チャネル
			@return 波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  熱抵抗波形の取得
			@param[in]	ch	チャネル（前半:0、後半:1）
			@return 熱抵抗波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_treg(uint32_t ch) const {
			return &treg_buff_[WAVE_BUFF_SIZE * (ch & 1)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
#ifdef DEBUG_EMU
			connect_ = true;
			return true;
#endif
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
#ifdef DEBUG_EMU

#else
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crcd_ = v;
						++mod_status_.crcd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crrd_ = v;
						++mod_status_.crrd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.d2md_ = v;
						++mod_status_.d2md_id_;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.wdm_id_[wdm_ch_ & 3];
						}
						t = d;
					}
				} else if(s.find("TRCH") == 0) {  // 熱抵抗チャネル (0, 1)
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					treg_ch_ = v;
					treg_pos_ = 0;
// std::cout << "TRCH: " << treg_ch_ << std::endl;
				} else if(s.find("TRMW") == 0) {  // 熱抵抗波形 (0, 1)
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = treg_pos_ % WAVE_BUFF_SIZE;
						treg_buff_[(treg_ch_ & 1) * WAVE_BUFF_SIZE + pos] = v;
						++treg_pos_;
						if(treg_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.treg_id_[treg_ch_ & 3];
// std::cout << "TRMW: " << treg_ch_ << std::endl;
						}
						t = d;
					}
				}
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
#ifdef DEBUG_EMU
			if(text.find("CRR?1") != std::string::npos) {
				double a = 50.0;
				a *= 2.0;
				a /= 778.2;
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crrd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crrd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("CRC?1") != std::string::npos) {
				double a = 0.33;
				a /= 1e6;
				a = 1.0 / (2.0 * 3.141592654 * 1000.0 * a);
				a *= 2.0;
				a /= 778.2 * 2.0;  // 778.2 mV P-P
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crcd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crcd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("wdm 20") != std::string::npos) {
				++mod_status_.wdm_id_[2];
			}
			std::cout << text << std::endl;
			return;
#else
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
#endif
		}
	};
}
<|endoftext|>


<commit_before>#include "algorithm-median.hpp"

namespace fmo {
    void MedianV1::selectObjects() {
        for (auto& o0 : mObjects[0]) {
            if (o0.prev == Special::END) {
                // no matched object in the previous frame
                continue;
            }
            auto& o1 = mObjects[1][o0.prev];
            if (o1.prev == Special::END) {
                // no matched object in the frame before the previous frame
                continue;
            }
            auto& o2 = mObjects[2][o1.prev];

            // ignore the triplet if it is not deemed a fast-moving object detection
            if (!selectable(o0, o1, o2)) continue;

            // everything is fine: mark objects as selected
            o0.selected = true;
            o1.selected = true;
            o2.selected = true;
        }
    }

    bool MedianV1::selectable(Object& o0, Object& o1, Object& o2) const {
        auto med3 = [] (float a, float b, float c) {
            if (a > b) std::swap(a, b);
            b = std::min(b, c);
            return std::max(a, b);
        };

        Vector motion = o1.center - o0.center;
        Pos expected = {o1.center.x + motion.x, o1.center.y + motion.y};
        Vector error = expected - o2.center;
        float distance = length(error) / (2.f * med3(o0.halfLen[0], o1.halfLen[0], o2.halfLen[0]));
        if (distance > mCfg.selectMaxDistance) return false;
        return true;
    }
}
<commit_msg>Make linear motion error calc more elegant<commit_after>#include "algorithm-median.hpp"

namespace fmo {
    void MedianV1::selectObjects() {
        for (auto& o0 : mObjects[0]) {
            if (o0.prev == Special::END) {
                // no matched object in the previous frame
                continue;
            }
            auto& o1 = mObjects[1][o0.prev];
            if (o1.prev == Special::END) {
                // no matched object in the frame before the previous frame
                continue;
            }
            auto& o2 = mObjects[2][o1.prev];

            // ignore the triplet if it is not deemed a fast-moving object detection
            if (!selectable(o0, o1, o2)) continue;

            // everything is fine: mark objects as selected
            o0.selected = true;
            o1.selected = true;
            o2.selected = true;
        }
    }

    bool MedianV1::selectable(Object& o0, Object& o1, Object& o2) const {
        auto med3 = [](float a, float b, float c) {
            if (a > b) std::swap(a, b);
            b = std::min(b, c);
            return std::max(a, b);
        };

        Vector error{o0.center.x - 2 * o1.center.x + o2.center.x,
                     o0.center.y - 2 * o1.center.y + o2.center.y};
        float distance = length(error) / (2.f * med3(o0.halfLen[0], o1.halfLen[0], o2.halfLen[0]));
        if (distance > mCfg.selectMaxDistance) return false;
        return true;
    }
}
<|endoftext|>


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

#include <Kernel.hpp>
using isa::OpenCL::Kernel;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <utils.hpp>
using isa::utils::giga;
using isa::utils::toStringValue;

#ifndef FLOPS_HPP
#define FLOPS_HPP

namespace isa {

namespace Benchmarks {

template < typename T > class Flops : public Kernel< T > {
public:
	Flops(string dataType);

	void generateCode() throw (OpenCLError);
	void operator()(CLData< T > * a, CLData< T > * c) throw (OpenCLError);

	inline void setNrThreadsPerBlock(unsigned int threads);
	inline void setNrThreads(unsigned int threads);
	inline void setNrRows(unsigned int rows);
	inline void setNrIterations(unsigned int iterations);

private:
	unsigned int nrThreadsPerBlock;
	unsigned int nrThreads;
	unsigned int nrRows;
	unsigned int nrIterations;
};

// Implementation

template< typename T > Flops< T >::Flops(string dataType) : Kernel< T >("Flops", dataType), nrThreadsPerBlock(0), nrThreads(0), nrRows(0), nrIterations(0) {}

template< typename T > void Flops< T >::generateCode() throw (OpenCLError) {
	long long unsigned int ops = static_cast< long long unsigned int >(nrThreads * nrIterations * 2);
	long long unsigned int memOps = nrThreads * 2 * sizeof(T);

	this->arInt = ops / static_cast< double >(memOps);
	this->gflop = giga(ops);
	this->gb = giga(memOps);

	delete this->code;
	this->code = new string();
	*(this->code) = "__kernel void " + this->name + "(__global const " + this->dataType + " * const restrict A, __global " + this->dataType + " * const restrict C) {\n"
		"const unsigned int id = ( get_global_id(1) * get_global_size(0) ) + get_global_id(0);\n"
		+ this->dataType + " a = A[id];\n"
		+ this->dataType + " total = 0;\n"
		"for ( unsigned int iteration = 0; iteration < " + toStringValue< unsigned int >(nrIterations) + "; iteration++ ) {\n"
		"total += (a * get_local_id(0);\n"
		"}\n"
		"C[id] = total;\n"
		"}";

	this->compile();
}

template< typename T > void Flops< T >::operator()(CLData< T > * a, CLData< T > * c) throw (OpenCLError) {
	cl::NDRange globalSize(nrThreads / nrRows, nrRows);
	cl::NDRange localSize(nrThreadsPerBlock, 1);

	this->setArgument(0, *(a->getDeviceData()));
	this->setArgument(1, *(c->getDeviceData()));

	this->run(globalSize, localSize);
}

template< typename T > inline void Flops< T >::setNrThreadsPerBlock(unsigned int threads) {
	nrThreadsPerBlock = threads;
}

template< typename T > inline void Flops< T >::setNrThreads(unsigned int threads) {
	nrThreads = threads;
}

template< typename T > inline void Flops< T >::setNrRows(unsigned int rows) {
	nrRows = rows;
}

template< typename T > inline void Flops< T >::setNrIterations(unsigned int iteration) {
	nrIterations = iteration;
}

} // Benchmarks
} // isa

#endif // FLOPS_HPP
<commit_msg>Missing (.<commit_after>//
// Copyright (C) 2014
// Alessio Sclocco <a.sclocco@vu.nl>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <Kernel.hpp>
using isa::OpenCL::Kernel;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <utils.hpp>
using isa::utils::giga;
using isa::utils::toStringValue;

#ifndef FLOPS_HPP
#define FLOPS_HPP

namespace isa {

namespace Benchmarks {

template < typename T > class Flops : public Kernel< T > {
public:
	Flops(string dataType);

	void generateCode() throw (OpenCLError);
	void operator()(CLData< T > * a, CLData< T > * c) throw (OpenCLError);

	inline void setNrThreadsPerBlock(unsigned int threads);
	inline void setNrThreads(unsigned int threads);
	inline void setNrRows(unsigned int rows);
	inline void setNrIterations(unsigned int iterations);

private:
	unsigned int nrThreadsPerBlock;
	unsigned int nrThreads;
	unsigned int nrRows;
	unsigned int nrIterations;
};

// Implementation

template< typename T > Flops< T >::Flops(string dataType) : Kernel< T >("Flops", dataType), nrThreadsPerBlock(0), nrThreads(0), nrRows(0), nrIterations(0) {}

template< typename T > void Flops< T >::generateCode() throw (OpenCLError) {
	long long unsigned int ops = static_cast< long long unsigned int >(nrThreads * nrIterations * 2);
	long long unsigned int memOps = nrThreads * 2 * sizeof(T);

	this->arInt = ops / static_cast< double >(memOps);
	this->gflop = giga(ops);
	this->gb = giga(memOps);

	delete this->code;
	this->code = new string();
	*(this->code) = "__kernel void " + this->name + "(__global const " + this->dataType + " * const restrict A, __global " + this->dataType + " * const restrict C) {\n"
		"const unsigned int id = (get_global_id(1) * get_global_size(0)) + get_global_id(0);\n"
		+ this->dataType + " a = A[id];\n"
		+ this->dataType + " total = 0;\n"
		"for ( unsigned int iteration = 0; iteration < " + toStringValue< unsigned int >(nrIterations) + "; iteration++ ) {\n"
		"total += (a * get_local_id(0));\n"
		"}\n"
		"C[id] = total;\n"
		"}";

	this->compile();
}

template< typename T > void Flops< T >::operator()(CLData< T > * a, CLData< T > * c) throw (OpenCLError) {
	cl::NDRange globalSize(nrThreads / nrRows, nrRows);
	cl::NDRange localSize(nrThreadsPerBlock, 1);

	this->setArgument(0, *(a->getDeviceData()));
	this->setArgument(1, *(c->getDeviceData()));

	this->run(globalSize, localSize);
}

template< typename T > inline void Flops< T >::setNrThreadsPerBlock(unsigned int threads) {
	nrThreadsPerBlock = threads;
}

template< typename T > inline void Flops< T >::setNrThreads(unsigned int threads) {
	nrThreads = threads;
}

template< typename T > inline void Flops< T >::setNrRows(unsigned int rows) {
	nrRows = rows;
}

template< typename T > inline void Flops< T >::setNrIterations(unsigned int iteration) {
	nrIterations = iteration;
}

} // Benchmarks
} // isa

#endif // FLOPS_HPP
<|endoftext|>