<commit_before>#pragma once
#include "augs/templates/snapshotted_player.h"

namespace augs {
	template <class A, class B>
	auto snapshotted_player<A, B>::get_current_step() const {
		return current_step;
	}

	template <class A, class B>
	auto snapshotted_player<A, B>::get_total_steps() const {
		if (step_to_entropy.size() > 0) {
			return std::max(current_step, (*step_to_entropy.rbegin()).first);
		}

		return current_step;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_replaying() {
		advance_mode = advance_type::REPLAYING;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_recording() {
		advance_mode = advance_type::RECORDING;
	}

	template <class A, class B>
	const fixed_delta_timer& snapshotted_player<A, B>::get_timer() const {
		return timer;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::finish() {
		step_to_entropy.clear();
		current_step = 0;

		pause();
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::pause() {
		advance_mode = advance_type::PAUSED;
	}

	template <class A, class B>
   	bool snapshotted_player<A, B>::is_paused() const {
		return advance_mode == advance_type::PAUSED;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::request_steps(const int amount) {
		additional_steps += amount;
	}

	template <class A, class B>
	double snapshotted_player<A, B>::get_speed() const {
		return is_paused() ? 0.0 : speed;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::set_speed(const double new_speed) {
		speed = new_speed;
	}

	template <class A, class B>
	template <class I, class SetSnapshot>
	void snapshotted_player<A, B>::seek_to(
		typename snapshotted_player<A, B>::step_type seeked_step,
		const I& input,
		SetSnapshot&& set_snapshot
	) {
		const auto previous_snapshot_index = std::min(
			static_cast<unsigned>(snapshots.size() - 1),
			seeked_step / snapshot_frequency_in_steps
		);

		auto set_ith = [&](const auto i) {
			set_snapshot(i, snapshots.at(i));
			current_step = i * snapshot_frequency_in_steps;
		};

		if (seeked_step < current_step) {
			set_ith(previous_snapshot_index);
		}

		/* at this point the seeked_step is either equal or greater than the current */

		const auto distance_from_previous_snapshot = seeked_step - previous_snapshot_index * snapshot_frequency_in_steps;
		const auto distance_from_current = seeked_step - current_step;

		if (distance_from_previous_snapshot < distance_from_current) {
			set_ith(previous_snapshot_index);
		}

		while (current_step < seeked_step) {
			advance_single_step(input);
		}
	}

	template <class A, class B>
	template <class MakeSnapshot>
	void snapshotted_player<A, B>::push_snapshot_if_needed(MakeSnapshot&& make_snapshot) {
		if (current_step != 0 && current_step % snapshot_frequency_in_steps == 0) {
			const auto snapshot_index = current_step / snapshot_frequency_in_steps;

			const bool valid_snapshot_exists = snapshot_index < snapshots.size();

			if (!valid_snapshot_exists) {
				snapshots.emplace_back(make_snapshot(snapshot_index));
			}
		}
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance_single_step(const I& in) {
		auto& step_i = current_step;
		auto& applied_entropy = in.total_collected;

		push_snapshot_if_needed(in.make_snapshot);

		{
			const auto next_snapshot_index = 1 + step_i / snapshot_frequency_in_steps;
			const bool outdated_snapshots_to_delete_exist = next_snapshot_index < snapshots.size();

			if (outdated_snapshots_to_delete_exist) {
				snapshots.erase(
					snapshots.begin() + next_snapshot_index,
					snapshots.end()
				);
			}
		}

		switch (advance_mode) {
			case advance_type::REPLAYING:
				if (const auto found_entropy = mapped_or_nullptr(step_to_entropy, step_i)) {
					applied_entropy = *found_entropy;
				}

			case advance_type::RECORDING:
				if (!applied_entropy.empty()) {
					step_to_entropy[step_i] = applied_entropy;
				}

			default: break;
		}

		in.step(applied_entropy);
		applied_entropy.clear();
		++step_i;
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance(
		const I& in,
		delta frame_delta,
		const delta& fixed_delta
	) {
		auto steps = additional_steps;

		if (!is_paused()) {
			timer.advance(frame_delta *= speed);
			steps += timer.extract_num_of_logic_steps(fixed_delta);
		}

		while (steps--) {
			advance_single_step(in);
		}

		additional_steps = 0;
	}

}
<commit_msg>Refactored snapshot logic and fixed a bug<commit_after>#pragma once
#include "augs/templates/snapshotted_player.h"

namespace augs {
	template <class A, class B>
	auto snapshotted_player<A, B>::get_current_step() const {
		return current_step;
	}

	template <class A, class B>
	auto snapshotted_player<A, B>::get_total_steps() const {
		if (step_to_entropy.size() > 0) {
			return std::max(current_step, (*step_to_entropy.rbegin()).first);
		}

		return current_step;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_replaying() {
		advance_mode = advance_type::REPLAYING;
	}

	template <class A, class B>
	void snapshotted_player<A, B>::begin_recording() {
		advance_mode = advance_type::RECORDING;
	}

	template <class A, class B>
	const fixed_delta_timer& snapshotted_player<A, B>::get_timer() const {
		return timer;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::finish() {
		step_to_entropy.clear();
		current_step = 0;

		pause();
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::pause() {
		advance_mode = advance_type::PAUSED;
	}

	template <class A, class B>
   	bool snapshotted_player<A, B>::is_paused() const {
		return advance_mode == advance_type::PAUSED;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::request_steps(const int amount) {
		additional_steps += amount;
	}

	template <class A, class B>
	double snapshotted_player<A, B>::get_speed() const {
		return is_paused() ? 0.0 : speed;
	}

	template <class A, class B>
   	void snapshotted_player<A, B>::set_speed(const double new_speed) {
		speed = new_speed;
	}

	template <class A, class B>
	template <class I, class SetSnapshot>
	void snapshotted_player<A, B>::seek_to(
		typename snapshotted_player<A, B>::step_type seeked_step,
		const I& input,
		SetSnapshot&& set_snapshot
	) {
		auto set = [&](const auto i) {
			set_snapshot(i, snapshots.at(i));
			current_step = i * snapshot_frequency_in_steps;
		};

		const auto seeked_adj_snapshot = std::min(
			static_cast<unsigned>(snapshots.size() - 1),
			seeked_step / snapshot_frequency_in_steps
		);

		if (seeked_step < current_step) {
			set(seeked_adj_snapshot);
		}

		/* At this point the current step is <= than the target step. */

		{
			/* Maybe we can speed up the forward seek by setting some future snapshot. */

			const auto step_of_adj_snapshot = seeked_adj_snapshot * snapshot_frequency_in_steps;

			const auto distance_from_adj_snapshot = seeked_step - step_of_adj_snapshot;
			const auto distance_from_seeked_step = seeked_step - current_step;

			if (distance_from_adj_snapshot < distance_from_seeked_step) {
				set(seeked_adj_snapshot);
			}
		}

		/* Advance how much is needed from the time of the set snapshot. */

		while (current_step < seeked_step) {
			advance_single_step(input);
		}
	}

	template <class A, class B>
	template <class MakeSnapshot>
	void snapshotted_player<A, B>::push_snapshot_if_needed(MakeSnapshot&& make_snapshot) {
		if (current_step % snapshot_frequency_in_steps == 0) {
			const auto snapshot_index = current_step / snapshot_frequency_in_steps;

			const bool valid_snapshot_exists = snapshot_index < snapshots.size();

			if (!valid_snapshot_exists) {
				snapshots.emplace_back(make_snapshot(snapshot_index));
			}
		}
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance_single_step(const I& in) {
		auto& step_i = current_step;
		auto& applied_entropy = in.total_collected;

		push_snapshot_if_needed(in.make_snapshot);

		{
			const auto next_snapshot_index = 1 + step_i / snapshot_frequency_in_steps;
			const bool outdated_snapshots_to_delete_exist = next_snapshot_index < snapshots.size();

			if (outdated_snapshots_to_delete_exist) {
				snapshots.erase(
					snapshots.begin() + next_snapshot_index,
					snapshots.end()
				);
			}
		}

		switch (advance_mode) {
			case advance_type::REPLAYING:
				if (const auto found_entropy = mapped_or_nullptr(step_to_entropy, step_i)) {
					applied_entropy = *found_entropy;
				}

			case advance_type::RECORDING:
				if (!applied_entropy.empty()) {
					step_to_entropy[step_i] = applied_entropy;
				}

			default: break;
		}

		in.step(applied_entropy);
		applied_entropy.clear();
		++step_i;
	}

	template <class entropy_type, class B>
	template <class I>
	void snapshotted_player<entropy_type, B>::advance(
		const I& in,
		delta frame_delta,
		const delta& fixed_delta
	) {
		auto steps = additional_steps;

		if (!is_paused()) {
			timer.advance(frame_delta *= speed);
			steps += timer.extract_num_of_logic_steps(fixed_delta);
		}

		while (steps--) {
			advance_single_step(in);
		}

		additional_steps = 0;
	}

}
<|endoftext|>


<commit_before>// Copyright 2013 Yangqing Jia

#include <cstring>
#include <cuda_runtime.h>

#include "gtest/gtest.h"
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class ConvolutionLayerTest : public ::testing::Test {
 protected:
  ConvolutionLayerTest()
      : blob_bottom_(new Blob<Dtype>()),
        blob_top_(new Blob<Dtype>()) {};
  virtual void SetUp() {
    blob_bottom_->Reshape(2, 3, 6, 5);
    // fill the values
    FillerParameter filler_param;
    filler_param.set_value(1.);
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  };

  virtual ~ConvolutionLayerTest() { delete blob_bottom_; delete blob_top_; }
  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(ConvolutionLayerTest, Dtypes);

TYPED_TEST(ConvolutionLayerTest, TestSetup) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(4);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), 2);
  EXPECT_EQ(this->blob_top_->channels(), 4);
  EXPECT_EQ(this->blob_top_->height(), 2);
  EXPECT_EQ(this->blob_top_->width(), 2);
  // setting group should not change the shape
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  layer.reset(new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), 2);
  EXPECT_EQ(this->blob_top_->channels(), 3);
  EXPECT_EQ(this->blob_top_->height(), 2);
  EXPECT_EQ(this->blob_top_->width(), 2);
}

TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolution) {
  // We will simply see if the convolution layer carries out averaging well.
  FillerParameter filler_param;
  filler_param.set_value(1.);
  ConstantFiller<TypeParam> filler(filler_param);
  filler.Fill(this->blob_bottom_);
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(4);
  layer_param.mutable_weight_filler()->set_type("constant");
  layer_param.mutable_weight_filler()->set_value(1);
  layer_param.mutable_bias_filler()->set_type("constant");
  layer_param.mutable_bias_filler()->set_value(0.1);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  Caffe::set_mode(Caffe::CPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 27.1
  const TypeParam* top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 27.1 - 1e-4);
    EXPECT_LE(top_data[i], 27.1 + 1e-4);
  }
  // Test GPU
  Caffe::set_mode(Caffe::GPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 27.1
  top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 27.1 - 1e-4);
    EXPECT_LE(top_data[i], 27.1 + 1e-4);
  }
}

TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolutionGroup) {
  // We will simply see if the convolution layer carries out averaging well.
  FillerParameter filler_param;
  filler_param.set_value(1.);
  ConstantFiller<TypeParam> filler(filler_param);
  filler.Fill(this->blob_bottom_);
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  layer_param.mutable_weight_filler()->set_type("constant");
  layer_param.mutable_weight_filler()->set_value(1);
  layer_param.mutable_bias_filler()->set_type("constant");
  layer_param.mutable_bias_filler()->set_value(0.1);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  Caffe::set_mode(Caffe::CPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 9.1
  const TypeParam* top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 9.1 - 1e-4);
    EXPECT_LE(top_data[i], 9.1 + 1e-4);
  }
  // Test GPU
  Caffe::set_mode(Caffe::GPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 9.1
  top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 9.1 - 1e-4);
    EXPECT_LE(top_data[i], 9.1 + 1e-4);
  }
}

TYPED_TEST(ConvolutionLayerTest, TestCPUGradient) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(2);
  Caffe::set_mode(Caffe::CPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

TYPED_TEST(ConvolutionLayerTest, TestGPUGradient) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(2);
  Caffe::set_mode(Caffe::GPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

}
<commit_msg>caffe test convolution<commit_after>// Copyright 2013 Yangqing Jia

#include <cstring>
#include <cuda_runtime.h>

#include "gtest/gtest.h"
#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class ConvolutionLayerTest : public ::testing::Test {
 protected:
  ConvolutionLayerTest()
      : blob_bottom_(new Blob<Dtype>()),
        blob_top_(new Blob<Dtype>()) {};
  virtual void SetUp() {
    blob_bottom_->Reshape(2, 3, 6, 5);
    // fill the values
    FillerParameter filler_param;
    filler_param.set_value(1.);
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  };

  virtual ~ConvolutionLayerTest() { delete blob_bottom_; delete blob_top_; }
  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(ConvolutionLayerTest, Dtypes);

TYPED_TEST(ConvolutionLayerTest, TestSetup) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(4);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), 2);
  EXPECT_EQ(this->blob_top_->channels(), 4);
  EXPECT_EQ(this->blob_top_->height(), 2);
  EXPECT_EQ(this->blob_top_->width(), 2);
  // setting group should not change the shape
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  layer.reset(new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  EXPECT_EQ(this->blob_top_->num(), 2);
  EXPECT_EQ(this->blob_top_->channels(), 3);
  EXPECT_EQ(this->blob_top_->height(), 2);
  EXPECT_EQ(this->blob_top_->width(), 2);
}

TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolution) {
  // We will simply see if the convolution layer carries out averaging well.
  FillerParameter filler_param;
  filler_param.set_value(1.);
  ConstantFiller<TypeParam> filler(filler_param);
  filler.Fill(this->blob_bottom_);
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(4);
  layer_param.mutable_weight_filler()->set_type("constant");
  layer_param.mutable_weight_filler()->set_value(1);
  layer_param.mutable_bias_filler()->set_type("constant");
  layer_param.mutable_bias_filler()->set_value(0.1);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  Caffe::set_mode(Caffe::CPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 27.1
  const TypeParam* top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 27.1 - 1e-4);
    EXPECT_LE(top_data[i], 27.1 + 1e-4);
  }
  // Test GPU
  Caffe::set_mode(Caffe::GPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 27.1
  top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 27.1 - 1e-4);
    EXPECT_LE(top_data[i], 27.1 + 1e-4);
  }
}

