SOUND4 x1.CLOUD Library [1.3.8]
sound4.x1.cloud-loopcreate.cpp
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <iostream>
3 #include <strings.h>
4 #include <sys/types.h>
5 #include <signal.h>
6 #include <chrono>
7 #include <thread> // NOTE: needs pthread link
8 // Choose good filesystem version depending on compiler.
9 #if __has_include(<filesystem>)
10  #include <filesystem>
11 #else //if __cpp_lib_experimental_filesystem
12  // We need the alias from std::experimental::filesystem to std::filesystem
13  #include <experimental/filesystem>
14  namespace std {
15  namespace filesystem = experimental::filesystem;
16  }
17 #endif
18 #if defined(_WIN32) || defined(WIN32)
19  #include <io.h>
20  #include <fcntl.h>
21 #endif
22 #include <sound4.x1.cloud.h>
23 
24 #define SAMPLE_RATE 48000
25 #define CHUNK_SIZE 64
26 #define CHANNEL_COUNT 2
27 
28 using namespace std::chrono_literals;
29 
30 void Usage(const char *progname)
31 {
32  std::cerr << "Usage: " << progname << std::endl;;
33  std::cerr << " Reads audio from stdin and return processed audio in stdout" << std::endl;
34  std::cerr << "Environment:"<< std::endl;;
35  std::cerr << " - S4STORE_PATH : path to store config [default: ./state]"<< std::endl;;
36  std::cerr << " - S4LOGINKEY : SOUND4 Login key (or S4USERID)"<< std::endl;;
37  std::cerr << " - RADIO_NAME : SOUND4 Radio Name"<< std::endl;;
38  std::cerr << " - S4_AWS_ACCESS_KEY_ID : SOUND4 Access Key ID"<< std::endl;;
39  std::cerr << " - S4_AWS_SECRET_ACCESS_KEY: SOUND4 Access Key Secret"<< std::endl;;
40  std::cerr << std::endl;
41  std::cerr << "Example:"<< std::endl;
42  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;;
43  #if defined(_WIN32) || defined(WIN32)
44  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;;
45  #else
46  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;;
47  #endif
48 }
49 
50 void MyLogger(cloudx1_LogSeverity severe [[maybe_unused]], const char *str)
51 {
52  std::cerr << str << std::endl;
53 }
54 
55 volatile bool gs_request_quit=false;
56 volatile bool gs_reload=false;
57 
58 void sigint(int signum [[maybe_unused]])
59 {
60  std::cerr << "Signal for quit" << std::endl;
61  signal(SIGINT, NULL);
62  signal(SIGTERM, NULL);
63  gs_request_quit=true;
64 }
65 
66 int main(int argc, char *const argv[])
67 {
68  const char *store_path=getenv("S4STORE_PATH");
69  // Get credentials from environment
70  char *pLoginKey=getenv("S4LOGINKEY");
71  if (!pLoginKey) {
72  pLoginKey=getenv("S4USERID");
73  }
74  char *pRadioName=getenv("RADIO_NAME");
75  char *pKeyId=getenv("S4_AWS_ACCESS_KEY_ID");
76  char *pAccessKey=getenv("S4_AWS_SECRET_ACCESS_KEY");
77 #if (CLOUDX1_HAS_WEBSERVER)
78  // int http=8080;
79  int http=0;
80  int https=0;
81 #endif // (CLOUDX1_HAS_WEBSERVER)
82 
83  const char *progname=argv[0];
84 
85  if (argc>1) {
86  if ((strcasecmp(argv[1],"-h")==0) || (strcasecmp(argv[1],"--help")==0)) {
87  Usage(progname);
88  return 0;
89  }
90  }
91  if (!pLoginKey || !pRadioName || !pKeyId || !pAccessKey) {
92  std::cerr << "Missing credentials in environment" << std::endl;
93  Usage(progname);
94  return 1;
95  }
96  if (!store_path ) {
97  store_path="./state";
98  }
99  if (!std::filesystem::exists(store_path) || !std::filesystem::is_directory(store_path)) {
100  std::cerr << "Storage folder '"<<store_path<<"' is not a valid directory" << std::endl;
101  Usage(progname);
102  return 1;
103  }
104 
105 
106  //cloudx1_SetLogSeverity(cloudx1_LogSeverity::info);
108 
109  std::cerr << "Process version: " << cloudx1_GetVersion() << std::endl;
110  // Do some sanity checks
112  std::cerr << "Bad library sampling rate, expecting '"<<SAMPLE_RATE<<"' but has "<< cloudx1_GetSampleRate() << std::endl;
113  return 1;
114  }
116  std::cerr << "Bad library frame size, expecting '"<<CHUNK_SIZE<<"' but has "<< cloudx1_GetChunkSizeInFrames() << std::endl;
117  return 1;
118  }
120  std::cerr << "Bad library channel count, expecting '"<<CHANNEL_COUNT<<"' but has "<< cloudx1_GetChannelCount() << std::endl;
121  return 1;
122  }
123 
124  signal(SIGTERM, &sigint);
125  signal(SIGINT, &sigint);
126 
127  while (!gs_request_quit) {
128  struct cloudx1_CInstance *pInstance = NULL;
129 
130  // Create the processing instance
131  std::cerr << "Creating instance" << std::endl;
132  pInstance=cloudx1_InitProcess(pLoginKey,pRadioName,pKeyId,pAccessKey,store_path);
133  if (!pInstance) {
134  std::cerr << "Failed to create the process instance"<< std::endl;
135  return 1;
136  }
137 
138  // Start the update thread, without JSON server (low priority)
139  std::thread updater([pInstance](){
140  // will returned when stopped or destroyed
141  std::cerr << "cloudx1_StartUpdateThread (no json port)" << std::endl;
142  cloudx1_StartUpdateThread(pInstance, 0);
143  std::cerr << "cloudx1_StartUpdateThread END" << std::endl;
144  });
145 
146  // This is not mandatory, but better be sure we are ready right now
147  std::cerr << "Waiting update thread" << std::endl;
148  if (cloudx1_WaitUpdateThreadReady(pInstance, 5000)<0) {
149  std::cerr << "Timeout to create the process instance"<< std::endl;
150  }
151  std::cerr << "Waiting update thread DONE" << std::endl;
152 
153  #if (CLOUDX1_HAS_WEBSERVER)
154  // Starts a web server, listening on port http://localhost:8080, https://localhost:8443
155  uint64_t webserver=-1;
156  if (http || https) {
157  std::cerr << "Starting web server" << std::endl;
158  webserver= cloudx1_Webserver(http,https,pInstance);
159  std::cerr << "Starting web server DONE" << std::endl;
160  }
161  #endif // (CLOUDX1_HAS_WEBSERVER)
162 
163  while (!gs_reload && !gs_request_quit) {
164  std::cout << "Type r(eload) or q(uit) + ENTER" << std::endl;
165  std::string s;
166  std::cin >> s;
167  if (s.length()>0) {
168  switch (s[0]) {
169  case 'q':
170  case 'Q':
171  gs_request_quit=true; break;
172  case 'r':
173  case 'R':
174  default:
175  gs_reload=true; break;
176  }
177  }
178  }
179 
180  #if (CLOUDX1_HAS_WEBSERVER)
181  if (http || https) {
182  // Stopping the webserver
183  std::cerr << "Stopping web server" << std::endl;
184  cloudx1_Webserver_Stop(webserver, 1000);
185  std::cerr << "Stopping web server DONE" << std::endl;
186  }
187  #endif // (CLOUDX1_HAS_WEBSERVER)
188 
189  // Stopping the processing instance
190  std::cerr << "Stopping Update thread" << std::endl;
191  cloudx1_StopUpdateThread(pInstance); // this will exit the update thread
192  std::cerr << "Stopping Update thread DONE" << std::endl;
193 
194  std::cerr << "waiting update thread" << std::endl;
195  updater.join();
196 
197  std::cerr << "Destorying instance" << std::endl;
198  cloudx1_ExitProcess(pInstance);
199 
200  gs_reload=false;
201  }
202 
203  return 0;
204 }
const char * cloudx1_GetVersion()
cloudx1_LogSeverity
unsigned int cloudx1_GetChunkSizeInFrames()
unsigned int cloudx1_GetChannelCount()
unsigned int cloudx1_GetSampleRate()
void cloudx1_SetLogSeverity(enum cloudx1_LogSeverity severity)
@ verbose5
struct cloudx1_CInstance * cloudx1_InitProcess(const char *LoginKey, const char *RadioName, const char *AWS_Access_ID, const char *AWS_Access_Secret, const char *save_path)
void cloudx1_ExitProcess(struct cloudx1_CInstance *instance)
void cloudx1_StartUpdateThread(struct cloudx1_CInstance *instance, unsigned int port)
int cloudx1_WaitUpdateThreadReady(struct cloudx1_CInstance *instance, int milliseconds)
void cloudx1_StopUpdateThread(struct cloudx1_CInstance *instance)
uint64_t cloudx1_Webserver(unsigned int listenport, unsigned int listenport_secure, struct cloudx1_CInstance *instance)
int cloudx1_Webserver_Stop(uint64_t id, int timeout_ms)
#define CHANNEL_COUNT
void sigint(int signum[[maybe_unused]])
#define SAMPLE_RATE
void Usage(const char *progname)
volatile bool gs_reload
void MyLogger(cloudx1_LogSeverity severe[[maybe_unused]], const char *str)
volatile bool gs_request_quit
#define CHUNK_SIZE
int main(int argc, char *const argv[])
C interface for library.