127 lines
3.6 KiB
C++
127 lines
3.6 KiB
C++
#include "Server.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <mpg123.h>
|
|
#include <netdb.h>
|
|
#include <stdexcept>
|
|
#include <thread>
|
|
#include <sys/socket.h>
|
|
#include <vector>
|
|
|
|
#include "packets/AudioPacket.hpp"
|
|
#include "utils/audio.hpp"
|
|
|
|
|
|
Server::Server() {
|
|
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.");
|
|
}
|
|
|
|
Server::~Server() {
|
|
// delete the mpg123 handle
|
|
mpg123_close(this->mpgHandle);
|
|
mpg123_delete(this->mpgHandle);
|
|
}
|
|
|
|
void Server::loop() const {
|
|
// 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<uint64_t>(
|
|
(1 / static_cast<double>(this->sampleRate * this->channels * mpg123_encsize(this->encoding))) *
|
|
1000 *
|
|
static_cast<double>(done)
|
|
)));
|
|
}
|
|
|
|
// free the server address
|
|
freeaddrinfo(broadcastInfo);
|
|
}
|