118 lines
2.8 KiB
C++
118 lines
2.8 KiB
C++
#include "Server.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cstdint>
|
|
#include <mpg123.h>
|
|
#include <netdb.h>
|
|
#include <stdexcept>
|
|
#include <thread>
|
|
#include <sys/socket.h>
|
|
#include <vector>
|
|
|
|
|
|
Server::Server() {
|
|
// create a new mpg123 handle
|
|
int error;
|
|
this->mpgHandle = mpg123_new(nullptr, &error);
|
|
|
|
// open the mp3 file
|
|
if (mpg123_open(
|
|
this->mpgHandle,
|
|
"./assets/Caravan Palace - Wonderland.mp3"
|
|
))
|
|
throw std::runtime_error("Could not open file.");
|
|
|
|
// get the format of the file
|
|
if (mpg123_getformat(
|
|
this->mpgHandle,
|
|
&this->rate,
|
|
&this->channels,
|
|
&this->encoding
|
|
) != MPG123_OK)
|
|
throw std::runtime_error("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() {
|
|
int error;
|
|
|
|
// create the socket
|
|
const int serverSocket = socket(
|
|
AF_INET6,
|
|
SOCK_DGRAM,
|
|
0
|
|
);
|
|
if (serverSocket < 0)
|
|
throw std::runtime_error("Could not create the socket.");
|
|
|
|
// get the broadcast address
|
|
addrinfo clientHints = {};
|
|
clientHints.ai_family = AF_INET6;
|
|
clientHints.ai_socktype = SOCK_DGRAM;
|
|
clientHints.ai_protocol = IPPROTO_UDP;
|
|
|
|
// TODO(Faraphel): ip / port as argument
|
|
addrinfo *clientInfo;
|
|
if((error = getaddrinfo(
|
|
"localhost",
|
|
// "ff02::1", // IPv6 local broadcast
|
|
"5650", // our port
|
|
&clientHints,
|
|
&clientInfo
|
|
)) != 0)
|
|
throw std::runtime_error("Could not get the address.\n" + std::string(gai_strerror(error)));
|
|
|
|
|
|
// read the file
|
|
std::vector<std::uint8_t> buffer(4096);
|
|
std::size_t done;
|
|
|
|
while (mpg123_read(
|
|
this->mpgHandle,
|
|
buffer.data(),
|
|
buffer.size(),
|
|
&done) == MPG123_OK
|
|
) {
|
|
// send the content of the file
|
|
sendto(
|
|
serverSocket,
|
|
buffer.data(),
|
|
buffer.size(),
|
|
0,
|
|
clientInfo->ai_addr,
|
|
clientInfo->ai_addrlen
|
|
);
|
|
|
|
std::cout << "[Server] sent : " << done << " bytes" << std::endl;
|
|
|
|
// wait 10ms to simulate lag
|
|
// TODO(Faraphel): should be extended to simulate live music streaming
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<uint64_t>(
|
|
(1 / static_cast<double>(this->rate * this->channels * mpg123_encsize(this->encoding))) *
|
|
1000 *
|
|
static_cast<double>(done)
|
|
)));
|
|
}
|
|
|
|
// free the server address
|
|
freeaddrinfo(clientInfo);
|
|
}
|
|
|
|
|
|
long Server::getRate() const {
|
|
return this->rate;
|
|
}
|
|
|
|
int Server::getChannels() const {
|
|
return this->channels;
|
|
}
|
|
|
|
int Server::getEncoding() const {
|
|
return this->encoding;
|
|
}
|