SOUND4 x1.CLOUD Library [1.5.0]
sound4cl-pipe.cpp
Go to the documentation of this file.
1 
6 #include <unistd.h>
7 #include <iostream>
8 #include <strings.h>
9 #include <sys/types.h>
10 #include <filesystem>
11 #include <fstream>
12 #include <sstream>
13 #if defined(_WIN32) || defined(WIN32)
14  #include <io.h>
15  #include <fcntl.h>
16 #endif
17 
18 #include "sound4cl.hpp"
19 
20 // --------------------------------------------------------------
60 std::string GetEnv(const std::string& name)
61 {
62  char *data=getenv(name.c_str());
63  if (!data) return {};
64  return std::string(data);
65 }
66 
67 
68 // Reads from stdin, write to stdout
70 {
71 bool stopthread=false;
72 
73  #if defined(_WIN32) || defined(WIN32)
74  // Windows: The stdin, stdout, and stderr streams always open in text mode by default
75  _setmode(_fileno(stdin), _O_BINARY);
76  _setmode(_fileno(stdout), _O_BINARY);
77  #endif
78 
80  size_t input_sample_count = instance.GetChunkFrames() * processor.GetChannelCount();
81  size_t output_sample_count = instance.GetChunkFrames() * processor.GetChannelCount();
82  while (!stopthread)
83  {
84  // Read a chunk from stdin
85  if (std::fread(instance.GetBufferIn(), sizeof(float), input_sample_count, stdin) != input_sample_count) {
86  std::cerr << "ProcessLoop: input stopped"<< std::endl;
87  stopthread=true;
88  break;
89  }
90  if (stopthread) break;
91  // Process it
92  instance.ProcessAudio();
93  // Write it to stdout
94  if (fwrite(instance.GetBufferOut(), sizeof(float), output_sample_count, stdout) != output_sample_count) {
95  std::cerr << "Failed to write audio output" << std::endl;
96  stopthread=true;
97  }
98  }
100 }
101 
103 class MyPresetManager : public sound4::CPresetLoader {
104 public:
105  MyPresetManager() = default;
106  virtual ~MyPresetManager() = default;
107 
108  bool SetupPath(const std::filesystem::path& a_preset_path)
109  {
110  m_preset_path=a_preset_path;
111  if ( !std::filesystem::exists(m_preset_path ) ) {
112  return false;
113  }
114  std::error_code ec;
115  if ( !std::filesystem::is_directory(m_preset_path, ec) ) {
116  return false;
117  }
118  return true;
119  }
120  virtual bool IsReadOnly() override { return false; };
121  virtual bool Exists(const std::filesystem::path &name) override
122  {
123  std::error_code ec;
124  return std::filesystem::exists(GetRealPath(name), ec);
125  }
126  virtual bool Remove(const std::filesystem::path &name) override
127  {
128  std::error_code ec;
129  return std::filesystem::remove(GetRealPath(name), ec);
130  }
131  virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to) override
132  {
133  std::error_code ec;
134  std::filesystem::rename(GetRealPath(from), GetRealPath(to), ec);
135  return (!ec);
136  }
137  virtual std::vector<std::filesystem::path> GetAll() override
138  {
139  std::vector<std::filesystem::path> list;
140  for (const auto & entry : std::filesystem::directory_iterator(m_preset_path.c_str(), std::filesystem::directory_options::skip_permission_denied)) {
141  if (entry.is_regular_file()) {
142  list.push_back(entry.path().lexically_relative(m_preset_path));
143  }
144  }
145  return list;
146  }
147  virtual std::string Read(const std::filesystem::path &filename) override
148  {
149  std::ifstream f(GetRealPath(filename));
150  if ( f.fail() ) {
151  return std::string();
152  }
153  std::ostringstream ss;
154  ss << f.rdbuf();
155  return ss.str();
156  }
157  virtual bool Write(const std::filesystem::path &filename, const std::string &content) override
158  {
159  std::ofstream f(GetRealPath(filename));
160  if ( f.fail() ) {
161  return false;
162  }
163  f << content;
164  if ( f.fail() ) {
165  return false;
166  }
167  return true;
168  }
169 private:
170  std::filesystem::path m_preset_path;
171  std::filesystem::path GetRealPath(const std::filesystem::path &name)
172  {
173  return m_preset_path / name;
174  }
175 };
177 
178 int main(int argc, const char **argv)
179 {
180  int listen_port = 8080;
181  auto store_path_str=GetEnv("S4STORE_PATH");
183  std::string libname = "libsound4.x1.cloud.so";
185 
186 
187  // Get credentials from environment
188  auto LoginKey=GetEnv("S4LOGINKEY");
189  if (LoginKey.empty()) {
190  LoginKey=GetEnv("S4USERID");
191  }
192  auto RadioName=GetEnv("RADIO_NAME");
193  auto KeyId=GetEnv("ACCESS_KEY_ID");
194  auto AccessKey=GetEnv("ACCESS_KEY_SECRET");
195 
196  const char *progname=argv[0];
197  for (int n=1;n<argc;n++) {
198  std::string arg = argv[n];
199  if (arg=="-p" || arg=="--port") {
200  if (argc<n+1) {
201  std::cerr << "--port needs a number"<< std::endl;
202  return 1;
203  }
204  n++;
205  listen_port=atoi(argv[n]);
206  } else if (arg=="-l" || arg=="--lib") {
207  if (argc<n+1) {
208  std::cerr << "--port needs a number"<< std::endl;
209  return 1;
210  }
211  n++;
212  libname=argv[n];
213  } else if (arg=="-h" || arg=="--help") {
214  std::cerr << "Usage: " << progname << " [-p port] [-l libname.so]"<<std::endl;;
215  std::cerr << " Reads audio from stdin and return processed audio in stdout" << std::endl;
216  std::cerr << " -l, --lib : library to load ["<<libname<<"]" << std::endl;
217  std::cerr << " -p, --port : port for web server ["<<listen_port<<"]" << std::endl;
218  std::cerr << std::endl;
219  std::cerr << "Environment:"<< std::endl;;
220  std::cerr << " - S4STORE_PATH : path to store config [default: (no storage)]"<< std::endl;;
221  std::cerr << " - S4LOGINKEY : SOUND4 Login key (or S4USERID)"<< std::endl;;
222  std::cerr << " - RADIO_NAME : SOUND4 Radio Name"<< std::endl;;
223  std::cerr << " - ACCESS_KEY_ID : SOUND4 Access Key ID"<< std::endl;;
224  std::cerr << " - ACCESS_KEY_SECRET : SOUND4 Access Key Secret"<< std::endl;
225  std::cerr << std::endl;
226  std::cerr << "Example:"<< std::endl;
227  std::cerr << " ffmpeg -re -i file.wav -ar 48000 -ac 2 -f f32le - | "<<progname<<" | ffplay -f f32le -ar 48000 -ac 2 -i -" << std::endl;;
228  #if defined(_WIN32) || defined(WIN32)
229  std::cerr << " ffmpeg -f dshow -i audio=\"Microphone\" -ar 48000 -ac 2 -f f32le - | "<<progname<<" | ffplay -f f32le -ar 48000 -ac 2 -i -" << std::endl;;
230  #else
231  std::cerr << " ffmpeg -f pulse -i default -ar 48000 -ac 2 -f f32le - | "<<progname<<" | ffplay -f f32le -ar 48000 -ac 2 -i -" << std::endl;;
232  #endif
233  return 0;
234  } else {
235  std::cerr << "unknown argument '"<<arg<<"'"<< std::endl;
236  return 1;
237  }
238  }
239 
240 
242  sound4::CProcessor processor;
243  if (!processor.Load(libname)) {
244  std::cerr << "Failed to load processing library" << std::endl;
245  return 1;
246  }
248 
249  if (LoginKey.empty() || RadioName.empty() || KeyId.empty() || AccessKey.empty()) {
250  std::cerr << "Missing credentials in environment" << std::endl;
251  return 1;
252  }
253  std::filesystem::path store_path;
254  if (!store_path_str.empty()) {
255  store_path = std::filesystem::path(store_path_str);
256  if (!std::filesystem::exists(store_path) || !std::filesystem::is_directory(store_path)) {
257  std::cerr << "Storage folder '"<<store_path.c_str()<<"' is not a valid directory" << std::endl;
258  return 1;
259  }
260  }
261 
263  processor.SetLogSeverity(sound4::verbose5);
264  processor.SetLoggerCallback([](sound4::LogSeverity severity,const std::string& msg) {
265  std::cerr << msg << std::endl;
266  });
267 
268  sound4::CInstance instance(processor);
269  instance.SetParam("ADMIN_USER","admin");
270  instance.SetParam("ADMIN_SECRET","admin");
272 
274  MyPresetManager preset_manager;
275  if (!store_path.empty()) {
276  if (!preset_manager.SetupPath(store_path)) {
277  std::cerr << "Failed to setup the custom preset manager on path " << store_path.c_str() << std::endl;
278  return 1;
279  }
280  instance.SetPresetManager(&preset_manager);
281  }
283 
284  std::cerr << "Creating" << std::endl;
286  if (!instance.Create(LoginKey, RadioName, KeyId, AccessKey, {})) {
287  std::cerr << "Failed to create the processing instance" << std::endl;
288  return 1;
289  }
291 
292  std::cerr << "Starting web server" << std::endl;
294  if (!instance.StartWebServer(listen_port,0)) {
295  std::cerr << "Failed to create the web server on port " << listen_port << std::endl;
296  return 1;
297  }
299 
300  {
302  auto client = instance.NewClient();
303  auto answer = client->ProcessJson(R"JSON({"get":{"processorname":null}})JSON");
304  std::cerr << "Request for processor name returned "<<answer<<std::endl;
306  }
307 
308  ProcessLoop(instance, processor);
309 
310  std::cerr << "Stopping now" << std::endl;
311  instance.Stop();
312 
313  std::cerr << "End" << std::endl;
314  return 0;
315 }
[Custom preset manager]
virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to) override
virtual ~MyPresetManager()=default
virtual bool Exists(const std::filesystem::path &name) override
virtual bool IsReadOnly() override
virtual bool Write(const std::filesystem::path &filename, const std::string &content) override
MyPresetManager()=default
virtual bool Remove(const std::filesystem::path &name) override
virtual std::string Read(const std::filesystem::path &filename) override
bool SetupPath(const std::filesystem::path &a_preset_path)
virtual std::vector< std::filesystem::path > GetAll() override
Instance handling class.
Definition: sound4cl.hpp:750
bool Create(const std::string &LoginKey, const std::string &RadioName, const std::string &Access_Key_ID, const std::string &Access_Key_Secret, const std::filesystem::path &save_path, int json_port=0, unsigned int frames_per_chunk=0)
Definition: sound4cl.hpp:854
std::shared_ptr< CClient > NewClient()
Definition: sound4cl.hpp:1265
float * GetBufferIn()
Definition: sound4cl.hpp:1128
void SetPresetManager(CPresetLoader *preset_manager)
Definition: sound4cl.hpp:821
unsigned int GetChunkFrames()
Definition: sound4cl.hpp:900
void SetParam(const std::string &name, const std::string &value)
Definition: sound4cl.hpp:783
bool StartWebServer(int http_port, int https_port=0)
Definition: sound4cl.hpp:1020
float * GetBufferOut()
Definition: sound4cl.hpp:1144
Custom preset handler helper.
Definition: sound4cl.hpp:730
Dynamic library interface.
Definition: sound4cl.hpp:270
bool Load(const std::filesystem::path &filepath)
Loads the library.
Definition: sound4cl.hpp:379
void SetLogSeverity(LogSeverity severity)
Definition: sound4cl.hpp:688
void SetLoggerCallback(log_cb_t cb)
Definition: sound4cl.hpp:694
unsigned int GetChannelCount()
Definition: sound4cl.hpp:625
const LogSeverity verbose5
Definition: sound4cl.hpp:247
int main(int argc, const char **argv)
[Custom preset manager]
std::string GetEnv(const std::string &name)
void ProcessLoop(sound4::CInstance &instance, sound4::CProcessor &processor)
C++ wrapper for dynamic loading library.
sound4cl_LogSeverity
Definition: sound4cl_cdef.h:41