SOUND4 x1.CLOUD Library [1.5.0]
sound4.x1.cloud-pipe-dyn.cpp
Go to the documentation of this file.
1 
4 #include <unistd.h>
5 #include <iostream>
6 #include <strings.h>
7 #include <sys/types.h>
8 #include <filesystem>
9 #include <fstream>
10 #include <sstream>
11 #if defined(_WIN32) || defined(WIN32)
12  #include <io.h>
13  #include <fcntl.h>
14 #endif
15 
16 #include "sound4.x1.cloud_dyn.hpp"
17 
18 // --------------------------------------------------------------
51 std::string GetEnv(const std::string& name)
52 {
53  char *data=getenv(name.c_str());
54  if (!data) return {};
55  return std::string(data);
56 }
57 
58 
59 // Reads from stdin, write to stdout
61 {
62 bool stopthread=false;
63 
64  #if defined(_WIN32) || defined(WIN32)
65  // Windows: The stdin, stdout, and stderr streams always open in text mode by default
66  _setmode(_fileno(stdin), _O_BINARY);
67  _setmode(_fileno(stdout), _O_BINARY);
68  #endif
69 
71  while (!stopthread)
72  {
73  // Read a chunk from stdin
74  if (std::fread(instance.GetBufferIn().data(), sizeof(float), sound4::cloudx1::dyn::InputSampleSize, stdin) != sound4::cloudx1::dyn::InputSampleSize) {
75  std::cerr << "ProcessLoop: input stopped"<< std::endl;
76  stopthread=true;
77  break;
78  }
79  if (stopthread) break;
80  // Process it
81  instance.ProcessAudio();
82  // Write it to stdout
83  if (fwrite(instance.GetBufferOut().data(), sizeof(float), sound4::cloudx1::dyn::OutputSampleSize, stdout) != sound4::cloudx1::dyn::OutputSampleSize) {
84  std::cerr << "Failed to write audio output" << std::endl;
85  stopthread=true;
86  }
87  }
89 }
90 
91 void Usage(const char *progname, sound4::cloudx1::dyn::CDynLib &dynlib)
92 {
93  std::cerr << "Usage: " << progname << std::endl;;
94  std::cerr << " Reads audio from stdin and return processed audio in stdout" << std::endl;
95  std::cerr << "Environment:"<< std::endl;;
96  std::cerr << " - S4STORE_PATH : path to store config [default: (no storage)]"<< std::endl;;
97  std::cerr << " - S4LOGINKEY : SOUND4 Login key (or S4USERID)"<< std::endl;;
98  std::cerr << " - RADIO_NAME : SOUND4 Radio Name"<< std::endl;;
99  std::cerr << " - ACCESS_KEY_ID : SOUND4 Access Key ID"<< std::endl;;
100  std::cerr << " - ACCESS_KEY_SECRET : SOUND4 Access Key Secret"<< std::endl;;
101  if (dynlib.IsOk()) {
102  std::cerr << std::endl;
103  std::cerr << "Example:"<< std::endl;
104  std::cerr << "ffmpeg -re -i file.wav -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -i -" << std::endl;;
105  #if defined(_WIN32) || defined(WIN32)
106  std::cerr << "ffmpeg -f dshow -i audio=\"Microphone\" -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -i -" << std::endl;;
107  #else
108  std::cerr << "ffmpeg -f pulse -i default -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<dynlib.GetSampleRate()<<" -ac "<<dynlib.GetChannelCount()<<" -i -" << std::endl;;
109  #endif
110  }
111 }
112 
113 void MyLogger(sound4::cloudx1::dyn::LogSeverity severity,const std::string& msg)
114 {
115  std::cerr << msg << std::endl;
116 }
117 
120 public:
121  MyPresetManager() = default;
122  virtual ~MyPresetManager() = default;
123 
124  bool SetupPath(const std::filesystem::path& a_preset_path)
125  {
126  m_preset_path=a_preset_path;
127  if ( !std::filesystem::exists(m_preset_path ) ) {
128  return false;
129  }
130  std::error_code ec;
131  if ( !std::filesystem::is_directory(m_preset_path, ec) ) {
132  return false;
133  }
134  return true;
135  }
136  virtual bool IsReadOnly() override { return false; };
137  virtual bool Exists(const std::filesystem::path &name) override
138  {
139  std::error_code ec;
140  return std::filesystem::exists(GetRealPath(name), ec);
141  }
142  virtual bool Remove(const std::filesystem::path &name) override
143  {
144  std::error_code ec;
145  return std::filesystem::remove(GetRealPath(name), ec);
146  }
147  virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to) override
148  {
149  std::error_code ec;
150  std::filesystem::rename(GetRealPath(from), GetRealPath(to), ec);
151  return (!ec);
152  }
153  virtual std::vector<std::filesystem::path> GetAll() override
154  {
155  std::vector<std::filesystem::path> list;
156  for (const auto & entry : std::filesystem::directory_iterator(m_preset_path.c_str(), std::filesystem::directory_options::skip_permission_denied)) {
157  if (entry.is_regular_file()) {
158  list.push_back(entry.path().lexically_relative(m_preset_path));
159  }
160  }
161  return list;
162  }
163  virtual std::string Read(const std::filesystem::path &filename) override
164  {
165  std::ifstream f(GetRealPath(filename));
166  if ( f.fail() ) {
167  return std::string();
168  }
169  std::ostringstream ss;
170  ss << f.rdbuf();
171  return ss.str();
172  }
173  virtual bool Write(const std::filesystem::path &filename, const std::string &content) override
174  {
175  std::ofstream f(GetRealPath(filename));
176  if ( f.fail() ) {
177  return false;
178  }
179  f << content;
180  if ( f.fail() ) {
181  return false;
182  }
183  return true;
184  }
185 private:
186  std::filesystem::path m_preset_path;
187  std::filesystem::path GetRealPath(const std::filesystem::path &name)
188  {
189  return m_preset_path / name;
190  }
191 };
193 
194 int main(int argc, const char **argv)
195 {
196 #if (CLOUDX1_HAS_WEBSERVER)
197  int listen_port = 8080;
198 #endif // (CLOUDX1_HAS_WEBSERVER)
199  auto store_path_str=GetEnv("S4STORE_PATH");
200 
201  // Get credentials from environment
202  auto LoginKey=GetEnv("S4LOGINKEY");
203  if (LoginKey.empty()) {
204  LoginKey=GetEnv("S4USERID");
205  }
206  auto RadioName=GetEnv("RADIO_NAME");
207  auto KeyId=GetEnv("ACCESS_KEY_ID");
208  auto AccessKey=GetEnv("ACCESS_KEY_SECRET");
209 
210  const char *progname=argv[0];
211 
212 
215  if (!dynlib.Load()) {
216  std::cerr << "Failed to load processing library" << std::endl;
217  return 1;
218  }
220 
221  if (argc>1) {
222  if ((strcasecmp(argv[1],"-h")==0) || (strcasecmp(argv[1],"--help")==0)) {
223  Usage(progname,dynlib);
224  return 0;
225  }
226  }
227  if (LoginKey.empty() || RadioName.empty() || KeyId.empty() || AccessKey.empty()) {
228  std::cerr << "Missing credentials in environment" << std::endl;
229  Usage(progname,dynlib);
230  return 1;
231  }
232  std::filesystem::path store_path;
233  if (!store_path_str.empty()) {
234  store_path = std::filesystem::path(store_path_str);
235  if (!std::filesystem::exists(store_path) || !std::filesystem::is_directory(store_path)) {
236  std::cerr << "Storage folder '"<<store_path.c_str()<<"' is not a valid directory" << std::endl;
237  Usage(progname,dynlib);
238  return 1;
239  }
240  }
241 
243  sound4::cloudx1::dyn::SetLogSeverity(dynlib, verbose5);
244  sound4::cloudx1::dyn::SetLoggerCallback(dynlib, MyLogger);
245 
246  sound4::cloudx1::dyn::CInstance instance(dynlib);
247  instance.SetParam("ADMIN_USER","admin");
248  instance.SetParam("ADMIN_SECRET","admin");
250 
252  MyPresetManager preset_manager;
253  if (!store_path.empty()) {
254  if (!preset_manager.SetupPath(store_path)) {
255  std::cerr << "Failed to setup the custom preset manager on path " << store_path.c_str() << std::endl;
256  return 1;
257  }
258  instance.SetPresetManager(&preset_manager);
259  }
261 
262  std::cerr << "Creating" << std::endl;
264  if (!instance.Create(LoginKey, RadioName, KeyId, AccessKey, {})) {
265  std::cerr << "Failed to create the processing instance" << std::endl;
266  return 1;
267  }
269 
270 #if (CLOUDX1_HAS_WEBSERVER)
271  std::cerr << "Starting web server" << std::endl;
273  if (!instance.StartWebServer(listen_port,0)) {
274  std::cerr << "Failed to create the web server on port " << listen_port << std::endl;
275  return 1;
276  }
278 #endif // (CLOUDX1_HAS_WEBSERVER)
279 
280  {
282  auto client = instance.NewClient();
283  auto answer = client->ProcessJson(R"JSON({"get":{"processorname":null}})JSON");
284  std::cerr << "Request for processor name returned "<<answer<<std::endl;
286  }
287 
288  ProcessLoop(instance);
289 
290  std::cerr << "Stopping now" << std::endl;
291  instance.Stop();
292 
293  std::cerr << "End" << std::endl;
294  return 0;
295 }
[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
Dynamic library interface.
bool Load(const std::filesystem::path &path={})
Loads the library.
helper::DynFuncHolder< decltype(cloudx1_GetChannelCount) > GetChannelCount
helper::DynFuncHolder< decltype(cloudx1_GetSampleRate) > GetSampleRate
bool IsOk() const
Check if the library was loaded correctly.
void SetPresetManager(CPresetLoader *preset_manager)
void SetParam(const std::string &name, const std::string &value)
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=64)
std::array< float, OutputSampleSize > & GetBufferOut()
std::array< float, InputSampleSize > & GetBufferIn()
std::shared_ptr< CClient > NewClient()
bool StartWebServer(int http_port, int https_port=0)
cloudx1_LogSeverity
@ verbose5
int main(int argc, const char **argv)
[Custom preset manager]
std::string GetEnv(const std::string &name)
void Usage(const char *progname, sound4::cloudx1::dyn::CDynLib &dynlib)
void ProcessLoop(sound4::cloudx1::dyn::CInstance &instance)
void MyLogger(sound4::cloudx1::dyn::LogSeverity severity, const std::string &msg)
C++ wrapper for dynamic loading library.