TYPED_TEST(ConvolutionLayerTest, TestSimpleConvolutionGroup) {
  // We will simply see if the convolution layer carries out averaging well.
  FillerParameter filler_param;
  filler_param.set_value(1.);
  ConstantFiller<TypeParam> filler(filler_param);
  filler.Fill(this->blob_bottom_);
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  layer_param.mutable_weight_filler()->set_type("constant");
  layer_param.mutable_weight_filler()->set_value(1);
  layer_param.mutable_bias_filler()->set_type("constant");
  layer_param.mutable_bias_filler()->set_value(0.1);
  shared_ptr<Layer<TypeParam> > layer(
      new ConvolutionLayer<TypeParam>(layer_param));
  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
  Caffe::set_mode(Caffe::CPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 9.1
  const TypeParam* top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 9.1 - 1e-4);
    EXPECT_LE(top_data[i], 9.1 + 1e-4);
  }
  // Test GPU
  Caffe::set_mode(Caffe::GPU);
  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
  // After the convolution, the output should all have output values 9.1
  top_data = this->blob_top_->cpu_data();
  for (int i = 0; i < this->blob_top_->count(); ++i) {
    EXPECT_GE(top_data[i], 9.1 - 1e-4);
    EXPECT_LE(top_data[i], 9.1 + 1e-4);
  }
}

