Close

add the subprocess function

A project log for DJmixer

This is a project of building DJmixer using raspberry pi with four ultrasonic sensors to playback and loop the music, and change the volumn

ten000hoursTen000hours 04/14/2019 at 21:580 Comments

To play the music in the background, we add the subprocess function to call the music playback while the main function is still running to check the distance data from sensor in order to switch the music.  when the distance reach the given range, the main function would create the subprocess to initial the music play thread.

class Popen
{
public:
  friend struct detail::ArgumentDeducer;
  friend class detail::Child;

  template <typename... Args>
  Popen(const std::string& cmd_args, Args&& ...args):
    args_(cmd_args)
  {
    vargs_ = util::split(cmd_args);
    init_args(std::forward<Args>(args)...);

    // Setup the communication channels of the Popen class
    stream_.setup_comm_channels();

    if (!defer_process_start_) execute_process();
  }

  template <typename... Args>
  Popen(std::initializer_list<const char*> cmd_args, Args&& ...args)
  {
    vargs_.insert(vargs_.end(), cmd_args.begin(), cmd_args.end());
    init_args(std::forward<Args>(args)...);

    // Setup the communication channels of the Popen class
    stream_.setup_comm_channels();

    if (!defer_process_start_) execute_process();
  }

  void start_process() noexcept(false);

  int pid() const noexcept { return child_pid_; }

  int retcode() const noexcept { return retcode_; }

  int wait() noexcept(false);

  int poll() noexcept(false);

  // Does not fail, Caller is expected to recheck the
  // status with a call to poll()
  void kill(int sig_num = 9);

  void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }

  void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }

  int send(const char* msg, size_t length)
  { return stream_.send(msg, length); }

  int send(const std::vector<char>& msg)
  { return stream_.send(msg); }

  std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length)
  {
    auto res = stream_.communicate(msg, length);
    retcode_ = wait();
    return res;
  }

  std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg)
  {
    auto res = stream_.communicate(msg);
    retcode_ = wait();
    return res;
  }

  std::pair<OutBuffer, ErrBuffer> communicate()
  {
    return communicate(nullptr, 0);
  }

  FILE* input()  { return stream_.input(); }
  FILE* output() { return stream_.output();}
  FILE* error()  { return stream_.error(); }

  /// Stream close APIs
  void close_input()  { stream_.input_.reset();  }
  void close_output() { stream_.output_.reset(); }
  void close_error()  { stream_.error_.reset();  }

private:
  template <typename F, typename... Args>
  void init_args(F&& farg, Args&&... args);
  void init_args();
  void populate_c_argv();
  void execute_process() noexcept(false);

private:
  detail::Streams stream_;

  bool defer_process_start_ = false;
  bool close_fds_ = false;
  bool has_preexec_fn_ = false;
  bool shell_ = false;
  bool session_leader_ = false;

  std::string exe_name_;
  std::string cwd_;
  std::map<std::string, std::string> env_;
  preexec_func preexec_fn_;

  // Command in string format
  std::string args_;
  // Comamnd provided as sequence
  std::vector<std::string> vargs_;
  std::vector<char*> cargv_;

  bool child_created_ = false;
  // Pid of the child process
  int child_pid_ = -1;

  int retcode_ = -1;
};

inline void Popen::init_args() {
  populate_c_argv();
}

template <typename F, typename... Args>
inline void Popen::init_args(F&& farg, Args&&... args)
{
  detail::ArgumentDeducer argd(this);
  argd.set_option(std::forward<F>(farg));
  init_args(std::forward<Args>(args)...);
}

inline void Popen::populate_c_argv()
{
  cargv_.clear();
  cargv_.reserve(vargs_.size() + 1);
  for (auto& arg : vargs_) cargv_.push_back(&arg[0]);
  cargv_.push_back(nullptr);
}

Discussions