text:
/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2018, Viktor Seib, Norman Link
 * 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 copyright holder nor the names of its
 *   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 HOLDER 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 <iostream>
#include <vector>
#include <fstream>
#include <boost/program_options.hpp>
#include <boost/program_options/errors.hpp>
#include "../implicit_shape_model/implicit_shape_model.h"
#include "eval_helpers.h"

int main(int argc, char **argv)
{
    boost::program_options::options_description generic("Generic options");
    boost::program_options::options_description training("Training");
    boost::program_options::options_description detection("Detection");

    generic.add_options()
            ("help,h", "Display this help message")
            ("output,o", boost::program_options::value<std::string>(), "The output folder (created automatically) for ism files after training or the classification log after classification")
            ("inputfile,f", boost::program_options::value<std::string>(), "Input file (for training or testing) containing the input clouds and their corresponding labels (replaces m and c in training and p and g in testing");

    training.add_options()
            ("train,t", boost::program_options::value<std::string>(), "Train an implicit shape model")
            ("inplace,i", "Overwrite the loaded ism file")
            ("models,m", boost::program_options::value<std::vector<std::string> >()->multitoken()->composing(), "Specifiy a list of training models")
            ("classes,c", boost::program_options::value<std::vector<unsigned> >()->multitoken()->composing(), "Specifiy a list of class ids for the given training models");

    detection.add_options()
            ("detect,d", boost::program_options::value<std::string>(), "Detect using a trained implicit shape model")
            ("pointclouds,p", boost::program_options::value<std::vector<std::string> >()->multitoken()->composing(), "Specify a list of input point clouds")
            ("groundtruth,g", boost::program_options::value<std::vector<unsigned> >()->multitoken()->composing(), "Specifiy a list of ground truth class ids for the given pointclouds");

    boost::program_options::options_description desc;
    desc.add(generic).add(training).add(detection);

    // parse command line arguments
    boost::program_options::variables_map variables;
    try {
        boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(desc).run(), variables);
        boost::program_options::notify(variables);
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

    // show help
    if (variables.count("help") || variables.size() == 0) {
        std::cout << desc << std::endl;
        return 1;
    }
    else {

        std::vector<std::string> filenames;
        std::vector<unsigned> class_labels;
        std::vector<unsigned> instance_labels;
        std::string mode = "";

        if(variables.count("inputfile"))
        {
            // manually parse input file if available, then adapt it to boost params
            std::string input_file_name = variables["inputfile"].as<std::string>();
            label_usage = parseFileList(input_file_name, filenames, class_labels, instance_labels, mode);
        }

        try {
            // train the ISM
            if ((variables.count("train") && mode == "") || mode == "train")
            {
                std::cout << "starting the training process" << std::endl;

                std::string ismFile;
                try // allows to use -t or -d for ism-files when input file with dataset is specified with -f
                {
                    ismFile = variables["train"].as<std::string>();
                }
                catch(std::exception& e)
                {
                    ismFile = variables["detect"].as<std::string>();
                }

                // try to read the file
                ism3d::ImplicitShapeModel ism;
                ism.setLogging(log_info);
                ism.setSignalsState(false); // disable signals since we are using command line, no GUI

                if(!ism.readObject(ismFile, true))
                {
                    std::cerr << "could not read ism from file, training stopped: " << ismFile << std::endl;
                    return 1;
                }

                // if both, class and instance labels given, check which is primary
                if(label_usage == LabelUsage::BOTH_GIVEN)
                {
                    if(ism.isInstancePrimaryLabel())
                    {
                        label_usage = LabelUsage::INSTANCE_PRIMARY;
                    }
                    else
                    {
                        label_usage = LabelUsage::CLASS_PRIMARY;
                    }
                }

                // set output filename
                if(variables.count("output"))
                {
                    std::string outFilename = variables["output"].as<std::string>();
                    ism.setOutputFilename(outFilename);
                }

                // add the training models to the ism
                if((variables.count("models") && variables.count("classes")) ||
                        (filenames.size() > 0 && class_labels.size() > 0))
                {
                    std::vector<std::string> models;
                    std::vector<unsigned> class_ids;
                    std::vector<unsigned> instance_ids;

                    if(variables.count("models")) // input directly from command line
                    {
                        models = variables["models"].as<std::vector<std::string> >();
                        class_ids = variables["classes"].as<std::vector<unsigned> >();
                        instance_ids = class_ids; // NOTE: instance training not supported on direct command line input
                    }
                    else if(filenames.size() > 0) // input inside file given on command line
                    {
                        models = filenames;
                        if(label_usage == LabelUsage::CLASS_ONLY)
                        {
                            // instance ids must be filled even if training with class labels only
                            class_ids = class_labels;
                            instance_ids = class_labels;
                        }
                        else if(label_usage == LabelUsage::CLASS_PRIMARY)
                        {
                            class_ids = class_labels;
                            instance_ids = instance_labels;
                        }
                        else if(label_usage == LabelUsage::INSTANCE_PRIMARY)
                        {
                            class_ids = instance_labels;
                            instance_ids = instance_labels;
                        }
                        else
                        {
                            std::cerr << "Label usage not defined or not supported! ("
                                      << static_cast<std::underlying_type<LabelUsage>::type>(label_usage) << ")" << std::endl;
                            return 1;
                        }
                    }

                    if (models.size() == class_ids.size())
                    {
                        for (int i = 0; i < (int)models.size(); i++)
                        {
                            std::string filename = models[i];
                            unsigned class_id = class_ids[i];
                            unsigned instance_id = instance_ids[i];

                            // add the training model to the ISM
                            if (!ism.addTrainingModel(filename, class_id, instance_id))
                            {
                                std::cerr << "could not add training model: " << filename << ", class " << class_id << std::endl;
                                return 1;
                            }
                        }
                    }
                    else
                    {
                        std::cerr << "number of models does not match the number of class ids" << std::endl;
                        return 1;
                    }
                }

                // train
                ism.train();

                // store maps in the model object file
                ism.setLabels(class_labels_rmap, instance_labels_rmap, instance_to_class_map);

                // write the ism data
                if (variables.count("inplace"))
                {
                    if (!ism.writeObject(ismFile, ismFile + "d"))
                    {
                        std::cerr << "could not write ism" << std::endl;
                        return 1;
                    }
                }
                else if (variables.count("output"))
                {
                    std::string outFilename = variables["output"].as<std::string>();
                    if (!ism.writeObject(outFilename))
                    {
                        std::cerr << "could not write ism" << std::endl;
                        return 1;
                    }
                }
                else
                {
                    std::cerr << "the trained ism is not saved" << std::endl;
                    return 1;
                }
            }

            // use ISM for classification
            if ((variables.count("detect") && mode == "") || mode == "test")
            {
                std::cout << "starting the classification process" << std::endl;

                std::string ismFile;
                try // allows to use -t or -d for ism-files when input file with dataset is specified with -f
                {
                    ismFile = variables["detect"].as<std::string>();
                }
                catch(std::exception& e)
                {
                    ismFile = variables["train"].as<std::string>();
                }

                // try to read the file
                ism3d::ImplicitShapeModel ism;
                ism.setLogging(log_info);
                ism.setSignalsState(false); // disable signals since we are using command line, no GUI

                if (!ism.readObject(ismFile))
                {
                    std::cerr << "could not read ism from file, classification stopped: " << ismFile << std::endl;
                    return 1;
                }
                else if ((variables.count("pointclouds") && variables.count("groundtruth")) ||
                         (filenames.size() > 0 && class_labels.size() > 0))  // load pointclouds and groundtruth
                {
                    std::vector<std::string> pointClouds;
                    std::vector<unsigned> gt_class_ids;
                    std::vector<unsigned> gt_instance_ids;

                    class_labels_rmap = ism.getClassLabels();
                    instance_labels_rmap = ism.getInstanceLabels();
                    instance_to_class_map = ism.getInstanceClassMap();

                    // if both, class and instance labels given, check which is primary
                    if(label_usage == LabelUsage::BOTH_GIVEN)
                    {
                        if(ism.isInstancePrimaryLabel())
                            label_usage = LabelUsage::INSTANCE_PRIMARY;
                        else
                            label_usage = LabelUsage::CLASS_PRIMARY;
                    }

                    if(variables.count("pointclouds")) // input directly from command line
                    {
                        pointClouds = variables["pointclouds"].as<std::vector<std::string> >();
                        gt_class_ids = variables["groundtruth"].as<std::vector<unsigned> >();
                    }
                    else if(filenames.size() > 0) // input inside file given on command line
                    {
                        pointClouds = filenames;
                        if(label_usage == LabelUsage::CLASS_ONLY)
                        {
                            // instance ids must be filled even if testing with class labels only
                            gt_class_ids = class_labels;
                            gt_instance_ids = class_labels;
                        }
                        else if(label_usage == LabelUsage::CLASS_PRIMARY || label_usage == LabelUsage::INSTANCE_PRIMARY)
                        {
                            gt_class_ids = class_labels;
                            gt_instance_ids = instance_labels;
                        }
                        else
                        {
                            std::cerr << "Label usage not defined or not supported!" << std::endl;
                            return 1;
                        }
                    }

                    // prepare summary
                    std::ofstream summaryFile;
                    int numCorrectClasses = 0;
                    int numCorrectInstances = 0;
                    std::map<unsigned, std::pair<unsigned, unsigned>> averageAccuracyHelper; // maps class id to pair <correct, total>

                    int numCorrectGlobal = 0;
                    int numBothCorrect = 0;
                    int numOnlyGlobalCorrect = 0;

                    //std::cout << "preparing output folder" << std::endl;

                    if (variables.count("output"))
                    {
                        // create folder for output
                        std::string command = "mkdir ";
                        std::string folder = variables["output"].as<std::string>();
                        command.append(folder);
                        std::ignore = std::system(command.c_str());
                        sleep(1);

                        // summary file
                        std::string outFile = variables["output"].as<std::string>();
                        std::string outFileName = outFile;
                        outFileName.append("/summary.txt");
                        summaryFile.open(outFileName.c_str(), std::ios::out);
                    }
                    else
                    {
                        std::cerr << "no output file specified, detected maxima will not be saved" << std::endl;
                    }

                    if (pointClouds.size() == gt_class_ids.size())
                    {
                        boost::timer::cpu_timer timer;
                        std::map<std::string, double> times;
                        for(unsigned i = 0; i < pointClouds.size(); i++)
                        {
                            // detect
                            std::string pointCloud = pointClouds.at(i);
                            unsigned trueID = gt_class_ids.at(i);
                            unsigned trueInstanceID = gt_instance_ids.at(i);
                            std::vector<ism3d::VotingMaximum> maxima;

                            std::cout << "Processing file: " << pointCloud << std::endl;
                            if (!ism.detect(pointCloud, maxima, times))
                            {
                                std::cerr << "classification failed" << std::endl;
                                return 1;
                            }
                            else
                            {
                                //std::cout << "detected " << maxima.size() << " maxima" << std::endl;
                                // write detected maxima to classification log file
                                if (variables.count("output"))
                                {
                                    if(write_log_to_files)
                                    {
                                        unsigned tmp = pointCloud.find_last_of('/');
                                        if(tmp == std::string::npos) tmp = 0;
                                        std::string fileWithoutFolder = pointCloud.substr(tmp+1);

                                        std::cout << "writing classification log" << std::endl;
                                        std::string outFile = variables["output"].as<std::string>();
                                        std::string outFileName = outFile;
                                        outFileName.append("/");
                                        outFileName.append(fileWithoutFolder);
                                        outFileName.append(".txt");

                                        std::ofstream file;
                                        file.open(outFileName.c_str(), std::ios::out);
                                        file << "ISM3D classification log, filename: " << ismFile << ", point cloud: " << pointCloud
                                             << ", ground truth class: " << trueID << ", ground truth instance: " << trueInstanceID << std::endl;
                                        file << "number, classID, weight, instanceID, instance weight, num-votes, position X Y Z, bounding box size X Y Z, bounding Box rotation quaternion w x y z" << std::endl;

                                        for (int i = 0; i < (int)maxima.size(); i++)
                                        {
                                            const ism3d::VotingMaximum& maximum = maxima[i];

                                            file << i << ", ";
                                            file << maximum.classId << ", ";
                                            file << maximum.weight << ", ";
                                            file << maximum.instanceId << ", ";
                                            file << maximum.instanceWeight << ", ";
                                            file << maximum.votes.size() << ", ";
                                            file << maximum.position[0] << ", ";
                                            file << maximum.position[1] << ", ";
                                            file << maximum.position[2] << ", ";
                                            file << maximum.boundingBox.size[0] << ", ";
                                            file << maximum.boundingBox.size[1] << ", ";
                                            file << maximum.boundingBox.size[2] << ", ";
                                            file << maximum.boundingBox.rotQuat.R_component_1() << ", ";
                                            file << maximum.boundingBox.rotQuat.R_component_2() << ", ";
                                            file << maximum.boundingBox.rotQuat.R_component_3() << ", ";
                                            file << maximum.boundingBox.rotQuat.R_component_4() << std::endl;
                                        }

                                        file.close();
                                    }

                                    // writing summary file
                                    int classId = -1;
                                    int classIdglobal = -1;
                                    int instanceId = -1;
                                    if(maxima.size() > 0)
                                    {
                                        classId = maxima.at(0).classId;
                                        classIdglobal = maxima.at(0).globalHypothesis.classId;
                                        // lookup real class ids if instances were used as primary labels
                                        if(label_usage == LabelUsage::INSTANCE_PRIMARY)
                                        {
                                            classId = instance_to_class_map[classId];
                                            classIdglobal = instance_to_class_map[classIdglobal];
                                        }
                                        instanceId = maxima.at(0).instanceId;
                                    }

                                    // only display additional classifiers if they are different from normal classification
                                    summaryFile << "file: " << pointCloud << ", ground truth class: " << trueID << ", classified class: " << classId;

                                    if(classId != classIdglobal)
                                    {
                                        summaryFile << ", global class: " << classIdglobal;
                                    }
                                    summaryFile << std::endl;

                                    // count correct matches
                                    // normal classifier
                                    if(((int)trueID) == classId)
                                    {
                                        // correct classification
                                        numCorrectClasses++;
                                        if(averageAccuracyHelper.find(trueID) != averageAccuracyHelper.end())
                                        {
                                            // pair <correct, total>
                                            std::pair<unsigned, unsigned> &res = averageAccuracyHelper.at(trueID);
                                            res.first++;
                                            res.second++;
                                        }
                                        else
                                        {
                                            averageAccuracyHelper.insert({trueID, {1,1}});
                                        }
                                    }
                                    else
                                    {
                                        // wrong classification
                                        if(averageAccuracyHelper.find(trueID) != averageAccuracyHelper.end())
                                        {
                                            // pair <correct, total>
                                            std::pair<unsigned, unsigned> &res = averageAccuracyHelper.at(trueID);
                                            res.second++;
                                        }
                                        else
                                        {
                                            averageAccuracyHelper.insert({trueID, {0,1}});
                                        }
                                    }
                                    // instance recognition
                                    if(((int)trueInstanceID) == instanceId)
                                    {
                                        numCorrectInstances++;
                                    }
                                    // global classifier
                                    if(((int)trueID) == classIdglobal)
                                    {
                                        numCorrectGlobal++;
                                    }
                                    // both correct
                                    if((int)trueID == classId && (int)trueID == classIdglobal)
                                    {
                                        numBothCorrect++;
                                    }
                                    // global correct, normal wrong
                                    if((int)trueID != classId && (int)trueID == classIdglobal)
                                    {
                                        numOnlyGlobalCorrect++;
                                    }
                                }
                            }
                        }

                        // write class id to class name mappings to summary
                        if(label_usage == LabelUsage::CLASS_ONLY || label_usage == LabelUsage::CLASS_PRIMARY)
                            summaryFile << "\n\nclass id to class name mapping:" << std::endl;
                        if(label_usage == LabelUsage::INSTANCE_PRIMARY)
                            summaryFile << "\n\ninstance id to instance name mapping (used as primary labels, i.e. classes):" << std::endl;
                        for(auto &elem : class_labels_rmap)
                        {
                            summaryFile << elem.first << ": " << elem.second << std::endl;
                        }
                        if(label_usage == LabelUsage::CLASS_PRIMARY)
                        {
                            summaryFile << "\ninstance id to instance name mapping:" << std::endl;
                            for(auto &elem : instance_labels_rmap)
                            {
                                summaryFile << elem.first << ": " << elem.second << std::endl;
                            }
                        }
                        if(label_usage == LabelUsage::INSTANCE_PRIMARY)
                        {
                            summaryFile << "\ninstance id to class id mapping:" << std::endl;
                            for(auto &elem : instance_to_class_map)
                            {
                                summaryFile << elem.first << ": " << elem.second << std::endl;
                            }
                        }

                        // write processing time details to summary
                        double time_sum = 0;
                        for(auto it : times)
                        {
                            if(it.first == "complete") continue;
                            time_sum += (it.second / 1000);
                        }
                        summaryFile << "\n\n\ncomplete time: " << times["complete"] / 1000 << " [s]" << ", sum all steps: " << time_sum << " [s]" << std::endl;
                        summaryFile << "times per step:\n";
                        summaryFile << "create flann index: " << std::setw(10) << std::setfill(' ') << times["flann"] / 1000 << " [s]" << std::endl;
                        summaryFile << "compute normals:    " << std::setw(10) << std::setfill(' ') << times["normals"] / 1000 << " [s]" << std::endl;
                        summaryFile << "compute keypoints:  " << std::setw(10) << std::setfill(' ') << times["keypoints"] / 1000 << " [s]" << std::endl;
                        summaryFile << "compute features:   " << std::setw(10) << std::setfill(' ') << times["features"] / 1000 << " [s]" << std::endl;
                        summaryFile << "cast votes:         " << std::setw(10) << std::setfill(' ') << times["voting"] / 1000 << " [s]" << std::endl;
                        summaryFile << "find maxima:        " << std::setw(10) << std::setfill(' ') << times["maxima"] / 1000 << " [s]" << std::endl;

                        float avg_pc_acc = 0;
                        for(const auto &elem : averageAccuracyHelper)
                        {
                            const std::pair<unsigned, unsigned> &p = elem.second;
                            avg_pc_acc += (float)p.first/p.second;
                        }
                        avg_pc_acc /= averageAccuracyHelper.size();

                        // complete and close summary file
                        summaryFile << std::endl << std::endl;
                        summaryFile << " Accuracy: " << ((float)numCorrectClasses/pointClouds.size())*100.0f << " %, Average per Class Accuracy: " <<
                                       avg_pc_acc*100.0f << " %" << std::endl << std::endl;
                        summaryFile << " result: " << numCorrectClasses << " of " << pointClouds.size() << " clouds classified correctly ("
                                    << ((float)numCorrectClasses/pointClouds.size())*100.0f << " %)\n";
                        summaryFile << " result: " << numCorrectInstances << " of " << pointClouds.size() << " instances recognized correctly ("
                                    << ((float)numCorrectInstances/pointClouds.size())*100.0f << " %)\n";

                        summaryFile << " result: " << numCorrectGlobal << " of " << pointClouds.size() << " clouds classified correctly with global descriptors ("
                                    << ((float)numCorrectGlobal/pointClouds.size())*100.0f << " %)\n\n";
                        summaryFile << " both correct: " << numBothCorrect << " (" << ((float)numBothCorrect/pointClouds.size())*100.0f << " %)\n";
                        summaryFile << " only global correct: " << numOnlyGlobalCorrect << " (" << ((float)numOnlyGlobalCorrect/pointClouds.size())*100.0f << " %)\n\n\n";

                        summaryFile << " Total processing time: " << timer.format(4, "%w") << " seconds \n";
                        summaryFile.close();

                    }
                    else
                    {
                        std::cerr << "number of point clouds does not match the number of groundtruth ids" << std::endl;
                        return 1;
                    }
                }
                else
                {
                    std::cerr << "number of point clouds arguments does not match the number of groundtruth id arguments" << std::endl;
                    return 1;
                }
            }
        }
        catch (const ism3d::Exception& e) {
            std::cerr << e.what() << std::endl;
            return 1;
        }
        catch (...) {
            std::cerr << "an exception occurred" << std::endl;
            return 1;
        }
    }

    return 0;
}