TYPED_TEST(ConvolutionLayerTest, TestCPUGradient) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(2);
  Caffe::set_mode(Caffe::CPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

TYPED_TEST(ConvolutionLayerTest, TestCPUGradientGroup) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  Caffe::set_mode(Caffe::CPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

TYPED_TEST(ConvolutionLayerTest, TestGPUGradient) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(2);
  Caffe::set_mode(Caffe::GPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

TYPED_TEST(ConvolutionLayerTest, TestGPUGradientGroup) {
  LayerParameter layer_param;
  layer_param.set_kernelsize(3);
  layer_param.set_stride(2);
  layer_param.set_num_output(3);
  layer_param.set_group(3);
  Caffe::set_mode(Caffe::GPU);
  ConvolutionLayer<TypeParam> layer(layer_param);
  GradientChecker<TypeParam> checker(1e-2, 1e-2);
  checker.CheckGradientExhaustive(layer, this->blob_bottom_vec_, this->blob_top_vec_);
}

}
<|endoftext|>


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

/**
 * @file ChirpGenerator.cpp
 *
 * Generates a linear chirp.
 *
 * @package Aquila
 * @version 3.1.0-dev
 * @author Robert C. Taylor
 * @date 2016
 * @license  http://www.apache.org/licenses/LICENSE-2.0
 * @since 3.1.0
 */

#include "ChirpGenerator.h"

namespace Aquila {

ChirpGenerator::ChirpGenerator(FrequencyType sampleFrequency) : Generator(sampleFrequency) {
}

ChirpGenerator::ChirpGenerator(FrequencyType sampleFrequency,
		FrequencyType startFrequency, FrequencyType stopFrequency) : Generator(sampleFrequency), m_startFrequency(startFrequency), m_stopFrequency(stopFrequency){
}

ChirpGenerator& ChirpGenerator::setStartFrequency(
		FrequencyType startFrequency) {
	m_startFrequency = startFrequency;
	return *(this);
}

ChirpGenerator& ChirpGenerator::setStopFrequency(FrequencyType stopFrequency) {
	return *(this);
	m_stopFrequency = stopFrequency;
}

void ChirpGenerator::generate(std::size_t samplesCount) {
	//TODO: Create generator function
}

} /* namespace Aquila */
<commit_msg>Fix badly placed return statement.<commit_after>/*
 *   Copyright 2016 Robert C. Taylor
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @file ChirpGenerator.cpp
 *
 * Generates a linear chirp.
 *
 * @package Aquila
 * @version 3.1.0-dev
 * @author Robert C. Taylor
 * @date 2016
 * @license  http://www.apache.org/licenses/LICENSE-2.0
 * @since 3.1.0
 */

#include "ChirpGenerator.h"

namespace Aquila {

ChirpGenerator::ChirpGenerator(FrequencyType sampleFrequency) : Generator(sampleFrequency) {
}

ChirpGenerator::ChirpGenerator(FrequencyType sampleFrequency,
		FrequencyType startFrequency, FrequencyType stopFrequency) : Generator(sampleFrequency), m_startFrequency(startFrequency), m_stopFrequency(stopFrequency){
}

ChirpGenerator& ChirpGenerator::setStartFrequency(
		FrequencyType startFrequency) {
	m_startFrequency = startFrequency;
	return *(this);
}

ChirpGenerator& ChirpGenerator::setStopFrequency(FrequencyType stopFrequency) {
	m_stopFrequency = stopFrequency;
	return *(this);
}

void ChirpGenerator::generate(std::size_t samplesCount) {
	//TODO: Create generator function
}

} /* namespace Aquila */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mediaplayer.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 19:38:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "mediaplayer.hxx"
#include "mediawindow.hxx"
#include "mediaitem.hxx"
#include "mediamisc.hxx"
#include "mediacontrol.hrc"
#include "helpids.hrc"

#include <svtools/stritem.hxx>
#include <sfx2/app.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>

namespace avmedia
{

// ---------------
// - MediaPlayer -
// ---------------

MediaPlayer::MediaPlayer( Window* pParent, USHORT nId, SfxBindings* pBindings, SfxChildWinInfo* pInfo ) :
    SfxChildWindow( pParent, nId )
{
    pWindow = new MediaFloater( pBindings, this, pParent );
    eChildAlignment = SFX_ALIGN_NOALIGNMENT;
    static_cast< MediaFloater* >( pWindow )->Initialize( pInfo );
};

// -----------------------------------------------------------------------------

MediaPlayer::~MediaPlayer()
{
}

// -----------------------------------------------------------------------------

SFX_IMPL_DOCKINGWINDOW( MediaPlayer, SID_AVMEDIA_PLAYER )

// ----------------
// - MediaFloater -
// ----------------

MediaFloater::MediaFloater( SfxBindings* pBindings, SfxChildWindow* pCW, Window* pParent ) :
    SfxDockingWindow( pBindings, pCW, pParent, WB_CLOSEABLE | WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE ),
    mpMediaWindow( new MediaWindow( this, true ) )
{
    const Size aSize( 378, 256 );

    SetPosSizePixel( Point( 0, 0 ), aSize );
    SetMinOutputSizePixel( aSize );
    SetText( String( AVMEDIA_RESID( AVMEDIA_STR_MEDIAPLAYER ) ) );
    implInit();
    mpMediaWindow->show();
}

// -----------------------------------------------------------------------------

MediaFloater::~MediaFloater()
{
    delete mpMediaWindow;
    mpMediaWindow = NULL;
}

// -----------------------------------------------------------------------------

void MediaFloater::implInit()
{
}

// -------------------------------------------------------------------------

void MediaFloater::Resize()
{
    SfxDockingWindow::Resize();

    if( mpMediaWindow )
        mpMediaWindow->setPosSize( Rectangle( Point(), GetOutputSizePixel() ) );
}

// -----------------------------------------------------------------------------

void MediaFloater::ToggleFloatingMode()
{
    ::avmedia::MediaItem aRestoreItem;

    mpMediaWindow->updateMediaItem( aRestoreItem );
    delete mpMediaWindow;
    mpMediaWindow = NULL;

    SfxDockingWindow::ToggleFloatingMode();

    mpMediaWindow = new MediaWindow( this, true );

    mpMediaWindow->setPosSize( Rectangle( Point(), GetOutputSizePixel() ) );
    mpMediaWindow->executeMediaItem( aRestoreItem );

    Window* pWindow = mpMediaWindow->getWindow();

    if( pWindow )
        pWindow->SetHelpId( HID_AVMEDIA_PLAYERWINDOW );

    mpMediaWindow->show();
}

// -----------------------------------------------------------------------------

void MediaFloater::setURL( const ::rtl::OUString& rURL, bool bPlayImmediately )
{
    if( mpMediaWindow )
    {
        mpMediaWindow->setURL( rURL );

        if( mpMediaWindow->isValid() && bPlayImmediately )
            mpMediaWindow->start();
    }
}

// -----------------------------------------------------------------------------

const ::rtl::OUString& MediaFloater::getURL() const
{
    static const ::rtl::OUString aEmptyStr;
    return( mpMediaWindow ? mpMediaWindow->getURL() : aEmptyStr );
}

// -----------------------------------------------------------------------------

void MediaFloater::dispatchCurrentURL()
{
    SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();

    if( pDispatcher )
    {
        const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, getURL() );
        pDispatcher->Execute( SID_INSERT_AVMEDIA, SFX_CALLMODE_RECORD, &aMediaURLItem, 0L );
    }
}

}
<commit_msg>INTEGRATION: CWS warnings01 (1.3.24); FILE MERGED 2005/11/28 12:46:25 cl 1.3.24.1: warning free code fixes<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mediaplayer.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 13:58:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "mediaplayer.hxx"
#include "mediawindow.hxx"
#include "mediaitem.hxx"
#include "mediamisc.hxx"
#include "mediacontrol.hrc"
#include "helpids.hrc"

#include <svtools/stritem.hxx>
#include <sfx2/app.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>

namespace avmedia
{

// ---------------
// - MediaPlayer -
// ---------------

MediaPlayer::MediaPlayer( Window* _pParent, USHORT nId, SfxBindings* _pBindings, SfxChildWinInfo* pInfo ) :
    SfxChildWindow( _pParent, nId )
{
    pWindow = new MediaFloater( _pBindings, this, _pParent );
    eChildAlignment = SFX_ALIGN_NOALIGNMENT;
    static_cast< MediaFloater* >( pWindow )->Initialize( pInfo );
};

// -----------------------------------------------------------------------------

MediaPlayer::~MediaPlayer()
{
}

// -----------------------------------------------------------------------------

SFX_IMPL_DOCKINGWINDOW( MediaPlayer, SID_AVMEDIA_PLAYER )

// ----------------
// - MediaFloater -
// ----------------

MediaFloater::MediaFloater( SfxBindings* _pBindings, SfxChildWindow* pCW, Window* pParent ) :
    SfxDockingWindow( _pBindings, pCW, pParent, WB_CLOSEABLE | WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE ),
    mpMediaWindow( new MediaWindow( this, true ) )
{
    const Size aSize( 378, 256 );

    SetPosSizePixel( Point( 0, 0 ), aSize );
    SetMinOutputSizePixel( aSize );
    SetText( String( AVMEDIA_RESID( AVMEDIA_STR_MEDIAPLAYER ) ) );
    implInit();
    mpMediaWindow->show();
}

// -----------------------------------------------------------------------------

MediaFloater::~MediaFloater()
{
    delete mpMediaWindow;
    mpMediaWindow = NULL;
}

// -----------------------------------------------------------------------------

void MediaFloater::implInit()
{
}

// -------------------------------------------------------------------------

void MediaFloater::Resize()
{
    SfxDockingWindow::Resize();

    if( mpMediaWindow )
        mpMediaWindow->setPosSize( Rectangle( Point(), GetOutputSizePixel() ) );
}

// -----------------------------------------------------------------------------

void MediaFloater::ToggleFloatingMode()
{
    ::avmedia::MediaItem aRestoreItem;

    mpMediaWindow->updateMediaItem( aRestoreItem );
    delete mpMediaWindow;
    mpMediaWindow = NULL;

    SfxDockingWindow::ToggleFloatingMode();

    mpMediaWindow = new MediaWindow( this, true );

    mpMediaWindow->setPosSize( Rectangle( Point(), GetOutputSizePixel() ) );
    mpMediaWindow->executeMediaItem( aRestoreItem );

    Window* pWindow = mpMediaWindow->getWindow();

    if( pWindow )
        pWindow->SetHelpId( HID_AVMEDIA_PLAYERWINDOW );

    mpMediaWindow->show();
}

// -----------------------------------------------------------------------------

void MediaFloater::setURL( const ::rtl::OUString& rURL, bool bPlayImmediately )
{
    if( mpMediaWindow )
    {
        mpMediaWindow->setURL( rURL );

        if( mpMediaWindow->isValid() && bPlayImmediately )
            mpMediaWindow->start();
    }
}

// -----------------------------------------------------------------------------

const ::rtl::OUString& MediaFloater::getURL() const
{
    static const ::rtl::OUString aEmptyStr;
    return( mpMediaWindow ? mpMediaWindow->getURL() : aEmptyStr );
}

// -----------------------------------------------------------------------------

void MediaFloater::dispatchCurrentURL()
{
    SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();

    if( pDispatcher )
    {
        const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, getURL() );
        pDispatcher->Execute( SID_INSERT_AVMEDIA, SFX_CALLMODE_RECORD, &aMediaURLItem, 0L );
    }
}

}
<|endoftext|>


<commit_before>#ifdef WIN32
#define UNICODE
#define _UNICODE
#define _WIN32_DCOM

#define INITGUID

#include <objbase.h>  // COM Interface header file.
#include <iadmw.h>    // COM Interface header file.
#include <iiscnfg.h>  // MD_ & IIS_MD_ #defines header file.
#include <ks.h>
extern const CLSID CLSID_StdGlobalInterfaceTable;
#include <atlBase.h>  // ATL support header file.

