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