max_stars_repo_name: Pandinosaurus/PointCloudDonkey

max_issues_repo_name: Pandinosaurus/PointCloudDonkey

max_forks_repo_name: Pandinosaurus/PointCloudDonkey


text:
#include <iostream>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
#include <vector>
#include <string>
#include <map>

using namespace std;

void any_func(void *p){
    cout << "some operate" << endl;
}

bool bool_test(void){
    boost::shared_ptr<int> p(new int(10));
    return static_cast<bool>(p);
}

int main(){
    boost::shared_ptr<int> p(new int);
    *p = 10;
    cout << *p << endl;
    cout << "Count of p is " << p.use_count() << endl;
    int* int_ptr = new int;
    boost::shared_ptr<int> p2(p);
    *int_ptr = 20;
    cout << *p2 << endl;
    cout << "Count of p is " << p2.use_count() << endl;

    auto sp = boost::make_shared<string>("make_shared");
    auto spv= boost::make_shared<vector<int> >(10,2);
    for(auto i = spv->begin(); i != spv->end(); ++i)
        cout << *i << endl;

    typedef boost::shared_ptr<string> sp_t;
    map<sp_t, int> m;

    sp_t sp2(new string("one"));
    m[sp2] = 111;
    cout << sp << endl;     // use smart_ptr::operator<< to print pointer's value

    boost::shared_ptr<void> p3(nullptr, any_func);  // nullptr and specify deleter
    assert(bool_test());
    return 0;
}

