#include "ServerTask.hpp" #include #include #include #include #include #include #include #include #include #include #include "packets/audio/AudioPacketData.hpp" #include "packets/base/Packet.hpp" #include "packets/base/SecurityMode.hpp" #include "utils/audio/audio.hpp" 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("[Task - Server] Could not create a mpg123 handle."); // open the mp3 file // TODO(Faraphel): mp3 file as argument if (mpg123_open( this->mpgHandle, "./assets/Queen - Another One Bites the Dust.mp3" ) != MPG123_OK) throw std::runtime_error("[Task - 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("[Task - Server] Could not get the format of the file."); } void ServerTask::use(Context& context, const std::shared_ptr& server) { context.me.status = TaskType::SERVER; context.server = server; } ServerTask::~ServerTask() { // delete the mpg123 handle mpg123_close(this->mpgHandle); mpg123_delete(this->mpgHandle); } void ServerTask::handle(Context& context) { // TODO(Faraphel): create a chrony server // get the time of the start of the processing const auto startProcessingTime = std::chrono::high_resolution_clock::now(); // prepare the packet structure packet::base::Packet packet {}; packet::base::PacketContent packetContent {}; std::size_t done; // create a packet packet::audio::AudioPacketData audioPacket; packet.channel = 0; // set the audio settings audioPacket.channels = this->channels; audioPacket.sampleFormat = util::encoding_mpg123_to_PulseAudio(this->encoding); audioPacket.sampleRate = this->sampleRate; std::vector content(64992); // read the file if (mpg123_read( this->mpgHandle, content.data(), content.size(), &done ) != MPG123_OK) { std::cerr << "[Task - Server] Could not read audio data from file." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); return; } // resize the content to fit content.resize(done); audioPacket.content = content; // 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); packetContent.eventType = event::EventType::AUDIO; packetContent.data = audioPacket.serialize(); packet.setContent(context, packet::base::SecurityMode::PLAIN, packetContent); const auto serializedPacket = packet.serialize(); // broadcast the audio data if (sendto( context.socket, serializedPacket.data(), serializedPacket.size(), 0, context.broadcastAddressInfo->ai_addr, context.broadcastAddressInfo->ai_addrlen ) == -1) { std::cerr << "[Task - Server] Could not send audio packet: " << strerror(errno) << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); return; } std::cout << "[Task - Server] Sent: " << done << " bytes" << std::endl; // wait for the duration of the audio chunk, since the start of the processing std::this_thread::sleep_until(startProcessingTime + util::get_audio_chunk_duration( this->sampleRate, this->channels, mpg123_encsize(this->encoding), done )); } }