SOUND4 x1.CLOUD Library [1.5.6]
Loading...
Searching...
No Matches
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
17
18// --------------------------------------------------------------
52std::string GetEnv(const std::string& name)
53{
54 char *data=getenv(name.c_str());
55 if (!data) return {};
56 return std::string(data);
57}
58
59
60// Reads from stdin, write to stdout
62{
63bool stopthread=false;
64
65 #if defined(_WIN32) || defined(WIN32)
66 // Windows: The stdin, stdout, and stderr streams always open in text mode by default
67 _setmode(_fileno(stdin), _O_BINARY);
68 _setmode(_fileno(stdout), _O_BINARY);
69 #endif
70
72 while (!stopthread)
73 {
74 // Read a chunk from stdin
75 if (std::fread(instance.GetBufferIn().data(), sizeof(float), sound4::cloudx1::dyn::InputSampleSize, stdin) != sound4::cloudx1::dyn::InputSampleSize) {
76 std::cerr << "ProcessLoop: input stopped"<< std::endl;
77 stopthread=true;
78 break;
79 }
80 if (stopthread) break;
81 // Process it
82 instance.ProcessAudio();
83 // Write it to stdout
84 if (fwrite(instance.GetBufferOut().data(), sizeof(float), sound4::cloudx1::dyn::OutputSampleSize, stdout) != sound4::cloudx1::dyn::OutputSampleSize) {
85 std::cerr << "Failed to write audio output" << std::endl;
86 stopthread=true;
87 }
88 }
90}
91
92void Usage(const char *progname, sound4::cloudx1::dyn::CDynLib &dynlib)
93{
94 std::cerr << "Usage: " << progname << std::endl;;
95 std::cerr << " Reads audio from stdin and return processed audio in stdout" << std::endl;
96 std::cerr << "Environment:"<< std::endl;;
97 std::cerr << " - S4STORE_PATH : path to store config [default: (no storage)]"<< std::endl;;
98 std::cerr << " - S4LOGINKEY : SOUND4 Login key (or S4USERID)"<< std::endl;;
99 std::cerr << " - RADIO_NAME : SOUND4 Radio Name"<< std::endl;;
100 std::cerr << " - ACCESS_KEY_ID : SOUND4 Access Key ID"<< std::endl;;
101 std::cerr << " - ACCESS_KEY_SECRET : SOUND4 Access Key Secret"<< std::endl;;
102 if (dynlib.IsOk()) {
103 std::cerr << std::endl;
104 std::cerr << "Example:"<< std::endl;
105 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;;
106 #if defined(_WIN32) || defined(WIN32)
107 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;;
108 #else
109 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;;
110 #endif
111 }
112}
113
114void MyLogger(sound4::cloudx1::dyn::LogSeverity severity,const std::string& msg)
115{
116 std::cerr << msg << std::endl;
117}
118
121public:
122 MyPresetManager() = default;
123 virtual ~MyPresetManager() = default;
124
125 bool SetupPath(const std::filesystem::path& a_preset_path)
126 {
127 m_preset_path=a_preset_path;
128 std::error_code ec;
129 if ( !std::filesystem::exists(m_preset_path,ec ) ) {
130 return false;
131 }
132 if ( !std::filesystem::is_directory(m_preset_path, ec) ) {
133 return false;
134 }
135 return true;
136 }
137 virtual bool IsReadOnly() override { return false; };
138 virtual bool Exists(const std::filesystem::path &name) override
139 {
140 std::error_code ec;
141 return std::filesystem::exists(GetRealPath(name), ec);
142 }
143 virtual bool Remove(const std::filesystem::path &name) override
144 {
145 std::error_code ec;
146 return std::filesystem::remove(GetRealPath(name), ec);
147 }
148 virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to) override
149 {
150 std::error_code ec;
151 std::filesystem::rename(GetRealPath(from), GetRealPath(to), ec);
152 return (!ec);
153 }
154 virtual std::vector<std::filesystem::path> GetAll() override
155 {
156 std::vector<std::filesystem::path> list;
157 std::error_code ec;
158 for (auto it = std::filesystem::directory_iterator(m_preset_path.c_str(), std::filesystem::directory_options::skip_permission_denied, ec);
159 !ec && it != std::filesystem::directory_iterator{};
160 it.increment(ec) )
161 {
162 if (it->is_regular_file(ec)) {
163 list.push_back(it->path().lexically_relative(m_preset_path));
164 }
165 }
166 return list;
167 }
168 virtual std::string Read(const std::filesystem::path &filename) override
169 {
170 std::ifstream f(GetRealPath(filename));
171 if ( f.fail() ) {
172 return std::string();
173 }
174 std::ostringstream ss;
175 ss << f.rdbuf();
176 return ss.str();
177 }
178 virtual bool Write(const std::filesystem::path &filename, const std::string &content) override
179 {
180 std::ofstream f(GetRealPath(filename));
181 if ( f.fail() ) {
182 return false;
183 }
184 f << content;
185 if ( f.fail() ) {
186 return false;
187 }
188 return true;
189 }
190private:
191 std::filesystem::path m_preset_path;
192 std::filesystem::path GetRealPath(const std::filesystem::path &name)
193 {
194 return m_preset_path / name;
195 }
196};
198
199int main(int argc, const char **argv)
200{
201#if (CLOUDX1_HAS_WEBSERVER)
202 int listen_port = 8080;
203#endif // (CLOUDX1_HAS_WEBSERVER)
204 auto store_path_str=GetEnv("S4STORE_PATH");
205
206 // Get credentials from environment
207 auto LoginKey=GetEnv("S4LOGINKEY");
208 if (LoginKey.empty()) {
209 LoginKey=GetEnv("S4USERID");
210 }
211 auto RadioName=GetEnv("RADIO_NAME");
212 auto KeyId=GetEnv("ACCESS_KEY_ID");
213 auto AccessKey=GetEnv("ACCESS_KEY_SECRET");
214
215 const char *progname=argv[0];
216
217
220 if (!dynlib.Load()) {
221 std::cerr << "Failed to load processing library" << std::endl;
222 return 1;
223 }
225
226 if (argc>1) {
227 if ((strcasecmp(argv[1],"-h")==0) || (strcasecmp(argv[1],"--help")==0)) {
228 Usage(progname,dynlib);
229 return 0;
230 }
231 }
232 if (LoginKey.empty() || RadioName.empty() || KeyId.empty() || AccessKey.empty()) {
233 std::cerr << "Missing credentials in environment" << std::endl;
234 Usage(progname,dynlib);
235 return 1;
236 }
237 std::filesystem::path store_path;
238 if (!store_path_str.empty()) {
239 std::error_code ec;
240 store_path = std::filesystem::path(store_path_str);
241 if (!std::filesystem::exists(store_path,ec) || !std::filesystem::is_directory(store_path,ec)) {
242 std::cerr << "Storage folder '"<<store_path.c_str()<<"' is not a valid directory" << std::endl;
243 Usage(progname,dynlib);
244 return 1;
245 }
246 }
247
251
252 sound4::cloudx1::dyn::CInstance instance(dynlib);
253 instance.SetParam("ADMIN_USER","admin");
254 instance.SetParam("ADMIN_SECRET","admin");
256
258 MyPresetManager preset_manager;
259 if (!store_path.empty()) {
260 if (!preset_manager.SetupPath(store_path)) {
261 std::cerr << "Failed to setup the custom preset manager on path " << store_path.c_str() << std::endl;
262 return 1;
263 }
264 instance.SetPresetManager(&preset_manager);
265 }
267
268 std::cerr << "Creating" << std::endl;
270 if (!instance.Create(LoginKey, RadioName, KeyId, AccessKey, {})) {
271 std::cerr << "Failed to create the processing instance" << std::endl;
272 return 1;
273 }
275
276#if (CLOUDX1_HAS_WEBSERVER)
277 std::cerr << "Starting web server" << std::endl;
279 if (!instance.StartWebServer(listen_port,0)) {
280 std::cerr << "Failed to create the web server on port " << listen_port << std::endl;
281 return 1;
282 }
284#endif // (CLOUDX1_HAS_WEBSERVER)
285
286 {
288 auto client = instance.NewClient();
289 auto answer = client->ProcessJson(R"JSON({"get":{"processorname":null}})JSON");
290 std::cerr << "Request for processor name returned "<<answer<<std::endl;
292 }
293
294 ProcessLoop(instance);
295
296 std::cerr << "Stopping now" << std::endl;
297 instance.Stop();
298
299 std::cerr << "End" << std::endl;
300 return 0;
301}
[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::vector< std::filesystem::path > GetAll() override
virtual std::string Read(const std::filesystem::path &filename) override
bool SetupPath(const std::filesystem::path &a_preset_path)
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::shared_ptr< CClient > NewClient()
std::array< float, InputSampleSize > & GetBufferIn()
std::array< float, OutputSampleSize > & GetBufferOut()
bool StartWebServer(int http_port, int https_port=0)
cloudx1_LogSeverity
@ verbose5
verbose5
static void SetLogSeverity(CDynLib &dynlib, LogSeverity severity)
static void SetLoggerCallback(CDynLib &dynlib, log_cb_t cb)
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.