ext: cpp


text:
// ---------------------------------------------------------------------------|
// Yuma Test Harness includes
// ---------------------------------------------------------------------------|
#include "test/support/misc-util/log-utils.h"

// ---------------------------------------------------------------------------|
// Linux includes
// ---------------------------------------------------------------------------|
#include <sys/ioctl.h>

// ---------------------------------------------------------------------------|
// Standard includes
// ---------------------------------------------------------------------------|
#include <unordered_map>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

// ---------------------------------------------------------------------------|
// Boost Test Framework
// ---------------------------------------------------------------------------|
#include <boost/test/unit_test.hpp>
#include <boost/test/results_collector.hpp>

// ---------------------------------------------------------------------------|
// File wide namespace use
// ---------------------------------------------------------------------------|
using namespace std;

// ---------------------------------------------------------------------------|
namespace
{

/** text width for result display */
const uint8_t resultWidth(6);

/** Mapping of test name to brief.  */
unordered_map<string, string> briefMap;

// ---------------------------------------------------------------------------|
/**
 * Get the result of the current test.
 *
 * \return true if the current test passed.
 */
inline bool CurrentTestPassed()
{
    using boost::unit_test::results_collector;
    using boost::unit_test::framework::current_test_case;
    using boost::unit_test::test_case;

    return results_collector.results( current_test_case().p_id ).passed();
}

// ---------------------------------------------------------------------------|
/**
 * Get the name of the current test.
 *
 * \return the name of the current test.
 */
inline string CurrentTestName()
{
    using boost::unit_test::results_collector;
    using boost::unit_test::framework::current_test_case;
    return current_test_case().p_name;
}

// ---------------------------------------------------------------------------|
inline string CurrentTestSuiteName()
{
    using boost::unit_test::results_collector;
    using boost::unit_test::framework::current_test_case;
    using boost::unit_test::framework::get;
    using boost::unit_test::test_suite;

    return get<test_suite>( current_test_case().p_parent_id ).p_name;
}

// ---------------------------------------------------------------------------|
/**
 * Add supplied brief to the mapping between test name and test brief.
 *
 * \param brief a brief description of the currently running test.
 */
void AddTestBrief( const string& brief )
{
    using boost::unit_test::framework::current_test_case;
    using boost::unit_test::test_case;

    briefMap[ CurrentTestName() ] = brief;
}

// ---------------------------------------------------------------------------|
/**
 * Get the width of the terminal
 *
 * \return the width of the terminal
 */
inline uint16_t GetTerminalWidth()
{
    struct winsize w;
    ioctl( 0, TIOCGWINSZ, &w );

    return w.ws_col;
}

/**
 * Get the width of the terminal to use for displaying text.
 *
 * \return the width of the terminal
 */
inline uint16_t GetParagraphWidth()
{
    return GetTerminalWidth() - resultWidth;
}

// ---------------------------------------------------------------------------|
/**
 * Split the supplied string across multiple lines. This function splits the
 * supplied string into words then it formats the text so that it wraps neatly
 * across multiple lines. The width of each line is determined by the
 * width of the terminal.
 *
 * \param text The text to prepare
 * \return a vector of strings, each one is one line of the text.
 */
vector<string> SplitWorker( const string& text )
{
    vector<string> lines;

    // allow space for result to be printed
    uint16_t wid = GetParagraphWidth();
    if ( text.size() > wid )
    {
        vector<string> strs;
        boost::split(strs, text, boost::is_any_of( " " ));
        ostringstream oss;
        BOOST_FOREACH( string& str, strs )
        {
            if ( oss.str().size() + str.size() > wid )
            {
                lines.push_back( oss.str() );
                oss.str("");
                oss.clear();
            }
            oss << str << " ";
        }
        lines.push_back( oss.str() );
    }
    else
    {
        lines.push_back( text );
    }

    return lines;
}

// ---------------------------------------------------------------------------|
/**
 * Format text for display.
 * This function first splits the string into pre-formatted lines,
 * delimited by '\n'. It the calls SplitWorker to format each of those
 * individual lines.
 *
 * \param text The text to prepare
 * \return a vector of strings, each one is one line of the text.
 */
vector<string> SplitText( const string& text )
{
    vector<string> rawlines;
    boost::split( rawlines, text, boost::is_any_of( "\n" ) );

    vector<string> formattedlines;
    BOOST_FOREACH( string& rawline, rawlines )
    {
        vector<string> lines = SplitWorker( rawline );
        formattedlines.insert( formattedlines.end(),
                               lines.begin(), lines.end() );
    }

    return formattedlines;
}

// ---------------------------------------------------------------------------|
/**
 * Prepare the supplied string for display. This function first splits
 * the supplied string into N lines then creates a single string
 * containing the format text.
 *
 * \param text The text to prepare
 * \return a multi-line text string for display.
 */
string FormatText( const string& text )
{
    vector<string> lines = SplitText( text );

    ostringstream oss;
    copy( lines.begin(), lines.end(), ostream_iterator<string>( oss, "\n" ) );
    return oss.str();
}

// ---------------------------------------------------------------------------|
/**
 * Display the suplied string as formatted text.
 *
 * \param text The text to display.
 */
void DisplayFormattedText( const string& text )
{
    if ( !text.empty() )
    {
        BOOST_TEST_MESSAGE( FormatText( text ) );
    }
}
} // anonymous namespace

