Babel  1
The voip software that only works on your local network
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2024
3** epitech-ratrappage-babel (Workspace)
4** File description:
5** main.cpp
6*/
7
18#include "Logging.hpp"
19#include "Network.hpp"
20#include "Controls.hpp"
21#include "Constants.hpp"
22#include "BootScreen.hpp"
23#include "Audio/Audio.hpp"
25
36const unsigned int stringToUnsignedInt(const std::string &str, const unsigned int defaultValue = 0)
37{
38 try {
39 return std::stoul(str);
40 }
41 catch (const std::exception &e) {
42 std::cerr << "Error: " << e.what() << ", defaulting to value: " << Recoded::myToString(defaultValue) << std::endl;
43 return defaultValue;
44 }
45}
46
47
58int main(int argc, char **argv)
59{
60 // Start the boot screen class
62 // Start the user control options
64 // Set the default values for the flags
65 bool defaultLog = false;
66 bool defaultEcho = false;
67 bool defaultDebug = false;
68 bool defaultSenderMode = true;
69 bool defaultMonoActive = false;
70 bool defaultSenderOnly = true;
71 unsigned int defaultLoopLimit = 0;
72 unsigned int defaultPacketDelay = 10;
73 unsigned int defaultPort = 9000;
74 std::string defaultIp = "0.0.0.0";
75 // Set the values for the flags
76 int port = defaultPort;
77 bool is_sender = defaultSenderMode;
78 std::string ip = defaultIp;
79 bool echo = defaultEcho;
80 bool log = defaultLog;
81 bool debug = defaultDebug;
82 unsigned int maxRounds = defaultLoopLimit;
83 unsigned int packetDelay = defaultPacketDelay;
84 bool monoActive = defaultMonoActive;
85 bool senderOnly = defaultSenderOnly;
86 // Check the arguments if present
87 for (int i = 1; i < argc; i++) {
88 std::string arg = std::string(argv[i]);
89 if (arg == "-p") {
90 if (i + 1 < argc) {
91 port = stringToUnsignedInt(argv[i + 1], defaultPort);
92 if (port < 1024 || port > 65535) {
93 std::cerr << "Invalid port number, please use a port number between 1024 and 65535" << std::endl;
94 return PROGRAM_ERROR;
95 }
96 i++;
97 } else {
98 std::cout << "Missing argument parameter, use -h for help" << std::endl;
99 }
100 } else if (arg == "-i") {
101 if (i + 1 < argc) {
102 ip = argv[i + 1];
103 i++;
104 } else {
105 std::cout << "Missing argument parameter, use -h for help" << std::endl;
106 }
107 } else if (arg == "-r") {
108 is_sender = false;
109 } else if (arg == "-s") {
110 is_sender = true;
111 } else if (arg == "-d") {
112 debug = true;
113 } else if (arg == "-l") {
114 log = true;
115 } else if (arg == "-m") {
116 if (i + 1 < argc) {
117 maxRounds = stringToUnsignedInt(argv[i + 1], defaultLoopLimit);
118 i++;
119 } else {
120 std::cout << "Missing argument parameter, use -h for help" << std::endl;
121 }
122 } else if (arg == "-mono") {
123 monoActive = true;
124 senderOnly = true;
125 } else if (arg == "-so") {
126 monoActive = true;
127 senderOnly = true;
128 } else if (arg == "-ro") {
129 monoActive = true;
130 senderOnly = false;
131 } else if (arg == "-e") {
132 echo = true;
133 } else if (arg == "-a") {
135 return PROGRAM_SUCCESS;
136 } else if (arg == "-v") {
137 std::cout << "The program's version is: " << VERSION << std::endl;
138 return PROGRAM_SUCCESS;
139 } else if (arg == "--packet-delay" || arg == "-pd" || arg == "-packet-delay" || arg == "--pd" || arg == "-packetdelay" || arg == "--packetdelay") {
140 if (i + 1 < argc) {
141 packetDelay = stringToUnsignedInt(argv[i + 1], defaultPacketDelay);
142 i++;
143 } else {
144 std::cout << "Missing argument parameter, use -h for help" << std::endl;
145 }
146 } else if (arg == "-h" || arg == "--help") {
147 std::cout << "USAGE:\n";
148 std::cout << std::string(argv[0]) << " -p <port> -i <ip> [-r <receiver> | -s <sender>] -d -l\n";
149 std::cout << "\n";
150 std::cout << "OPTIONS:\n";
151 std::cout << "-p <port> : Set the port to connect to (default: " << defaultPort << ")\n";
152 std::cout << "-i <ip> : Set the ip to connect to (default: " << defaultIp << ")\n";
153 std::cout << "-r <receiver> : Set the client to receiver mode [This is for the connection reasons] (default: " << Recoded::myToString(!defaultSenderMode) << "\n";
154 std::cout << "-s <sender> : Set the client to sender mode [This is for the connection reasons] (default: " << Recoded::myToString(defaultSenderMode) << ")\n";
155 std::cout << "-d : Enable debug mode (default: " << Recoded::myToString(defaultDebug) << ")\n";
156 std::cout << "-l : Enable log mode (default: " << Recoded::myToString(defaultLog) << ")\n";
157 std::cout << "-m <maxRounds> : Set the maximum number of rounds, 0 = endless (default: " << defaultLoopLimit << ")\n";
158 std::cout << "-e : Enable echo mode for the user prompt (default: " << Recoded::myToString(defaultEcho) << ")\n";
159 std::cout << "-a : Display all boot screens (Epilepsy warning, all the" << Recoded::myToString(BootScreen.getAvailableScreens()) << "logos will be displayed one after the other without any delay, meaning they will come out as fast as you terminal can diplay them)\n";
160 std::cout << "-h, --help : Display this help message\n";
161 std::cout << "-mono : Set the program to mono mode [This is for the audio management] (default " << Recoded::myToString(defaultMonoActive) << ")\n";
162 std::cout << "-so : Set the program to sender only mode, will set mono mode to true [This is for the audio management] (default " << Recoded::myToString(defaultSenderOnly) << ")\n";
163 std::cout << "-ro : Set the program to receiver only mode, will set mono mode to true [This is for the audio management] (default " << Recoded::myToString(!defaultSenderOnly) << ")\n";
164 std::cout << "-v : Display the program's version\n";
165 std::cout << "--packet-delay, -pd, -packet-delay, --pd, -packetdelay, --packetdelay : Set the delay between packets in milliseconds (default: " << Recoded::myToString(defaultPacketDelay) << ")\n";
166 std::cout << "\n";
167 std::cout << "VERSION:\n";
168 std::cout << "The program's version is: " << VERSION << std::endl;
169 std::cout << "\n";
170 std::cout << "AUTHOR:\n";
171 std::cout << "Written by:";
172 std::cout << "\t-\tHenry Letellier : https://github.com/HenraL\n";
173 std::cout << "Epitech student 2025\n";
174 std::cout << "\n" << std::flush;
175 return PROGRAM_SUCCESS;
176 } else {
177 std::cout << "Invalid argument, use -h for help" << std::endl;
178 std::cout << "The argument you provided was: " << argv[i] << std::endl;
179 }
180 }
181
182 // Set the logging status
185
186 myCapsule.setEcho(echo);
187
188 PRETTY_INFO << "Starting the program" << std::endl;
189
190 // Initialised asio
191 asio::io_context io_context;
192
193 // Set the end message
194 const std::string endMessage = "END";
195
196 char usrC = ' ';
197 unsigned int rounds = 0;
198 bool continueRunning = true;
199 std::vector<float> sound;
200 std::vector<unsigned char> compressedSound;
201 try {
202 PortAudio audio;
203 Compressor::Manager myManager;
204 Network::UDP myUDP(io_context, ip, port, is_sender);
206 if (monoActive) {
207 if (senderOnly) {
208 audio.record();
209 myCapsule.startThread();
210 } else {
211 audio.play();
212 }
213 } else {
214 audio.record();
215 myCapsule.startThread();
216 audio.play();
217 }
218
219 while ((rounds < maxRounds || maxRounds == 0) && continueRunning == true && myUDP.isConnectionAlive()) {
220 if (monoActive) {
221 if (senderOnly) {
222 if (myCapsule.hangUpTheCall()) {
223 PRETTY_INFO << "Haging up the call" << std::endl;
224 continueRunning = false;
225 PRETTY_INFO << "Sending end message" << std::endl;
226 std::cout << "Sending end message" << std::endl;
227 myUDP.sendRaw(endMessage.c_str(), endMessage.size(), ip, port);
228 break;
229 }
230 PRETTY_INFO << "Round " << rounds << std::endl;
231 audio.getSound(sound, 480);
232 PRETTY_INFO << "Compressing" << std::endl;
233 myManager.encode(sound, compressedSound);
234 PRETTY_INFO << "Decompressing" << std::endl;
235 PRETTY_INFO << "compressedSound size: " << compressedSound.size() << std::endl;
236 PRETTY_DEBUG << "compressed sound data: " << compressedSound << std::endl;
237 myUDP.sendRaw(reinterpret_cast<const char *>(compressedSound.data()), compressedSound.size(), ip, port);
238 } else {
239 std::string receivedData = myUDP.receiveFrom(ip, port);
240 if (receivedData == "END") {
241 std::cout << "Received end message, ending program" << std::endl;
242 continueRunning = false;
243 break;
244 }
245 PRETTY_INFO << "Received data size: " << receivedData.size() << std::endl;
246 PRETTY_INFO << "Received data: " << receivedData << std::endl;
247 for (int i = 0; i < receivedData.size(); i++) {
248 compressedSound.push_back(receivedData[i]);
249 }
250 PRETTY_INFO << "compressed sound data: " << compressedSound << std::endl;
251 myManager.decode(compressedSound, sound);
252 audio.setPlaySound(sound);
253 }
254 } else {
255 if (myCapsule.hangUpTheCall()) {
256 PRETTY_INFO << "Haging up the call" << std::endl;
257 continueRunning = false;
258 PRETTY_INFO << "Sending end message" << std::endl;
259 std::cout << "Sending end message" << std::endl;
260 myUDP.sendRaw(endMessage.c_str(), endMessage.size(), ip, port);
261 break;
262 }
263 PRETTY_INFO << "Round " << rounds << std::endl;
264 audio.getSound(sound, 480);
265 PRETTY_INFO << "Compressing" << std::endl;
266 myManager.encode(sound, compressedSound);
267 PRETTY_INFO << "Decompressing" << std::endl;
268 PRETTY_INFO << "compressedSound size: " << compressedSound.size() << std::endl;
269 PRETTY_DEBUG << "compressed sound data: " << compressedSound << std::endl;
270 myUDP.sendRaw(reinterpret_cast<const char *>(compressedSound.data()), compressedSound.size(), ip, port);
271 std::this_thread::sleep_for(std::chrono::milliseconds(10));
272 std::string receivedData = myUDP.receiveFrom(ip, port);
273 if (receivedData == "END") {
274 std::cout << "Received end message, ending program" << std::endl;
275 continueRunning = false;
276 break;
277 }
278 PRETTY_INFO << "Received data size: " << receivedData.size() << std::endl;
279 PRETTY_INFO << "Received data: " << receivedData << std::endl;
280 for (int i = 0; i < receivedData.size(); i++) {
281 compressedSound.push_back(receivedData[i]);
282 }
283 PRETTY_INFO << "compressed sound data: " << compressedSound << std::endl;
284 myManager.decode(compressedSound, sound);
285 audio.setPlaySound(sound);
286 }
287 PRETTY_INFO << "Round end " << rounds << std::endl;
288 PRETTY_INFO << "Clearing sound buffer and compressed buffer" << std::endl;
289 sound.clear();
290 compressedSound.clear();
291 PRETTY_INFO << "Sound buffer and compressed buffer cleared" << std::endl;
292 rounds++;
293 }
294 if (monoActive) {
295 if (senderOnly) {
296 audio.stopRecord();
297 PRETTY_INFO << "Sending end message" << std::endl;
298 myUDP.sendRaw(endMessage.c_str(), endMessage.size(), ip, port);
299 } else {
300 audio.stopPlay();
301 }
302 } else {
303 audio.stopRecord();
304 PRETTY_INFO << "Sending end message" << std::endl;
305 myUDP.sendRaw(endMessage.c_str(), endMessage.size(), ip, port);
306 audio.stopPlay();
307 }
308 if (myCapsule.isRunning()) {
309 try {
310 myCapsule.stopThread();
311 }
312 catch (const CustomExceptions::ThreadFound &e) {
313 PRETTY_WARNING << e.what() << std::endl;
314 }
315 catch (...) {
316 PRETTY_ERROR << "The thread stopping did not happen in a clean manner" << std::endl;
317 }
318 }
319 PRETTY_SUCCESS << "Program ended successfully" << std::endl;
320 std::cout << "Program ended successfully" << std::endl;
321 }
322 catch (const std::exception &e) {
323 std::cerr << "An error occurred: " << e.what() << std::endl;
324 PRETTY_ERROR << e.what() << std::endl;
325 return PROGRAM_ERROR;
326 }
327 return PROGRAM_SUCCESS;
328}
Declares the PortAudio class for handling audio playback and recording using PortAudio.
Defines the BootScreen class for displaying boot screens.
Defines various constants used throughout the project.
Aggregates control-related headers.
#define PRETTY_ERROR
Error log with details and colour.
#define PRETTY_DEBUG
Debug log with details and colour.
#define PRETTY_INFO
Info log with details and colour.
#define PRETTY_WARNING
Warning log with details and colour.
#define PRETTY_SUCCESS
Success log with details and colour.
Aggregates logging-related headers.
This file contains the definition of the Manager class responsible for managing audio compression and...
Aggregates network-related headers.
Manages and displays boot screens.
int getAvailableScreens() const
Get the number of available boot screens.
void display() const
Display a random boot screen.
void displayAllScreens() const
Display all available boot screens.
Class responsible for managing audio compression and decompression.
Definition Manager.hpp:32
void decode(std::vector< unsigned char > &sound, std::vector< float > &output)
Decode compressed audio data into raw format.
Definition Manager.cpp:348
void encode(std::vector< float > &sound, std::vector< unsigned char > &output)
Encode raw audio data into compressed format.
Definition Manager.cpp:286
Manages a thread for user controls.
const bool isRunning() const
Checks if the thread is running.
void startThread()
Starts the thread to run the spamUserChoice function.
void stopThread(const unsigned int delay=2)
Stops the thread safely.
void setEcho(const bool echo)
Sets the echo state.
const bool hangUpTheCall() const
Checks if the call should be hung up.
Exception class for the thread termination. This is not an error.
Definition Found.hpp:79
const char * what() const noexcept
Retrieves the message.
Definition Found.cpp:85
void setLogEnabled(bool enabled)
Enables or disables logging.
Definition Log.cpp:56
static Log & getInstance(const bool debug=false)
Provides access to the singleton instance of the Log class.
Definition Log.cpp:22
void setDebugEnabled(bool enabled)
Enables or disables debug logging.
Definition Log.cpp:66
A class for handling UDP network communication.
Definition UDP.hpp:27
void sendRaw(const char *data, std::size_t size, const std::string &address, int port)
Send raw data to a specified address and port.
Definition UDP.cpp:68
bool isConnectionAlive()
Check if the connection is alive.
Definition UDP.cpp:112
std::string receiveFrom(std::string &address, int &port)
Receive a message from a specified address and port.
Definition UDP.cpp:81
Class for handling audio playback and recording using PortAudio.
Definition Audio.hpp:29
void play()
Start audio playback.
Definition Audio.cpp:106
void setPlaySound(const std::vector< float > &soundVector)
Set the sound data to be played.
Definition Audio.cpp:185
void stopPlay()
Stop audio playback.
Definition Audio.cpp:120
bool getSound(std::vector< float > &soundVector, int packetSize)
Get recorded sound data.
Definition Audio.cpp:164
void record()
Start audio recording.
Definition Audio.cpp:133
void stopRecord()
Stop audio recording.
Definition Audio.cpp:147
const unsigned int stringToUnsignedInt(const std::string &str, const unsigned int defaultValue=0)
Converts a string to an unsigned integer.
Definition main.cpp:36
int main(int argc, char **argv)
Main function of the program.
Definition main.cpp:58
const std::string myToString(bool value)
Converts a boolean value to its string representation.
Definition ToString.cpp:22