#include "win32bindings.h"
#include "javasigar.h"

#ifdef __cplusplus
extern "C" {
#endif

static jfieldID ptr_field = 0;
static jfieldID IMeta_field = 0;

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseClose)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    METADATA_HANDLE MyHandle;
    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);
    (*pIMeta)->CloseKey(MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseRelease)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    pIMeta->Release();
    delete pIMeta;
    env->SetIntField(cur, ptr_field, 0);
    CoUninitialize();
}

JNIEXPORT jstring SIGAR_JNI(win32_MetaBase_MetaBaseEnumKey)
(JNIEnv *env, jobject cur, jint index)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[METADATA_MAX_NAME_LEN];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    hRes = (*pIMeta)->EnumKeys(MyHandle, TEXT(""), pbBuffer, index);
    if (SUCCEEDED(hRes)) {
        jstring strResult;
        // Store the data identifiers in an array for future use.
        // Note: declare a suitable DWORD array for names and add
        // array bounds checking.
        strResult = env->NewString((const jchar *)pbBuffer, lstrlen(pbBuffer));
        return strResult;
    } else if (hRes == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) {
        return NULL;
    }

    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "MetaBaseEnumKey");
    return NULL;
}

JNIEXPORT jlong SIGAR_JNI(win32_MetaBase_MetaBaseInit)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    HRESULT hRes = 0;
    hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "MetaBaseInit");
        return 0;
    }

    pIMeta = new (CComPtr <IMSAdminBase>);
    hRes = CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL,
                            IID_IMSAdminBase, (void **)pIMeta);
    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "MetaBaseInit:  Can't CoCreateInstance");
        return 0;
    }

    jclass cls = env->GetObjectClass(cur);
    ptr_field = env->GetFieldID(cls, "m_handle", "I");
    IMeta_field = env->GetFieldID(cls, "pIMeta", "J");
    return (jlong)pIMeta;
}

static void MetaBaseOpenSubKey(JNIEnv *env, jobject cur,
                               jstring path, METADATA_HANDLE MyHandle)
{
    HRESULT hRes = 0;
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    // Get a handle to the Web service.
    LPCTSTR lpSubkey = (LPCTSTR)env->GetStringChars(path, NULL);
    hRes = (*pIMeta)->OpenKey(MyHandle, lpSubkey,
                              METADATA_PERMISSION_READ, 20, &MyHandle);
    env->ReleaseStringChars(path, (const jchar *)lpSubkey);

    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "Can't open Sub Key");
        return;
    }
    env->SetIntField(cur, ptr_field, MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseOpenSubKey)
(JNIEnv *env, jobject cur, jstring path)
{
    METADATA_HANDLE MyHandle;
    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);
    MetaBaseOpenSubKey(env, cur, path, MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseOpenSubKeyAbs)
(JNIEnv *env, jobject cur, jstring path)
{
    MetaBaseOpenSubKey(env, cur, path, METADATA_MASTER_ROOT_HANDLE);
}

JNIEXPORT jint SIGAR_JNI(win32_MetaBase_MetaBaseGetIntValue)
(JNIEnv *env, jobject cur, jint key)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    // Initialize the input structure -
    // the values specify what kind of data to enumerate.
    MyRecord.dwMDIdentifier = key;
    MyRecord.dwMDAttributes = 0;
    MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
    MyRecord.dwMDDataType = DWORD_METADATA;
    MyRecord.dwMDDataLen = dwBufLen;
    MyRecord.pbMDData = (unsigned char *)pbBuffer;

    // Enumerate the data of the first virtual Web server,
    // checking to ensure that the data returned does not
    // overflow the buffer.

    hRes = (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);
    if (SUCCEEDED(hRes)) {
        int ret = (int)MyRecord.pbMDData;
        return ret;
    }
    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No such Int value");
    return 0;
}

JNIEXPORT jstring SIGAR_JNI(win32_MetaBase_MetaBaseGetStringValue)
(JNIEnv *env, jobject cur, jint key)
{
    int i;
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];
    DWORD data_types[] = {
        STRING_METADATA,
        EXPANDSZ_METADATA /* e.g. MD_LOGFILEDIRECTORY */
    };

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    for (i=0; i<sizeof(data_types)/sizeof(data_types[0]); i++) {
        DWORD dtype = data_types[i];
        // Initialize the input structure -
        // the values specify what kind of data to enumerate.
        MyRecord.dwMDIdentifier = key;
        MyRecord.dwMDAttributes = 0;
        MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
        MyRecord.dwMDDataType = dtype;
        MyRecord.dwMDDataLen = dwBufLen;
        MyRecord.pbMDData = (unsigned char *)pbBuffer;

        hRes =
            (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);

        if (SUCCEEDED(hRes)) {
            jstring strResult;
            // Store the data identifiers in an array for future use.
            // Note: declare a suitable DWORD array for names and add
            // array bounds checking.
            strResult = env->NewString((const jchar *)MyRecord.pbMDData,
                                       lstrlen(pbBuffer));
            return strResult;
        }
    }
    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No Such string value");
    return NULL;
}

JNIEXPORT jobjectArray SIGAR_JNI(win32_MetaBase_MetaBaseGetMultiStringValue)
(JNIEnv *env, jobject cur, jint key)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    // Initialize the input structure -
    // the values specify what kind of data to enumerate.
    MyRecord.dwMDIdentifier = key;
    MyRecord.dwMDAttributes = 0;
    MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
    MyRecord.dwMDDataType = MULTISZ_METADATA;
    MyRecord.dwMDDataLen = dwBufLen;
    MyRecord.pbMDData = (unsigned char *)pbBuffer;

    hRes = (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);
    if (SUCCEEDED(hRes)) {
        TCHAR *szThisInstance = NULL;
        jobjectArray ret = NULL;
        int i;
        // Start at -1 to account for the \0 at the end of the
        // list.
        int count = -1;

        // Count # of objects in dwInstanceList
        for (i = 0; i < MyRecord.dwMDDataLen; i+=2) {
            if ((TCHAR)MyRecord.pbMDData[i] == '\0') {
                count++;
            }
        }

        ret = (jobjectArray)env->
            NewObjectArray(count,
                           env->FindClass("java/lang/String"),
                           env->NewString((const jchar *)"", 1));

        // Walk the return instance list, creating an array
        for (szThisInstance = (TCHAR *)MyRecord.pbMDData, i = 0;
             *szThisInstance != 0;
             szThisInstance += lstrlen(szThisInstance) + 1, i++)
        {
            env->SetObjectArrayElement(ret,i,env->NewString(
                      (const jchar *)(LPCTSTR)szThisInstance,
                      lstrlen(szThisInstance)));
        }
        return ret;
    }

    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No Such string value");
    return NULL;
}

#ifdef __cplusplus
}
#endif
#endif /* WIN32 */
<commit_msg>2008 MSC express/SDK does not include atl<commit_after>#if defined(WIN32) && !defined(SIGAR_NO_ATL)
#define UNICODE
#define _UNICODE
#define _WIN32_DCOM

#define INITGUID

#include <objbase.h>  // COM Interface header file.
#include <iadmw.h>    // COM Interface header file.
#include <iiscnfg.h>  // MD_ & IIS_MD_ #defines header file.
#include <ks.h>
extern const CLSID CLSID_StdGlobalInterfaceTable;
#include <atlBase.h>  // ATL support header file.

#include "win32bindings.h"
#include "javasigar.h"

#ifdef __cplusplus
extern "C" {
#endif

static jfieldID ptr_field = 0;
static jfieldID IMeta_field = 0;

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseClose)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    METADATA_HANDLE MyHandle;
    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);
    (*pIMeta)->CloseKey(MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseRelease)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    pIMeta->Release();
    delete pIMeta;
    env->SetIntField(cur, ptr_field, 0);
    CoUninitialize();
}

JNIEXPORT jstring SIGAR_JNI(win32_MetaBase_MetaBaseEnumKey)
(JNIEnv *env, jobject cur, jint index)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[METADATA_MAX_NAME_LEN];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    hRes = (*pIMeta)->EnumKeys(MyHandle, TEXT(""), pbBuffer, index);
    if (SUCCEEDED(hRes)) {
        jstring strResult;
        // Store the data identifiers in an array for future use.
        // Note: declare a suitable DWORD array for names and add
        // array bounds checking.
        strResult = env->NewString((const jchar *)pbBuffer, lstrlen(pbBuffer));
        return strResult;
    } else if (hRes == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) {
        return NULL;
    }

    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "MetaBaseEnumKey");
    return NULL;
}

JNIEXPORT jlong SIGAR_JNI(win32_MetaBase_MetaBaseInit)
(JNIEnv *env, jobject cur)
{
    CComPtr <IMSAdminBase> *pIMeta;
    HRESULT hRes = 0;
    hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "MetaBaseInit");
        return 0;
    }

    pIMeta = new (CComPtr <IMSAdminBase>);
    hRes = CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL,
                            IID_IMSAdminBase, (void **)pIMeta);
    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "MetaBaseInit:  Can't CoCreateInstance");
        return 0;
    }

    jclass cls = env->GetObjectClass(cur);
    ptr_field = env->GetFieldID(cls, "m_handle", "I");
    IMeta_field = env->GetFieldID(cls, "pIMeta", "J");
    return (jlong)pIMeta;
}