// ---------------------------------------------------------------------------|
namespace YumaTest
{

// ---------------------------------------------------------------------------|
void DisplayTestBreak( char chr, bool force )
{
    const uint16_t terminalWidth = GetTerminalWidth();
    string txt( terminalWidth, chr );
    if ( force )
    {
        cout << GREY_BOLD << txt << DEFAULT_TEXT;
    }
    else
    {
        BOOST_TEST_MESSAGE( GREY_BOLD << txt << DEFAULT_TEXT );
    }
}

// ---------------------------------------------------------------------------|
void DisplayTestTitle( const string& title )
{
    DisplayTestBreak();

    BOOST_TEST_MESSAGE( HIGHLIGHT_ON << FormatText( title )
                        << DEFAULT_TEXT );
}

// ---------------------------------------------------------------------------|
void DisplayTestDescrption( const string& brief,
                            const string& desc,
                            const string& notes )
{
    AddTestBrief( brief );
    DisplayTestTitle( brief );
    DisplayFormattedText( desc );
    DisplayFormattedText( notes );
    DisplayCurrentTestSummary();
}

// ---------------------------------------------------------------------------|
void DisplayCurrentTestSummary( const char* highlight )
{
    uint16_t wid = GetParagraphWidth();
    vector<string> lines = SplitText( briefMap[ CurrentTestName() ] );

    auto beg = lines.begin();
    auto end = lines.end();

    cout << highlight;
    // Display all lines except the last one
    copy( beg, --end, ostream_iterator<string>( cout, "\n" ) );

    cout.setf( ios::left );
    cout << setw( wid ) << setfill( '.' ) << ( *end + " " );
    cout << DEFAULT_TEXT;
    cout.flush();
}

// ---------------------------------------------------------------------------|
void DisplayCurrentTestId( const char* highlight )
{
    cout << highlight << CurrentTestSuiteName() << "/"
         << CurrentTestName() << " : " << DEFAULT_TEXT;
}

// ---------------------------------------------------------------------------|
void DisplayCurrentTestResult()
{
    cout << HIGHLIGHT_ON;
    if ( CurrentTestPassed() )
    {
        cout << " PASS\n";
    }
    else
    {
        DisplayCurrentTestSummary();
        cout << RED_BOLD << " FAIL\n";
        DisplayCurrentTestId( RED_BOLD );
        cout << RED_BOLD << "FAILED!\n";
    }
    cout << DEFAULT_TEXT;
}

} // namespace YumaTest


