SOUND4 IMPACT.CL Library [1.3.6]
Loading...
Searching...
No Matches
sound4.impact.cl-pipe.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 <thread> // NOTE: needs pthread link
9#if (__cplusplus<201703L)
10 #error "Need C++17 for this example"
11#endif
12#include <filesystem>
13#if defined(_WIN32) || defined(WIN32)
14 #include <io.h>
15 #include <fcntl.h>
16 #include <stringapiset.h> // UTF-8 conversion
17#endif
18#include <sound4.impact.cl.h>
19
20#define SAMPLE_RATE 48000
21#define CHUNK_SIZE 64
22#define CHANNEL_COUNT 2
23
24// Reads from stdin, write to stdout
25void ProcessLoop(struct impact_CInstance *pInstance)
26{
28bool stopthread=false;
29alignas(64) float audio_in[CHUNK_SIZE*CHANNEL_COUNT];
30alignas(64) float audio_out[CHUNK_SIZE*CHANNEL_COUNT];
31
32 #if defined(_WIN32) || defined(WIN32)
33 // Windows: The stdin, stdout, and stderr streams always open in text mode by default
34 _setmode(_fileno(stdin), _O_BINARY);
35 _setmode(_fileno(stdout), _O_BINARY);
36 #endif
37
38 while (!stopthread)
39 {
40 // Read a chunk from stdin
41 if (std::fread(&audio_in[0], sizeof(float), CHUNK_SIZE*CHANNEL_COUNT, stdin) != CHUNK_SIZE*CHANNEL_COUNT) {
42 std::cerr << "ProcessLoop: input stopped"<< std::endl;
43 stopthread=true;
44 break;
45 }
46 if (stopthread) break;
47 // Process it
48 impact_ProcessAudio(pInstance, audio_in, audio_out);
49 // Write it to stdout
50 if (fwrite(&audio_out[0], sizeof(float), CHUNK_SIZE*CHANNEL_COUNT, stdout) != CHUNK_SIZE*CHANNEL_COUNT) {
51 std::cerr << "Failed to write audio output" << std::endl;
52 stopthread=true;
53 }
54 }
56}
57
58void Usage(const char *progname)
59{
60 std::cerr << "Usage: " << progname << std::endl;;
61 std::cerr << " Reads audio from stdin and return processed audio in stdout" << std::endl;
62 std::cerr << "Environment:"<< std::endl;;
63 std::cerr << " - S4STORE_PATH : path to store config [default: ./state]"<< std::endl;;
64 std::cerr << " - S4LOGINKEY : SOUND4 Login key (or S4USERID)"<< std::endl;;
65 std::cerr << " - RADIO_NAME : SOUND4 Radio Name"<< std::endl;;
66 std::cerr << " - ACCESS_KEY_ID : SOUND4 Access Key ID"<< std::endl;;
67 std::cerr << " - ACCESS_KEY_SECRET : SOUND4 Access Key Secret"<< std::endl;;
68 std::cerr << std::endl;
69 std::cerr << "Example:"<< std::endl;
70 std::cerr << "ffmpeg -re -i file.wav -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -i -" << std::endl;;
71 #if defined(_WIN32) || defined(WIN32)
72 std::cerr << "ffmpeg -f dshow -i audio=\"Microphone\" -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -i -" << std::endl;;
73 #else
74 std::cerr << "ffmpeg -f pulse -i default -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -f f32le - | "<<progname<<" | ffplay -f f32le -ar "<<SAMPLE_RATE<<" -ac "<<CHANNEL_COUNT<<" -i -" << std::endl;;
75 #endif
76}
77
78void MyLogger(impact_LogSeverity severe [[maybe_unused]], const char *str)
79{
80 std::cerr << str << std::endl;
81}
82
83
84int main(int argc, char *const argv[])
85{
86 struct impact_CInstance *pInstance = NULL;
87 const char *store_path_str=getenv("S4STORE_PATH");
88 // Get credentials from environment
89 char *pLoginKey=getenv("S4LOGINKEY");
90 if (!pLoginKey) {
91 pLoginKey=getenv("S4USERID");
92 }
93 char *pRadioName=getenv("RADIO_NAME");
94 char *pKeyId=getenv("ACCESS_KEY_ID");
95 char *pAccessKey=getenv("ACCESS_KEY_SECRET");
96
97 const char *progname=argv[0];
98
99 if (argc>1) {
100 if ((strcasecmp(argv[1],"-h")==0) || (strcasecmp(argv[1],"--help")==0)) {
101 Usage(progname);
102 return 0;
103 }
104 }
105 if (!pLoginKey || !pRadioName || !pKeyId || !pAccessKey) {
106 std::cerr << "Missing credentials in environment" << std::endl;
107 Usage(progname);
108 return 1;
109 }
110 std::error_code ec;
111 std::filesystem::path fs_store_path;
112 if (!store_path_str || store_path_str[0]==0) {
113 fs_store_path=std::filesystem::current_path(ec) / "state";
114 } else {
115 fs_store_path = std::filesystem::path(store_path_str);
116 }
117 if (!std::filesystem::exists(fs_store_path,ec) || !std::filesystem::is_directory(fs_store_path,ec)) {
118 std::cerr << "Storage folder '"<<fs_store_path.c_str()<<"' is not a valid directory" << std::endl;
119 Usage(progname);
120 return 1;
121 }
122 std::string store_path;
123 #ifdef _WIN32
124 {
125 // Convert path to UTF-8
126 std::wstring wstr(fs_store_path.wstring());
127 if (wstr.empty()) return {};
128 int size = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
129 std::string str(size, 0);
130 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size, NULL, NULL);
131 store_path=str;
132 }
133 #else // !_WIN32
134 store_path=fs_store_path;
135 #endif // !_WIN32
136
138 // Optional: Use our own logging, instead of default color output to stderr.
139 //impact_SetLoggerCallback(&MyLogger);
140
141 //impact_SetLogSeverity(impact_LogSeverity::info);
143
144 std::cerr << "Process version: " << impact_GetVersion() << std::endl;
145 // Do some sanity checks
147 std::cerr << "Bad library sampling rate, expecting '"<<SAMPLE_RATE<<"' but has "<< impact_GetSampleRate() << std::endl;
148 return 1;
149 }
151 std::cerr << "Bad library frame size, expecting '"<<CHUNK_SIZE<<"' but has "<< impact_GetChunkSizeInFrames() << std::endl;
152 return 1;
153 }
155 std::cerr << "Bad library channel count, expecting '"<<CHANNEL_COUNT<<"' but has "<< impact_GetChannelCount() << std::endl;
156 return 1;
157 }
159
161 // Setup parameters
162 struct impact_CParameters *params = impact_NewParameters();
163 // Optional: activate web authentication, set admin password
164 // This creates the authentication only for a new storage path
165 impact_SetParameter(params,"ADMIN_USER", "admin");
166 impact_SetParameter(params,"ADMIN_SECRET", "admin");
167
168 // Create the processing instance
169 pInstance=impact_InitProcess2(pLoginKey,pRadioName,pKeyId,pAccessKey,store_path.c_str(), params);
170 impact_FreeParameters(params);
171 if (!pInstance) {
172 std::cerr << "Failed to create the process instance"<< std::endl;
173 return 1;
174 }
175
176 // Start the update thread, without JSON server (low priority)
177 std::thread updater([pInstance](){
178 // will returned when stopped or destroyed
179 std::cerr << "impact_StartUpdateThread (no json port)" << std::endl;
180 impact_StartUpdateThread(pInstance, 0);
181 std::cerr << "impact_StartUpdateThread END" << std::endl;
182 });
183
184 // This is not mandatory, but better be sure we are ready right now
185 std::cerr << "Waiting update thread" << std::endl;
186 if (impact_WaitUpdateThreadReady(pInstance, 5000)<0) {
187 std::cerr << "Timeout to create the process instance"<< std::endl;
188 }
189 std::cerr << "Waiting update thread DONE" << std::endl;
190
191#if (IMPACT_HAS_WEBSERVER)
193 // Starts a web server, listening on port http://localhost:8080, https://localhost:8443
194 std::cerr << "Starting web server" << std::endl;
195 int listenport= 8080;
196 int listenport_secure= 8443;
197 uint64_t webserver= SOUND4_INVALID_WEBSERVER_ID;
198 if (listenport || listenport_secure) {
199 webserver = impact_Webserver(listenport,listenport_secure,pInstance);
200 if (webserver==SOUND4_INVALID_WEBSERVER_ID) {
201 std::cerr << "Starting web server FAILED" << std::endl;
202 } else {
203 int web_status=impact_Webserver_Status(webserver);
204 if (listenport) {
205 if (web_status & SOUND4_WEBSERVER_HTTP_OK) {
206 std::cerr << "Web server listening on port " << listenport;
207 } else {
208 std::cerr << "Web server failed to listen on port " << listenport;
209 }
210 }
211 if (listenport_secure) {
212 if (web_status & SOUND4_WEBSERVER_HTTPS_OK) {
213 std::cerr << "Web server listening on secure port " << listenport_secure;
214 } else {
215 std::cerr << "Web server failed to listen on secure port " << listenport_secure;
216 }
217 }
218 std::cerr << "Starting web server DONE" << std::endl;
219 }
220 }
222#endif // (IMPACT_HAS_WEBSERVER)
223
224 // Force load a factory preset now
225 // Could be used instead of setting a store_path
226 /*{
227 impact_CClientInstance *pClient=impact_NewClient(pInstance);
228 const char *answer=impact_ProcessJson(pClient, "{ \"factoryload\": \"All Programs\" }", NULL);
229 std::cerr << "Loaded factory preset answer: " << answer<< std::endl;
230 impact_FreeJsonAnswer(answer);
231 impact_DeleteClient(pClient);
232 }*/
234
235 std::cerr << "Estimated delay " << ( impact_GetEstimatedDelay(pInstance)*1000.0/SAMPLE_RATE ) << " ms" << std::endl;
236
237 ProcessLoop(pInstance);
238
240#if (IMPACT_HAS_WEBSERVER)
241 // Stopping the webserver
242 std::cerr << "Stopping web server" << std::endl;
243 impact_Webserver_Stop(webserver, 1000);
244 std::cerr << "Stopping web server DONE" << std::endl;
245#endif // (IMPACT_HAS_WEBSERVER)
246
247 // Stopping the processing instance
248 std::cerr << "Stopping Update thread" << std::endl;
249 impact_StopUpdateThread(pInstance); // this will exit the update thread
250 std::cerr << "Stopping Update thread DONE" << std::endl;
251
252 updater.join();
253
254 impact_ExitProcess(pInstance);
256
257 return 0;
258}
void impact_ProcessAudio(struct impact_CInstance *instance, const float *input, float *output)
unsigned int impact_GetEstimatedDelay(struct impact_CInstance *instance)
const char * impact_GetVersion()
unsigned int impact_GetChunkSizeInFrames()
impact_LogSeverity
unsigned int impact_GetChannelCount()
void impact_SetLogSeverity(enum impact_LogSeverity severity)
unsigned int impact_GetSampleRate()
@ verbose5
verbose5
struct impact_CParameters * impact_NewParameters()
void impact_SetParameter(struct impact_CParameters *params, const char *name, const char *value)
struct impact_CInstance * impact_InitProcess2(const char *LoginKey, const char *RadioName, const char *Access_Key_ID, const char *Access_Key_Secret, const char *save_path, const struct impact_CParameters *parameters)
void impact_FreeParameters(struct impact_CParameters *params)
void impact_ExitProcess(struct impact_CInstance *instance)
void impact_StopUpdateThread(struct impact_CInstance *instance)
void impact_StartUpdateThread(struct impact_CInstance *instance, unsigned int port)
int impact_WaitUpdateThreadReady(struct impact_CInstance *instance, int milliseconds)
#define SOUND4_WEBSERVER_HTTPS_OK
int impact_Webserver_Stop(uint64_t id, int timeout_ms)
uint64_t impact_Webserver(unsigned int listenport, unsigned int listenport_secure, struct impact_CInstance *instance)
int impact_Webserver_Status(uint64_t id)
#define SOUND4_WEBSERVER_HTTP_OK
#define SOUND4_INVALID_WEBSERVER_ID
#define CHANNEL_COUNT
void MyLogger(impact_LogSeverity severe, const char *str)
void ProcessLoop(struct impact_CInstance *pInstance)
#define SAMPLE_RATE
void Usage(const char *progname)
#define CHUNK_SIZE
int main(int argc, char *const argv[])
C interface for library.