static void MetaBaseOpenSubKey(JNIEnv *env, jobject cur,
                               jstring path, METADATA_HANDLE MyHandle)
{
    HRESULT hRes = 0;
    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    // Get a handle to the Web service.
    LPCTSTR lpSubkey = (LPCTSTR)env->GetStringChars(path, NULL);
    hRes = (*pIMeta)->OpenKey(MyHandle, lpSubkey,
                              METADATA_PERMISSION_READ, 20, &MyHandle);
    env->ReleaseStringChars(path, (const jchar *)lpSubkey);

    if (FAILED(hRes)) {
        jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
        env->ThrowNew(cls, "Can't open Sub Key");
        return;
    }
    env->SetIntField(cur, ptr_field, MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseOpenSubKey)
(JNIEnv *env, jobject cur, jstring path)
{
    METADATA_HANDLE MyHandle;
    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);
    MetaBaseOpenSubKey(env, cur, path, MyHandle);
}

JNIEXPORT void SIGAR_JNI(win32_MetaBase_MetaBaseOpenSubKeyAbs)
(JNIEnv *env, jobject cur, jstring path)
{
    MetaBaseOpenSubKey(env, cur, path, METADATA_MASTER_ROOT_HANDLE);
}

JNIEXPORT jint SIGAR_JNI(win32_MetaBase_MetaBaseGetIntValue)
(JNIEnv *env, jobject cur, jint key)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    // Initialize the input structure -
    // the values specify what kind of data to enumerate.
    MyRecord.dwMDIdentifier = key;
    MyRecord.dwMDAttributes = 0;
    MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
    MyRecord.dwMDDataType = DWORD_METADATA;
    MyRecord.dwMDDataLen = dwBufLen;
    MyRecord.pbMDData = (unsigned char *)pbBuffer;

    // Enumerate the data of the first virtual Web server,
    // checking to ensure that the data returned does not
    // overflow the buffer.

    hRes = (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);
    if (SUCCEEDED(hRes)) {
        int ret = (int)MyRecord.pbMDData;
        return ret;
    }
    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No such Int value");
    return 0;
}

JNIEXPORT jstring SIGAR_JNI(win32_MetaBase_MetaBaseGetStringValue)
(JNIEnv *env, jobject cur, jint key)
{
    int i;
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];
    DWORD data_types[] = {
        STRING_METADATA,
        EXPANDSZ_METADATA /* e.g. MD_LOGFILEDIRECTORY */
    };

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    for (i=0; i<sizeof(data_types)/sizeof(data_types[0]); i++) {
        DWORD dtype = data_types[i];
        // Initialize the input structure -
        // the values specify what kind of data to enumerate.
        MyRecord.dwMDIdentifier = key;
        MyRecord.dwMDAttributes = 0;
        MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
        MyRecord.dwMDDataType = dtype;
        MyRecord.dwMDDataLen = dwBufLen;
        MyRecord.pbMDData = (unsigned char *)pbBuffer;

        hRes =
            (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);

        if (SUCCEEDED(hRes)) {
            jstring strResult;
            // Store the data identifiers in an array for future use.
            // Note: declare a suitable DWORD array for names and add
            // array bounds checking.
            strResult = env->NewString((const jchar *)MyRecord.pbMDData,
                                       lstrlen(pbBuffer));
            return strResult;
        }
    }
    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No Such string value");
    return NULL;
}

JNIEXPORT jobjectArray SIGAR_JNI(win32_MetaBase_MetaBaseGetMultiStringValue)
(JNIEnv *env, jobject cur, jint key)
{
    HRESULT hRes = 0;
    METADATA_HANDLE MyHandle;
    METADATA_RECORD MyRecord;
    DWORD dwBufLen = 8096;
    DWORD dwReqBufLen = 0;
    TCHAR pbBuffer[8096];

    CComPtr <IMSAdminBase> *pIMeta;
    pIMeta = (CComPtr <IMSAdminBase> *)env->GetLongField(cur, IMeta_field);

    MyHandle = (METADATA_HANDLE)env->GetIntField(cur, ptr_field);

    // Initialize the input structure -
    // the values specify what kind of data to enumerate.
    MyRecord.dwMDIdentifier = key;
    MyRecord.dwMDAttributes = 0;
    MyRecord.dwMDUserType = IIS_MD_UT_SERVER;
    MyRecord.dwMDDataType = MULTISZ_METADATA;
    MyRecord.dwMDDataLen = dwBufLen;
    MyRecord.pbMDData = (unsigned char *)pbBuffer;

    hRes = (*pIMeta)->GetData(MyHandle, TEXT(""), &MyRecord, &dwReqBufLen);
    if (SUCCEEDED(hRes)) {
        TCHAR *szThisInstance = NULL;
        jobjectArray ret = NULL;
        int i;
        // Start at -1 to account for the \0 at the end of the
        // list.
        int count = -1;

        // Count # of objects in dwInstanceList
        for (i = 0; i < MyRecord.dwMDDataLen; i+=2) {
            if ((TCHAR)MyRecord.pbMDData[i] == '\0') {
                count++;
            }
        }

        ret = (jobjectArray)env->
            NewObjectArray(count,
                           env->FindClass("java/lang/String"),
                           env->NewString((const jchar *)"", 1));

        // Walk the return instance list, creating an array
        for (szThisInstance = (TCHAR *)MyRecord.pbMDData, i = 0;
             *szThisInstance != 0;
             szThisInstance += lstrlen(szThisInstance) + 1, i++)
        {
            env->SetObjectArrayElement(ret,i,env->NewString(
                      (const jchar *)(LPCTSTR)szThisInstance,
                      lstrlen(szThisInstance)));
        }
        return ret;
    }

    jclass cls = env->FindClass(WIN32_PACKAGE "Win32Exception");
    env->ThrowNew(cls, "No Such string value");
    return NULL;
}

#ifdef __cplusplus
}
#endif
#endif /* WIN32 */
<|endoftext|>


<commit_before><commit_msg>Minor updates<commit_after><|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CoreAudioOut.h"

#include <iostream>

#define BUFFER_COUNT 16

using namespace musik::core::audio;

void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    CoreAudioOut* output = (CoreAudioOut *) customData;
    CoreAudioOut::BufferContext* context = (CoreAudioOut::BufferContext *) buffer->mUserData;

    OSStatus result = AudioQueueFreeBuffer(queue, buffer);

    if (result != 0) {
        std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
    }

    output->NotifyBufferCompleted(context);
}

size_t countBuffersWithProvider(
    const std::list<CoreAudioOut::BufferContext*>& buffers,
    const IBufferProvider* provider)
{
    size_t count = 0;
    auto it = buffers.begin();
    while (it != buffers.end()) {
        if ((*it)->provider == provider) {
            ++count;
        }
        ++it;
    }
    return count;
}

void CoreAudioOut::NotifyBufferCompleted(BufferContext *context) {
    {
        boost::recursive_mutex::scoped_lock lock(this->mutex);

        auto it = this->buffers.begin();
        while (it != this->buffers.end()) {
            if (*it == context) {
                this->buffers.erase(it);
            }
            ++it;
        }
    }

    context->provider->OnBufferProcessed(context->buffer);
    delete context;
}

CoreAudioOut::CoreAudioOut() {
    this->quit = false;
    this->volume = 1.0f;

    this->audioFormat = (AudioStreamBasicDescription) { 0 };

    this->audioFormat.mFormatID = kAudioFormatLinearPCM;
    this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat;
    this->audioFormat.mFramesPerPacket = 1;
    this->audioFormat.mBitsPerChannel = 32;
    this->audioFormat.mReserved = 0;

    /* these get filled in later */
    this->audioFormat.mChannelsPerFrame = -1;
    this->audioFormat.mSampleRate = -1;
    this->audioFormat.mBytesPerFrame = -1;
    this->audioFormat.mBytesPerPacket = -1;

    this->audioQueue = NULL;
}

bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (countBuffersWithProvider(this->buffers, provider) >= BUFFER_COUNT) {
        /* enough buffers are already in the queue. bail, we'll notify the
        caller when there's more data available */
        return false;
    }

    OSStatus result;

    if (buffer->SampleRate() != this->audioFormat.mSampleRate ||
        buffer->Channels() != this->audioFormat.mChannelsPerFrame ||
        this->audioQueue == NULL)
    {
        this->audioFormat.mSampleRate = buffer->SampleRate();
        this->audioFormat.mChannelsPerFrame = buffer->Channels();
        this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame;
        this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket;

        this->Stop();

        result = AudioQueueNewOutput(
            &this->audioFormat,
            audioCallback,
            this,
            NULL,
            kCFRunLoopCommonModes,
            0,
            &this->audioQueue);

        if (result != 0) {
            std::cerr << "AudioQueueNewOutput failed: " << result << "\n";
            return false;
        }

        result = AudioQueueStart(this->audioQueue, NULL);

        this->SetVolume(volume);

        if (result != 0) {
            std::cerr << "AudioQueueStart failed: " << result << "\n";
            return false;
        }
    }

    AudioQueueBufferRef audioQueueBuffer = NULL;

    size_t bytes = buffer->Bytes();

    result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);

    BufferContext* context = new BufferContext();
    context->provider = provider;
    context->buffer = buffer;

    if (result != 0) {
        std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
        return false;
    }

    audioQueueBuffer->mUserData = (void *) context;
    audioQueueBuffer->mAudioDataByteSize = bytes;

    memcpy(
        audioQueueBuffer->mAudioData,
        (void *) buffer->BufferPointer(),
        bytes);

    result = AudioQueueEnqueueBuffer(
        this->audioQueue, audioQueueBuffer, 0, NULL);

    if (result != 0) {
        std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
        delete context;
        return false;
    }

    this->buffers.push_back(context);

    return true;
}