text:
///////////////////////////////////////////////////////////////////////////////
// enum_macros.hpp: macros to generate an enum model
//
// Copyright 2005 Frank Laub
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ENUM_MACROS_HPP
#define BOOST_ENUM_MACROS_HPP

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <boost/preprocessor.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <cstring>

#define BOOST_ENUM_IS_COLUMN_2(i, k) \
	BOOST_PP_EQUAL(BOOST_PP_MOD(i, 2), k)

#define BOOST_ENUM_GET_COLUMN_2(r, data, i, elem) \
	BOOST_PP_IF(BOOST_ENUM_IS_COLUMN_2(i, data), BOOST_PP_IDENTITY((elem)), BOOST_PP_EMPTY)()

#define BOOST_ENUM_VISITOR1(_seq, _macro, _col) \
	BOOST_PP_SEQ_FOR_EACH_I(_macro, _, _seq)

#define BOOST_ENUM_VISITOR2(_seq, _macro, _col) \
	BOOST_PP_SEQ_FOR_EACH_I( \
		_macro, \
		_, \
		BOOST_PP_SEQ_FOR_EACH_I(BOOST_ENUM_GET_COLUMN_2, _col, _seq) \
	)

#define BOOST_ENUM_DOMAIN_ITEM(r, data, i, elem) \
	BOOST_PP_COMMA_IF(i) elem

