#include "ServerTask.hpp" #include #include #include #include #include #include #include #include #include namespace drp::task { ServerTask::ServerTask() { this->channels = 0; this->encoding = 0; this->sampleRate = 0; // create a new mpg123 handle int error; this->mpgHandle = mpg123_new(nullptr, &error); if (this->mpgHandle == nullptr) throw std::runtime_error("[Server] Could not create a mpg123 handle."); // open the mp3 file // TODO(Faraphel): mp3 file as argument if (mpg123_open( this->mpgHandle, // "./assets/Caravan Palace - Wonderland.mp3" "./assets/Queen - Another One Bites the Dust.mp3" ) != MPG123_OK) throw std::runtime_error("[Server] Could not open file."); // get the format of the file if (mpg123_getformat( this->mpgHandle, &this->sampleRate, &this->channels, &this->encoding ) != MPG123_OK) throw std::runtime_error("[Server] Could not get the format of the file."); } ServerTask::~ServerTask() { // delete the mpg123 handle mpg123_close(this->mpgHandle); mpg123_delete(this->mpgHandle); } void ServerTask::loop() const { // TODO(Faraphel): create a chrony server // get the broadcast address addrinfo broadcastHints {}; broadcastHints.ai_family = AF_INET6; broadcastHints.ai_socktype = SOCK_DGRAM; broadcastHints.ai_protocol = IPPROTO_UDP; // TODO(Faraphel): ip / port as argument addrinfo *broadcastInfo; if(const int error = getaddrinfo( "::1", "5650", &broadcastHints, &broadcastInfo ) != 0) throw std::runtime_error("[Server] Could not get the address: " + std::string(gai_strerror(error))); const int broadcastSocket = socket( broadcastInfo->ai_family, broadcastInfo->ai_socktype, broadcastInfo->ai_protocol ); if (broadcastSocket == -1) throw std::runtime_error("[Server] Could not create the socket: " + std::string(gai_strerror(errno))); // read the file AudioPacket audioPacket; std::size_t done; while (mpg123_read( this->mpgHandle, &audioPacket.content, std::size(audioPacket.content), &done ) == MPG123_OK) { // set the target time // TODO(Faraphel): dynamically change this delay to be the lowest possible audioPacket.timePlay = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(5000); // set the audio settings audioPacket.channels = this->channels; audioPacket.sampleFormat = encoding_mpg123_to_PulseAudio(this->encoding); audioPacket.sampleRate = this->sampleRate; // set the size of the content audioPacket.contentSize = done; // broadcast the audio data if (sendto( broadcastSocket, &audioPacket, sizeof(audioPacket), 0, broadcastInfo->ai_addr, broadcastInfo->ai_addrlen ) == -1) { std::cerr << "[Server] Could not send audio packet: " << strerror(errno) << std::endl; continue; } std::cout << "[Server] Sent: " << done << " bytes" << std::endl; // wait for the duration of the audio chunk std::this_thread::sleep_for(std::chrono::milliseconds(static_cast( (1 / static_cast(this->sampleRate * this->channels * mpg123_encsize(this->encoding))) * 1000 * static_cast(done) ))); } // free the server address freeaddrinfo(broadcastInfo); } }