Ardour  9.0-pre0-386-g96ef4d20f2
cmdpipe_writer.h
Go to the documentation of this file.
1 #ifndef AUDIOGRAPHER_CMDPIPE_WRITER_H
2 #define AUDIOGRAPHER_CMDPIPE_WRITER_H
3 
4 #include <string>
5 
6 #include <glib.h>
7 
9 #include "audiographer/sink.h"
10 #include "audiographer/types.h"
11 
12 #include "pbd/gstdio_compat.h"
13 #include "pbd/signals.h"
14 
15 #include "ardour/system_exec.h"
16 #include "ardour/export_failed.h"
17 
18 namespace AudioGrapher
19 {
20 
24 template <typename T = DefaultSampleType>
26  : public Sink<T>
27  , public Throwing<>
28  , public FlagDebuggable<>
29 {
30 public:
31  CmdPipeWriter (ARDOUR::SystemExec* proc, std::string const& path, int tmp_fd = -1, gchar* tmp_file = 0)
32  : samples_written (0)
33  , _proc (proc)
34  , _path (path)
35  , _tmp_fd (tmp_fd)
36  , _tmp_file (tmp_file)
37  {
39 
40  if (tmp_fd >= 0) {
41  ;
42  } else if (proc->start (ARDOUR::SystemExec::ShareWithParent)) {
43  throw ARDOUR::ExportFailed ("External encoder (ffmpeg) cannot be started.");
44  }
45  proc->Terminated.connect_same_thread (exec_connections, std::bind (&CmdPipeWriter::encode_complete, this));
46  }
47 
48  virtual ~CmdPipeWriter () {
49  delete _proc;
50  if (_tmp_fd >= 0) {
51  ::close (_tmp_fd);
52  }
53  if (_tmp_file) {
54  g_unlink (_tmp_file);
55  g_free (_tmp_file);
56  }
57  }
58 
61 
62  void close (void)
63  {
64  _proc->terminate ();
65  }
66 
67  virtual void process (ProcessContext<T> const & c)
68  {
69  check_flags (*this, c);
70 
71  if (_tmp_fd < 0 && (!_proc || !_proc->is_running())) {
72  throw Exception (*this, "Target encoder process is not running");
73  }
74 
75  const size_t bytes_per_sample = sizeof (T);
76  samplecnt_t written;
77  if (_tmp_fd >= 0) {
78  written = write (_tmp_fd, (const void*) c.data(), c.samples() * bytes_per_sample) / bytes_per_sample;
79  } else {
80  written = _proc->write_to_stdin ((const void*) c.data(), c.samples() * bytes_per_sample) / bytes_per_sample;
81  }
82 
83  samples_written += written;
84 
85  if (throw_level (ThrowProcess) && written != c.samples()) {
86  throw Exception (*this, "Could not write data to output file");
87  }
88 
90  if (_tmp_fd >= 0) {
91  ::close (_tmp_fd);
92  _tmp_fd = -1;
94  throw ARDOUR::ExportFailed ("External encoder (ffmpeg) cannot be started.");
95  }
96  } else {
97  _proc->close_stdin ();
98  }
99  _proc->wait ();
100  }
101  }
102 
103  using Sink<T>::process;
104 
105  PBD::Signal<void(std::string)> FileWritten;
106 
107 private:
108  CmdPipeWriter (CmdPipeWriter const & other) {}
109 
112  std::string _path;
113  int _tmp_fd;
114  gchar* _tmp_file;
115 
116  void encode_complete () {
117  if (_tmp_file) {
118  g_unlink (_tmp_file);
119  g_free (_tmp_file);
120  _tmp_file = NULL;
121  }
122  FileWritten (_path);
123  }
124 
126 };
127 
128 } // namespace
129 
130 #endif
131 
int start(StdErrMode stderr_mode=IgnoreAndClose)
samplecnt_t get_samples_written() const
CmdPipeWriter(CmdPipeWriter const &other)
virtual void process(ProcessContext< T > const &c)
CmdPipeWriter(ARDOUR::SystemExec *proc, std::string const &path, int tmp_fd=-1, gchar *tmp_file=0)
PBD::Signal< void(std::string)> FileWritten
PBD::ScopedConnectionList exec_connections
ARDOUR::SystemExec * _proc
A debugging class for nodes that support a certain set of flags.
void check_flags(SelfType &self, ProcessContext< ContextType > context)
Prints debug output if context contains flags that are not supported by this class.
void add_supported_flag(Flag flag)
Adds a flag to the set of flags supported.
bool has_flag(Flag flag) const
T const * data() const
data points to the array of data to process
samplecnt_t const & samples() const
samples tells how many samples the array pointed by data contains
bool throw_level(ThrowLevel level)
Definition: throwing.h:47
int wait(int options=0)
PBD::Signal< void()> Terminated
size_t write_to_stdin(std::string const &d, size_t len=0)
@ ThrowProcess
Process cycle level stuff.
Definition: throwing.h:23