#define BOOST_ENUM_domain(_seq, _col, _colsize) \
	enum domain \
	{ \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_DOMAIN_ITEM, _col) \
	}; \
	BOOST_STATIC_CONSTANT(index_type, size = BOOST_ENUM_size(_seq, _colsize));

#define BOOST_ENUM_size(_seq, _colsize) \
	BOOST_PP_DIV(BOOST_PP_SEQ_SIZE(_seq), _colsize)

#define BOOST_ENUM_PARSE_ITEM(r, data, i, elem) \
	if(strcmp(str, BOOST_PP_STRINGIZE(elem)) == 0) return optional(elem);

#define BOOST_ENUM_PARSE_ITEM_CASE_INSENSITIVE(r, data, i, elem) \
	if(boost::algorithm::iequals(str, BOOST_PP_STRINGIZE(elem))) return optional(elem);

#define BOOST_ENUM_get_by_name(_name, _seq, _col, _colsize) \
	static optional get_by_name(const char* str) \
	{ \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_PARSE_ITEM, _col) \
		return optional(); \
	}

#define BOOST_ENUM_get_by_name_case_insensitive(_name, _seq, _col, _colsize) \
	static optional get_by_name_case_insensitive(const char* str) \
	{ \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_PARSE_ITEM_CASE_INSENSITIVE, _col) \
		return optional(); \
	}

#define BOOST_ENUM_CASE_STRING(r, data, i, elem) \
	case elem: return BOOST_PP_STRINGIZE(elem);

#define BOOST_ENUM_names(_seq, _col, _colsize) \
	static const char* names(domain index) \
	{ \
		BOOST_ASSERT(static_cast<index_type>(index) < size); \
		switch(index) \
		{ \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_CASE_STRING, _col) \
		default: return NULL; \
		} \
	}

#define BOOST_ENUM_CASE_PART(elem) \
	case (elem):

#define BOOST_ENUM_VALUE_PART(elem) \
	return optional_value(elem);

#define BOOST_ENUM_VALUE_LINE(r, data, i, elem) \
	BOOST_PP_IF(BOOST_ENUM_IS_COLUMN_2(i, 0), \
		BOOST_ENUM_CASE_PART(elem), \
		BOOST_ENUM_VALUE_PART(elem) \
	)

#define BOOST_ENUM_values_identity() \
	typedef boost::optional<value_type> optional_value; \
	static optional_value values(domain index) \
	{ \
		if(static_cast<index_type>(index) < size) return optional_value(index); \
		return optional_value(); \
	}

#define BOOST_ENUM_values(_seq, _name_col, _value_col, _colsize) \
	typedef boost::optional<value_type> optional_value; \
	static optional_value values(domain index) \
	{ \
		switch(index) \
		{ \
		BOOST_PP_SEQ_FOR_EACH_I(BOOST_ENUM_VALUE_LINE, _, _seq) \
		default: return optional_value(); \
		} \
	}

#define BOOST_BITFIELD_names(_seq, _col, _colsize) \
	static const char* names(domain index) \
	{ \
		BOOST_ASSERT(static_cast<index_type>(index) < size); \
		switch(index) \
		{ \
		case all_mask: return "all_mask"; \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_CASE_STRING, _col) \
		default: return NULL; \
		} \
	}

#define BOOST_BITFIELD_OR_ITEM(r, data, i, elem) \
	| (elem)

#define BOOST_BITFIELD_domain(_seq, _col, _colsize) \
	enum domain \
	{ \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_DOMAIN_ITEM, _col), \
		all_mask, \
		not_mask \
	}; \
	BOOST_STATIC_CONSTANT(index_type, size = BOOST_ENUM_size(_seq, _colsize));