CoreAudioOut::~CoreAudioOut() {
    this->Stop();
}

void CoreAudioOut::Destroy() {
    delete this;
}

void CoreAudioOut::Pause() {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (this->audioQueue) {
        AudioQueuePause(this->audioQueue);
    }
}

void CoreAudioOut::Resume() {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (this->audioQueue) {
        AudioQueueStart(this->audioQueue, NULL);
    }
}

void CoreAudioOut::SetVolume(double volume) {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    this->volume = volume;

    if (this->audioQueue) {
        OSStatus result = AudioQueueSetParameter(
            this->audioQueue,
            kAudioQueueParam_Volume,
            volume);

        if (result != 0) {
            std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n";
        }
    }
}

void CoreAudioOut::Stop() {
    AudioQueueRef queue = NULL;

    {
        /* AudioQueueStop/AudioQueueDispose will trigger the callback, which
        will try to dispose of the samples on a separate thread and deadlock.
        cache the queue and reset outside of the critical section */
        boost::recursive_mutex::scoped_lock lock(this->mutex);
        queue = this->audioQueue;
        this->audioQueue = NULL;
    }

    if (queue) {
        AudioQueueStop(queue, true);
        AudioQueueDispose(queue, true);
    }
}
<commit_msg>One of those "how did this ever work?" bugs. Fixed CoreAudioOut buffer notification logic.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CoreAudioOut.h"

#include <iostream>

#define BUFFER_COUNT 16

using namespace musik::core::audio;

void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    CoreAudioOut* output = (CoreAudioOut *) customData;
    CoreAudioOut::BufferContext* context = (CoreAudioOut::BufferContext *) buffer->mUserData;

    OSStatus result = AudioQueueFreeBuffer(queue, buffer);

    if (result != 0) {
        std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
    }

    output->NotifyBufferCompleted(context);
}

size_t countBuffersWithProvider(
    const std::list<CoreAudioOut::BufferContext*>& buffers,
    const IBufferProvider* provider)
{
    size_t count = 0;
    auto it = buffers.begin();
    while (it != buffers.end()) {
        if ((*it)->provider == provider) {
            ++count;
        }
        ++it;
    }
    return count;
}

void CoreAudioOut::NotifyBufferCompleted(BufferContext *context) {
    {
        boost::recursive_mutex::scoped_lock lock(this->mutex);

        bool found = false;
        auto it = this->buffers.begin();
        while (!found && it != this->buffers.end()) {
            if (*it == context) {
                this->buffers.erase(it);
                found = true;
            }
            ++it;
        }
    }

    context->provider->OnBufferProcessed(context->buffer);
    delete context;
}

CoreAudioOut::CoreAudioOut() {
    this->quit = false;
    this->volume = 1.0f;

    this->audioFormat = (AudioStreamBasicDescription) { 0 };

    this->audioFormat.mFormatID = kAudioFormatLinearPCM;
    this->audioFormat.mFormatFlags = kAudioFormatFlagIsFloat;
    this->audioFormat.mFramesPerPacket = 1;
    this->audioFormat.mBitsPerChannel = 32;
    this->audioFormat.mReserved = 0;

    /* these get filled in later */
    this->audioFormat.mChannelsPerFrame = -1;
    this->audioFormat.mSampleRate = -1;
    this->audioFormat.mBytesPerFrame = -1;
    this->audioFormat.mBytesPerPacket = -1;

    this->audioQueue = NULL;
}

bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (countBuffersWithProvider(this->buffers, provider) >= BUFFER_COUNT) {
        /* enough buffers are already in the queue. bail, we'll notify the
        caller when there's more data available */
        return false;
    }

    OSStatus result;

    if (buffer->SampleRate() != this->audioFormat.mSampleRate ||
        buffer->Channels() != this->audioFormat.mChannelsPerFrame ||
        this->audioQueue == NULL)
    {
        this->audioFormat.mSampleRate = buffer->SampleRate();
        this->audioFormat.mChannelsPerFrame = buffer->Channels();
        this->audioFormat.mBytesPerFrame = (this->audioFormat.mBitsPerChannel / 8) * this->audioFormat.mChannelsPerFrame;
        this->audioFormat.mBytesPerPacket = this->audioFormat.mBytesPerFrame * this->audioFormat.mFramesPerPacket;

        this->Stop();

        result = AudioQueueNewOutput(
            &this->audioFormat,
            audioCallback,
            this,
            NULL,
            kCFRunLoopCommonModes,
            0,
            &this->audioQueue);

        if (result != 0) {
            std::cerr << "AudioQueueNewOutput failed: " << result << "\n";
            return false;
        }

        result = AudioQueueStart(this->audioQueue, NULL);

        this->SetVolume(volume);

        if (result != 0) {
            std::cerr << "AudioQueueStart failed: " << result << "\n";
            return false;
        }
    }

    AudioQueueBufferRef audioQueueBuffer = NULL;

    size_t bytes = buffer->Bytes();

    result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);

    BufferContext* context = new BufferContext();
    context->provider = provider;
    context->buffer = buffer;

    if (result != 0) {
        std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
        return false;
    }

    audioQueueBuffer->mUserData = (void *) context;
    audioQueueBuffer->mAudioDataByteSize = bytes;

    memcpy(
        audioQueueBuffer->mAudioData,
        (void *) buffer->BufferPointer(),
        bytes);

    result = AudioQueueEnqueueBuffer(
        this->audioQueue, audioQueueBuffer, 0, NULL);

    if (result != 0) {
        std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
        delete context;
        return false;
    }

    this->buffers.push_back(context);

    return true;
}

CoreAudioOut::~CoreAudioOut() {
    this->Stop();
}

void CoreAudioOut::Destroy() {
    delete this;
}

void CoreAudioOut::Pause() {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (this->audioQueue) {
        AudioQueuePause(this->audioQueue);
    }
}

void CoreAudioOut::Resume() {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    if (this->audioQueue) {
        AudioQueueStart(this->audioQueue, NULL);
    }
}

void CoreAudioOut::SetVolume(double volume) {
    boost::recursive_mutex::scoped_lock lock(this->mutex);

    this->volume = volume;

    if (this->audioQueue) {
        OSStatus result = AudioQueueSetParameter(
            this->audioQueue,
            kAudioQueueParam_Volume,
            volume);

        if (result != 0) {
            std::cerr << "AudioQueueSetParameter(volume) failed: " << result << "\n";
        }
    }
}

void CoreAudioOut::Stop() {
    AudioQueueRef queue = NULL;

    {
        /* AudioQueueStop/AudioQueueDispose will trigger the callback, which
        will try to dispose of the samples on a separate thread and deadlock.
        cache the queue and reset outside of the critical section */
        boost::recursive_mutex::scoped_lock lock(this->mutex);
        queue = this->audioQueue;
        this->audioQueue = NULL;
    }

    if (queue) {
        AudioQueueStop(queue, true);
        AudioQueueDispose(queue, true);
    }
}
<|endoftext|>