#define BOOST_BITFIELD_all_mask(_seq, _col, _colsize) \
	0 BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
		(_seq, BOOST_BITFIELD_OR_ITEM, _col)

#define BOOST_BITFIELD_get_by_name(_name, _seq, _col, _colsize) \
	static optional get_by_name(const char* str) \
	{ \
		if(strcmp(str, "all_mask") == 0) return optional(all_mask); \
		if(strcmp(str, "not_mask") == 0) return optional(not_mask); \
		BOOST_PP_CAT(BOOST_ENUM_VISITOR, _colsize) \
			(_seq, BOOST_ENUM_PARSE_ITEM, _col) \
		return optional(); \
	}

#define BOOST_BITFIELD_values(_seq, _name_col, _value_col, _colsize) \
	typedef boost::optional<value_type> optional_value; \
	static optional_value values(domain index) \
	{ \
		switch(index) \
		{ \
		BOOST_PP_SEQ_FOR_EACH_I(BOOST_ENUM_VALUE_LINE, _, _seq) \
		case all_mask: return optional_value(BOOST_BITFIELD_all_mask(_seq, _value_col, _colsize)); \
		case not_mask: return optional_value(~(BOOST_BITFIELD_all_mask(_seq, _value_col, _colsize))); \
		default: return optional_value(); \
		} \
	}

#define BOOST_ENUM_EX(_name, _interface, _seq) \
	class _interface _name : public boost::detail::enum_base<_name> \
	{ \
	public: \
		BOOST_ENUM_domain(_seq, 0, 1) \
		_name() {} \
		_name(domain index) : boost::detail::enum_base<_name>(index) {} \
		BOOST_ENUM_get_by_name(_name, _seq, 0, 1) \
		BOOST_ENUM_get_by_name_case_insensitive(_name, _seq, 0, 1) \
	private: \
		friend class boost::detail::enum_base<_name>; \
		BOOST_ENUM_names(_seq, 0, 1) \
		BOOST_ENUM_values_identity() \
	};

#define BOOST_ENUM(_name, _seq) BOOST_ENUM_EX(_name, , _seq)

#define BOOST_ENUM_VALUES_EX(_name, _interface, _type, _seq) \
	class _interface _name : public boost::detail::enum_base<_name, _type> \
	{ \
	public: \
		BOOST_ENUM_domain(_seq, 0, 2) \
		_name() {} \
		_name(domain index) : boost::detail::enum_base<_name, _type>(index) {} \
		BOOST_ENUM_get_by_name(_name, _seq, 0, 2) \
		BOOST_ENUM_get_by_name_case_insensitive(_name, _seq, 0, 2) \
	private: \
		friend class boost::detail::enum_base<_name, _type>; \
		BOOST_ENUM_names(_seq, 0, 2) \
		BOOST_ENUM_values(_seq, 0, 1, 2) \
	};

#define BOOST_ENUM_VALUES(_name, _type, _seq) BOOST_ENUM_VALUES_EX(_name, , _type, _seq)

#define BOOST_BITFIELD_EX(_name, _interface, _seq) \
	class _interface _name : public boost::detail::bitfield_base<_name> \
	{ \
	public: \
		BOOST_BITFIELD_domain(_seq, 0, 2) \
		_name() {} \
		_name(domain index) : boost::detail::bitfield_base<_name>(index) {} \
		BOOST_ENUM_get_by_name(_name, _seq, 0, 2) \
		BOOST_ENUM_get_by_name_case_insensitive(_name, _seq, 0, 2) \
	private: \
		friend class boost::detail::bitfield_access; \
		_name(value_type raw, int) : boost::detail::bitfield_base<_name>(raw, 0) {} \
		BOOST_BITFIELD_names(_seq, 0, 2) \
		BOOST_BITFIELD_values(_seq, 0, 1, 2) \
	};

#define BOOST_BITFIELD(_name, _seq) BOOST_BITFIELD_EX(_name, , _seq)

#define BOOST_ENUM_DOMAIN_OPERATORS(_name) \
    inline bool operator== (const _name::domain& lhs, const _name& rhs) {return rhs == lhs;} \
    inline bool operator!= (const _name::domain& lhs, const _name& rhs) {return rhs != lhs;} \
    inline bool operator< (const _name::domain& lhs, const _name& rhs) {return rhs < lhs;} \
    inline bool operator> (const _name::domain& lhs, const _name& rhs) {return rhs > lhs;} \
    inline bool operator<= (const _name::domain& lhs, const _name& rhs) {return rhs <= lhs;} \
    inline bool operator>= (const _name::domain& lhs, const _name& rhs) {return rhs >= lhs;}

#define BOOST_BITFIELD_DOMAIN_OPERATORS(_name) \
    BOOST_ENUM_DOMAIN_OPERATORS(_name) \
    inline _name operator| (const _name::domain& lhs, const _name::domain& rhs) {return _name(lhs) | rhs;} \
    inline _name operator& (const _name::domain& lhs, const _name::domain& rhs) {return _name(lhs) & rhs;}

#endif

ext: hpp

max_stars_repo_name: vagisha/pwiz

max_issues_repo_name: vagisha/pwiz

max_forks_repo_name: vagisha/pwiz