<commit_before>/*
 * PosixProcess.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "ChildProcess.hpp"

// TODO: on posix sleep seems to affect everyone -- is readsome blocking?

// TODO: address semantics of SIGCHLD:
//
//  - We've been calling reapChildren in SessionMain.cpp. this prevents
//    us from getting exit codes in the ChildProcessSupervisor! it appears
//    as if the semantics of system is to block SIGCHLD during execution
//    so we get away with it, however some other cases we might not be
//    (see pg. 345 of Advanced Unix Programming for more on this)
//
//  - Are the popen issues we've seen on the mac a result of the fact
//    that popen is not ignoring SIGCHLD on the mac? -- experiment
//
//  - Are the sweave/texi2dvi exit code issues we saw actually still
//    present if we do away with reapChildren? (we moved away from
//    ignoreChildExits to reapChildren however it may have been enough
//    to simply get rid of ignoreChildExits
//
//  - On the Mac R_system (in sysutils.c) uses a special cocoa run process
//    impl if useAqua is defined. Could it be that this implementation does
//    not block child signals which is why we couldn't get texi2dvi
//    exit codes?
//
//  - In server we need to reapChildren since we have session processes
//    which are exiting at random times (however we did have problems
//    with exit codes for PAM helper!). this simply may not be necessary
//    in session
//
//  - Furthermore, we may want to go with a more explicit method of
//    reaping the rsession processes so that we don't interfere with
//    the exit code handing for other scenarios.
//
// TODO: once we resolve the signal delivery issues could this
//       actually run on a background thread?

// PStreams 0.7.0
//
// The implementation of PosixChildProcess uses an embedded copy of the
// PStreams posix process control library. Links to the PStreams docs:
//
// http://pstreams.sourceforge.net/
// http://pstreams.sourceforge.net/doc/
// http://pstreams.sourceforge.net/faq.html
//
#include "pstreams-0.7.0/pstream.h"

#include <iostream>
#include <sstream>

#include <boost/iostreams/copy.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include "ChildProcess.hpp"

namespace core {
namespace system {

namespace {

Error readStream(redi::basic_pstream<char>& stream, std::string* pStr)
{
   try
   {
      // set exception mask (required for consistent reporting of errors since
      // boost::iostreams::copy throws)
      stream.exceptions(std::istream::failbit | std::istream::badbit);

      // copy file to string stream
      std::ostringstream ostr;
      boost::iostreams::copy(stream, ostr);
      *pStr = ostr.str();

      // reset exception mask
      stream.exceptions(std::istream::goodbit);

      // return success
      return Success();
   }
   catch(const std::exception& e)
   {
      Error error = systemError(boost::system::errc::io_error,
                                ERROR_LOCATION);
      error.addProperty("what", e.what());
      return error;
   }
}

void asyncReadStream(redi::basic_pstream<char>& stream, std::string* pOutput)
{
   char ch;
   while (stream.readsome(&ch, 1) > 0)
      pOutput->append(1, ch);
}

Error checkStreamState(redi::basic_pstream<char>& stream,
                       bool *pFinished,
                       bool otherFinished)
{
   // defualt to no error
   Error error;

   // check for eof or error
   if (stream.eof())
   {
      *pFinished = true;
   }
   else if (stream.fail())
   {
      error = systemError(boost::system::errc::io_error, ERROR_LOCATION);
   }

   // clear any error bit if the other stream isn't finished yet
   if (!stream.good() && !otherFinished)
      stream.clear();

   // return error status
   return error;
}

int resolveExitStatus(int status)
{
   return WIFEXITED(status) ? WEXITSTATUS(status) : status;
}

} // anonymous namespace

struct ChildProcess::Impl
{
   redi::basic_pstreambuf<char>& rdbuf() { return *pstream_.rdbuf(); }
   redi::basic_pstream<char> pstream_;
};

ChildProcess::ChildProcess(const std::string& cmd,
                           const std::vector<std::string>& args)
  : pImpl_(new Impl()), cmd_(cmd), args_(args)
{
}

ChildProcess::~ChildProcess()
{
}

Error ChildProcess::writeToStdin(const std::string& input, bool eof)
{
   try
   {
      // write and check for error
      pImpl_->pstream_ << input;
      if (pImpl_->pstream_.fail())
         return systemError(boost::system::errc::io_error, ERROR_LOCATION);

      // write eof if requested
      if (eof)
      {
         pImpl_->rdbuf().peof();

         if (pImpl_->pstream_.fail())
            return systemError(boost::system::errc::io_error, ERROR_LOCATION);
      }

      return Success();
   }
   catch(const std::ios_base::failure& e)
   {
      // we don't expect this to ever happen (since we haven't set the
      // exception flag on our io objects)
      Error error = systemError(boost::system::errc::io_error,
                                ERROR_LOCATION);
      error.addProperty("what", e.what());
      return error;
   }
}

Error ChildProcess::terminate()
{
   // only send signal if the process is open
   if (!pImpl_->pstream_.is_open())
      return systemError(ESRCH, ERROR_LOCATION);

   // send signal
   if (pImpl_->rdbuf().kill(SIGTERM) != NULL)
      return Success();
   else
      return systemError(pImpl_->rdbuf().error(), ERROR_LOCATION);
}

Error ChildProcess::run()
{
   // create set of args to pass (needs to include the cmd)
   std::vector<std::string> args;
   args.push_back(cmd_);
   args.insert(args.end(), args_.begin(), args_.end());

   // open the process
   pImpl_->pstream_.open(cmd_, args, redi::pstreambuf::pstdin |
                                     redi::pstreambuf::pstdout |
                                     redi::pstreambuf::pstderr);

   // return success if we are running
   if (pImpl_->pstream_.is_open())
   {
      return Success();
   }
   else
   {
      return systemError(pImpl_->rdbuf().error(), ERROR_LOCATION);
   }
}

Error SyncChildProcess::readStdOut(std::string* pOutput)
{
   return readStream(pImpl_->pstream_.out(), pOutput);
}

Error SyncChildProcess::readStdErr(std::string* pOutput)
{
   return readStream(pImpl_->pstream_.err(), pOutput);
}

Error SyncChildProcess::waitForExit(int* pExitStatus)
{
   pImpl_->pstream_.close();
   *pExitStatus = resolveExitStatus(pImpl_->rdbuf().status());
   return Success();
}

struct AsyncChildProcess::AsyncImpl
{
   AsyncImpl()
      : calledOnStarted_(false),
        finishedStdout_(false),
        finishedStderr_(false),
        exited_(false)
   {
   }

   bool calledOnStarted_;
   bool finishedStdout_;
   bool finishedStderr_;
   bool exited_;
};

AsyncChildProcess::AsyncChildProcess(const std::string& cmd,
                                     const std::vector<std::string>& args)
   : ChildProcess(cmd, args), pAsyncImpl_(new AsyncImpl())
{
}

AsyncChildProcess::~AsyncChildProcess()
{
}

void AsyncChildProcess::poll()
{
   // check for output
   try
   {
      // call onStarted if we haven't yet
      if (!(pAsyncImpl_->calledOnStarted_))
      {
         if (callbacks_.onStarted)
            callbacks_.onStarted(*this);
         pAsyncImpl_->calledOnStarted_ = true;
      }

      // call onRunning
      if (callbacks_.onRunning)
         callbacks_.onRunning(*this);

      // check stdout and fire event if we got output
      if (!pAsyncImpl_->finishedStdout_)
      {
         std::string out;
         asyncReadStream(pImpl_->pstream_.out(), &out);
         if (!out.empty() && callbacks_.onStdout)
            callbacks_.onStdout(*this, out);

         // check stream state
         Error error = checkStreamState(pImpl_->pstream_,
                                        &(pAsyncImpl_->finishedStdout_),
                                        pAsyncImpl_->finishedStderr_);
         if (error)
            reportError(error);
      }

      // check stderr and fire event if we got output
      if (!pAsyncImpl_->finishedStderr_)
      {
         std::string err;
         asyncReadStream(pImpl_->pstream_.err(), &err);
         if (!err.empty() && callbacks_.onStderr)
            callbacks_.onStderr(*this, err);

         // check stream state
         Error error = checkStreamState(pImpl_->pstream_,
                                        &(pAsyncImpl_->finishedStderr_),
                                        pAsyncImpl_->finishedStdout_);
         if (error)
            reportError(error);
      }

      // if both streams are finished then check for exited
      if (pAsyncImpl_->finishedStdout_ && pAsyncImpl_->finishedStderr_)
      {
         // Attempt to reap child. Note that this method specifies WNOHANG
         // so we don't block forever waiting for a process the exit. We may
         // not be able to reap the child due to EINTR, in that case we'll
         // just call exited again at the next polling interval. We may not
         // be able to reap the child due to ECHILD (reaped by a global
         // handler) in which case we'll allow the exit sequence to proceed
         // and simply pass -1 as the exit status. If we fail to reap the
         // the child for any other reason (there aren't actually any other
         // failure codes defined for waitpid) then we'll simply continue
         // calling exited in every polling interval (and this leak this
         // object). Note that we don't anticipate this ever occuring based
         // on our understanding of waitpid, PStreams, etc.
         if (pImpl_->rdbuf().exited() || (pImpl_->rdbuf().error() == ECHILD))
         {
            // close the stream (this won't block because we have
            // already established that the child is not running)
            pImpl_->pstream_.close();

            // fire exit event
            if (callbacks_.onExit)
            {
               // resolve exit status
               int status = resolveExitStatus(pImpl_->rdbuf().status());

               // call onExit
               callbacks_.onExit(status);
            }

            // set exited_ flag so that our exited function always
            // returns the right value (even if we haven't been able
            // to successfully wait/reap the child)
            pAsyncImpl_->exited_ = true;
         }
      }
   }
   catch(const std::ios_base::failure& e)
   {
      // we don't expect this to ever happen (since we haven't set the
      // exception flag on our io objects)
      reportIOError(e.what(), ERROR_LOCATION);
   }
}

bool AsyncChildProcess::exited()
{
   return pAsyncImpl_->exited_;
}

} // namespace system
} // namespace core

<commit_msg>update todo comments<commit_after>/*
 * PosixProcess.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "ChildProcess.hpp"

// TODO: address semantics of SIGCHLD:
//
//  - We've been calling reapChildren in SessionMain.cpp. this prevents
//    us from getting exit codes in the ChildProcessSupervisor! it appears
//    as if the semantics of system is to block SIGCHLD during execution
//    so we get away with it, however some other cases we might not be
//    (see pg. 345 of Advanced Unix Programming for more on this)
//
//  - Are the popen issues we've seen on the mac a result of the fact
//    that popen is not ignoring SIGCHLD on the mac? -- experiment
//
//  - Are the sweave/texi2dvi exit code issues we saw actually still
//    present if we do away with reapChildren? (we moved away from
//    ignoreChildExits to reapChildren however it may have been enough
//    to simply get rid of ignoreChildExits
//
//  - On the Mac R_system (in sysutils.c) uses a special cocoa run process
//    impl if useAqua is defined. Could it be that this implementation does
//    not block child signals which is why we couldn't get texi2dvi
//    exit codes?
//
//  - In server we need to reapChildren since we have session processes
//    which are exiting at random times (however we did have problems
//    with exit codes for PAM helper!). this simply may not be necessary
//    in session
//
//  - Furthermore, we may want to go with a more explicit method of
//    reaping the rsession processes so that we don't interfere with
//    the exit code handing for other scenarios.
//
// TODO: once we resolve the signal delivery issues could this
//       actually run on a background thread?

// PStreams 0.7.0
//
// The implementation of PosixChildProcess uses an embedded copy of the
// PStreams posix process control library. Links to the PStreams docs:
//
// http://pstreams.sourceforge.net/
// http://pstreams.sourceforge.net/doc/
// http://pstreams.sourceforge.net/faq.html
//
#include "pstreams-0.7.0/pstream.h"

#include <iostream>
#include <sstream>

#include <boost/iostreams/copy.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include "ChildProcess.hpp"

namespace core {
namespace system {

namespace {

Error readStream(redi::basic_pstream<char>& stream, std::string* pStr)
{
   try
   {
      // set exception mask (required for consistent reporting of errors since
      // boost::iostreams::copy throws)
      stream.exceptions(std::istream::failbit | std::istream::badbit);

      // copy file to string stream
      std::ostringstream ostr;
      boost::iostreams::copy(stream, ostr);
      *pStr = ostr.str();

      // reset exception mask
      stream.exceptions(std::istream::goodbit);

      // return success
      return Success();
   }
   catch(const std::exception& e)
   {
      Error error = systemError(boost::system::errc::io_error,
                                ERROR_LOCATION);
      error.addProperty("what", e.what());
      return error;
   }
}

void asyncReadStream(redi::basic_pstream<char>& stream, std::string* pOutput)
{
   char ch;
   while (stream.readsome(&ch, 1) > 0)
      pOutput->append(1, ch);
}

Error checkStreamState(redi::basic_pstream<char>& stream,
                       bool *pFinished,
                       bool otherFinished)
{
   // defualt to no error
   Error error;

   // check for eof or error
   if (stream.eof())
   {
      *pFinished = true;
   }
   else if (stream.fail())
   {
      error = systemError(boost::system::errc::io_error, ERROR_LOCATION);
   }

   // clear any error bit if the other stream isn't finished yet
   if (!stream.good() && !otherFinished)
      stream.clear();

   // return error status
   return error;
}

int resolveExitStatus(int status)
{
   return WIFEXITED(status) ? WEXITSTATUS(status) : status;
}

} // anonymous namespace

struct ChildProcess::Impl
{
   redi::basic_pstreambuf<char>& rdbuf() { return *pstream_.rdbuf(); }
   redi::basic_pstream<char> pstream_;
};

ChildProcess::ChildProcess(const std::string& cmd,
                           const std::vector<std::string>& args)
  : pImpl_(new Impl()), cmd_(cmd), args_(args)
{
}

ChildProcess::~ChildProcess()
{
}

Error ChildProcess::writeToStdin(const std::string& input, bool eof)
{
   try
   {
      // write and check for error
      pImpl_->pstream_ << input;
      if (pImpl_->pstream_.fail())
         return systemError(boost::system::errc::io_error, ERROR_LOCATION);

      // write eof if requested
      if (eof)
      {
         pImpl_->rdbuf().peof();

         if (pImpl_->pstream_.fail())
            return systemError(boost::system::errc::io_error, ERROR_LOCATION);
      }

      return Success();
   }
   catch(const std::ios_base::failure& e)
   {
      // we don't expect this to ever happen (since we haven't set the
      // exception flag on our io objects)
      Error error = systemError(boost::system::errc::io_error,
                                ERROR_LOCATION);
      error.addProperty("what", e.what());
      return error;
   }
}

Error ChildProcess::terminate()
{
   // only send signal if the process is open
   if (!pImpl_->pstream_.is_open())
      return systemError(ESRCH, ERROR_LOCATION);

   // send signal
   if (pImpl_->rdbuf().kill(SIGTERM) != NULL)
      return Success();
   else
      return systemError(pImpl_->rdbuf().error(), ERROR_LOCATION);
}

Error ChildProcess::run()
{
   // create set of args to pass (needs to include the cmd)
   std::vector<std::string> args;
   args.push_back(cmd_);
   args.insert(args.end(), args_.begin(), args_.end());

   // open the process
   pImpl_->pstream_.open(cmd_, args, redi::pstreambuf::pstdin |
                                     redi::pstreambuf::pstdout |
                                     redi::pstreambuf::pstderr);

   // return success if we are running
   if (pImpl_->pstream_.is_open())
   {
      return Success();
   }
   else
   {
      return systemError(pImpl_->rdbuf().error(), ERROR_LOCATION);
   }
}

Error SyncChildProcess::readStdOut(std::string* pOutput)
{
   return readStream(pImpl_->pstream_.out(), pOutput);
}

Error SyncChildProcess::readStdErr(std::string* pOutput)
{
   return readStream(pImpl_->pstream_.err(), pOutput);
}

Error SyncChildProcess::waitForExit(int* pExitStatus)
{
   pImpl_->pstream_.close();
   *pExitStatus = resolveExitStatus(pImpl_->rdbuf().status());
   return Success();
}

struct AsyncChildProcess::AsyncImpl
{
   AsyncImpl()
      : calledOnStarted_(false),
        finishedStdout_(false),
        finishedStderr_(false),
        exited_(false)
   {
   }

   bool calledOnStarted_;
   bool finishedStdout_;
   bool finishedStderr_;
   bool exited_;
};

AsyncChildProcess::AsyncChildProcess(const std::string& cmd,
                                     const std::vector<std::string>& args)
   : ChildProcess(cmd, args), pAsyncImpl_(new AsyncImpl())
{
}

AsyncChildProcess::~AsyncChildProcess()
{
}

void AsyncChildProcess::poll()
{
   // check for output
   try
   {
      // call onStarted if we haven't yet
      if (!(pAsyncImpl_->calledOnStarted_))
      {
         if (callbacks_.onStarted)
            callbacks_.onStarted(*this);
         pAsyncImpl_->calledOnStarted_ = true;
      }

      // call onRunning
      if (callbacks_.onRunning)
         callbacks_.onRunning(*this);

      // check stdout and fire event if we got output
      if (!pAsyncImpl_->finishedStdout_)
      {
         std::string out;
         asyncReadStream(pImpl_->pstream_.out(), &out);
         if (!out.empty() && callbacks_.onStdout)
            callbacks_.onStdout(*this, out);

         // check stream state
         Error error = checkStreamState(pImpl_->pstream_,
                                        &(pAsyncImpl_->finishedStdout_),
                                        pAsyncImpl_->finishedStderr_);
         if (error)
            reportError(error);
      }

      // check stderr and fire event if we got output
      if (!pAsyncImpl_->finishedStderr_)
      {
         std::string err;
         asyncReadStream(pImpl_->pstream_.err(), &err);
         if (!err.empty() && callbacks_.onStderr)
            callbacks_.onStderr(*this, err);

         // check stream state
         Error error = checkStreamState(pImpl_->pstream_,
                                        &(pAsyncImpl_->finishedStderr_),
                                        pAsyncImpl_->finishedStdout_);
         if (error)
            reportError(error);
      }

      // if both streams are finished then check for exited
      if (pAsyncImpl_->finishedStdout_ && pAsyncImpl_->finishedStderr_)
      {
         // Attempt to reap child. Note that this method specifies WNOHANG
         // so we don't block forever waiting for a process the exit. We may
         // not be able to reap the child due to EINTR, in that case we'll
         // just call exited again at the next polling interval. We may not
         // be able to reap the child due to ECHILD (reaped by a global
         // handler) in which case we'll allow the exit sequence to proceed
         // and simply pass -1 as the exit status. If we fail to reap the
         // the child for any other reason (there aren't actually any other
         // failure codes defined for waitpid) then we'll simply continue
         // calling exited in every polling interval (and this leak this
         // object). Note that we don't anticipate this ever occuring based
         // on our understanding of waitpid, PStreams, etc.
         if (pImpl_->rdbuf().exited() || (pImpl_->rdbuf().error() == ECHILD))
         {
            // close the stream (this won't block because we have
            // already established that the child is not running)
            pImpl_->pstream_.close();

            // fire exit event
            if (callbacks_.onExit)
            {
               // resolve exit status
               int status = resolveExitStatus(pImpl_->rdbuf().status());

               // call onExit
               callbacks_.onExit(status);
            }

            // set exited_ flag so that our exited function always
            // returns the right value (even if we haven't been able
            // to successfully wait/reap the child)
            pAsyncImpl_->exited_ = true;
         }
      }
   }
   catch(const std::ios_base::failure& e)
   {
      // we don't expect this to ever happen (since we haven't set the
      // exception flag on our io objects)
      reportIOError(e.what(), ERROR_LOCATION);
   }
}

bool AsyncChildProcess::exited()
{
   return pAsyncImpl_->exited_;
}

} // namespace system
} // namespace core

<|endoftext|>