text:
/*
  Copyright (c) 2012, Matthew H. Reilly (kb1vc)
  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.

  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
  HOLDER 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 "Debug.hxx"
#include "AudioQt.hxx"
#include <alsa/asoundlib.h>

#include <boost/format.hpp>
#define _USE_MATH_DEFINES
#include <cmath>

// Use the simple setup, as recent (March 2015) changes to the
// ALSA/pulseaudio interactions have made explicit selection
// of parameters somewhat harder to figure out.  In particular,
// buffer management has become far more important.
#define ALSA_USE_SIMPLE_SETUP

namespace SoDa {
  AudioQt::AudioQt(unsigned int _sample_rate,
		   unsigned int _sample_count_hint,
		   std::string audio_sock_basename,
		   std::string audio_port_name) :
    AudioIfc(_sample_rate, _sample_count_hint, "AudioQt ALSA Interface") {

    // code is largely borrowed from equalarea.com/paul/alsa-audio.html
    setupCapture(audio_port_name);

    setupNetwork(audio_sock_basename);

    ang = 0.0;
    ang_incr = 2.0 * M_PI / 48.0;
  }

  void AudioQt::setupNetwork(std::string audio_sock_basename)
  {
    std::string sockname = audio_sock_basename + "_rxa";
    audio_rx_socket = new SoDa::UD::ServerSocket(sockname);
    audio_rx_socket->setDebug(true);
  }

  void AudioQt::setupCapture(std::string audio_port_name)
  {
    // char pcm_cap_name[] = "default"; // "hw:0,2";
    const char *pcm_cap_name = audio_port_name.c_str();
    snd_pcm_stream_t instream  = SND_PCM_STREAM_CAPTURE;
    if(snd_pcm_open(&pcm_in, pcm_cap_name, instream, 0) < 0) {
      std::cerr << boost::format("can't open Alsa PCM device [%s] for  input... Crap.\n") % pcm_cap_name;
      exit(-1);
    }

#ifdef ALSA_USE_SIMPLE_SETUP
    checkStatus(snd_pcm_set_params(pcm_in,
				   SND_PCM_FORMAT_FLOAT,
				   SND_PCM_ACCESS_RW_INTERLEAVED,
				   1,
				   sample_rate,
				   1,
				   500000), // 100000),
		"Failed to do simple set params for output.", true);
#else
    setupParams(pcm_in, hw_in_params);
#endif
  }

  void AudioQt::setupParams(snd_pcm_t * dev, snd_pcm_hw_params_t *  & hw_params_ptr)
  {
    snd_pcm_hw_params_t * hw_paramsp;
    std::lock_guard<std::mutex> mt_lock(alsa_mutex);

    checkStatus(snd_pcm_hw_params_malloc(&hw_paramsp),
		"ALSA failed to allocate hardware params block",
		true);

    hw_params_ptr = hw_paramsp;

    checkStatus(snd_pcm_hw_params_any (dev, hw_paramsp), "ALSA failed in setupParams init parm block", true);

    checkStatus(snd_pcm_hw_params_set_access (dev, hw_paramsp, SND_PCM_ACCESS_RW_INTERLEAVED),
		"ALSA failed in setupParams set access", true);

    checkStatus(snd_pcm_hw_params_set_format (dev, hw_paramsp, SND_PCM_FORMAT_FLOAT),
		"ALSA failed in setupParams set format", true);

    checkStatus(snd_pcm_hw_params_set_rate_near (dev, hw_paramsp, &sample_rate, 0),
		"ALSA failed in setupParams set sample rate", true);

    checkStatus(snd_pcm_hw_params_set_channels (dev, hw_paramsp, 1),
		"setupParams set number of channels", true);

    checkStatus(snd_pcm_hw_params_set_buffer_size (dev, hw_paramsp,
						   sample_count_hint * datatype_size),
		"ALSA failed in setupParams set buffer size", true);

    checkStatus(snd_pcm_hw_params (dev, hw_paramsp),
		"ALSA failed in setupParams set parameter block", true);

    checkStatus(snd_pcm_prepare (dev),
		"ALSA failed in setupParams prepare audio interface", true);
  }

  bool AudioQt::recvBufferReady(unsigned int len) {
      std::lock_guard<std::mutex> lock(alsa_mutex);
      return recvBufferReady_priv(len);
  }

  bool AudioQt::recvBufferReady_priv(unsigned int len)  {
    snd_pcm_sframes_t sframes_ready = snd_pcm_avail(pcm_in);

    if(sframes_ready == -EBADFD) {
      debugMsg("recvBufferReady got EBADFD, tried recovery");
      return false;
    }
    else if(sframes_ready == -EPIPE) {
      // we got an under-run... just ignore it.
      int err;
      std::cerr << "A";  // but put a goat dropping on the console
      if((err = snd_pcm_recover(pcm_in, sframes_ready, 1)) < 0) {
	checkStatus(err, "recvBufferReady got EPIPE, tried recovery", false);
      }
      sframes_ready = snd_pcm_avail(pcm_in);
    }

    if(sframes_ready < 0) {
      checkStatus(sframes_ready, "recvBufferReady", false);
    }

    return sframes_ready >= len;
  }

  bool AudioQt::sendBufferReady(unsigned int len)  {
    return true;
  }

  int AudioQt::send(void * buf, unsigned int len, bool when_ready) {
    int ret;
#if 0
    float *fbuf = (float*) buf;
    int l = len >> 2;
    for(int i = 0; i < l; i++) {
      fbuf[i] = sin(ang);
      ang += ang_incr;
      if(ang > (2.0 * M_PI)) {
	ang -= 2.0 * M_PI;
      }
    }
#endif
    ret = audio_rx_socket->put(buf, len, false);

    return ret;
  }

  int AudioQt::recv(void * buf, unsigned int len, bool when_ready) {
    int err;
    int olen = len;
    int loopcount = 0;
    {
      std::lock_guard<std::mutex> mt_lock(alsa_mutex);

      if(when_ready && !recvBufferReady_priv(len)) return 0;

      char * cbuf = (char *) buf;
      while(1) {
	loopcount++;
	err = snd_pcm_readi(pcm_in, cbuf, len);

	if(err == (int)len) {
	  break;
	}
	else if(err == -EAGAIN) continue;
	else if(err < 0) {
	  checkStatus(err, "recv", true);
	}
	else if(err != (int)len) {
	  len -= err;
	  cbuf += (err * datatype_size);
	}
      }
    }
    return olen;
  }
}

ext: cxx