105 lines
2.6 KiB
C++
105 lines
2.6 KiB
C++
#include "Client.hpp"
|
|
|
|
#include <cstring>
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <netdb.h>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
#include <sys/socket.h>
|
|
|
|
|
|
Client::Client(const int channels, const double rate) {
|
|
this->channels = channels;
|
|
|
|
// TODO(Faraphel): make the sampleFormat and the framesPerBuffer arguments.
|
|
// open a PortAudio stream
|
|
if (Pa_OpenDefaultStream(
|
|
&this->stream,
|
|
0,
|
|
channels,
|
|
paInt16,
|
|
rate,
|
|
512,
|
|
nullptr,
|
|
nullptr
|
|
) != paNoError)
|
|
throw std::runtime_error("Could not open PortAudio stream.");
|
|
}
|
|
|
|
Client::~Client() {
|
|
// close the audio stream
|
|
Pa_StopStream(this->stream);
|
|
Pa_CloseStream(this->stream);
|
|
}
|
|
|
|
|
|
void Client::loop() {
|
|
int error;
|
|
|
|
// start the PortAudio stream
|
|
if (Pa_StartStream(stream) != paNoError)
|
|
throw std::runtime_error("Could not start the PortAudio stream.");
|
|
|
|
// create the socket
|
|
const int clientSocket = socket(
|
|
AF_INET6,
|
|
SOCK_DGRAM,
|
|
0
|
|
);
|
|
if (clientSocket < 0)
|
|
throw std::runtime_error("Could not create the socket.");
|
|
|
|
// get the broadcast address
|
|
addrinfo serverHints = {};
|
|
serverHints.ai_family = AF_INET6;
|
|
serverHints.ai_socktype = SOCK_DGRAM;
|
|
serverHints.ai_protocol = IPPROTO_UDP;
|
|
|
|
// TODO(Faraphel): port as argument
|
|
addrinfo *serverInfo;
|
|
if((error = getaddrinfo(
|
|
nullptr, // any source
|
|
"5650", // our port
|
|
&serverHints,
|
|
&serverInfo
|
|
)) != 0)
|
|
throw std::runtime_error("Could not get the address.\n" + std::string(gai_strerror(error)));
|
|
|
|
// bind to this address
|
|
if (bind(
|
|
clientSocket,
|
|
serverInfo->ai_addr,
|
|
serverInfo->ai_addrlen
|
|
) < 0)
|
|
throw std::runtime_error("Could not bind to the address.");
|
|
|
|
// free the server address
|
|
freeaddrinfo(serverInfo);
|
|
|
|
sockaddr_storage serverAddress {};
|
|
socklen_t serverAddressLength;
|
|
std::vector<std::uint8_t> buffer(4096);
|
|
|
|
// receive new audio data
|
|
while (ssize_t size = recvfrom(
|
|
clientSocket,
|
|
buffer.data(),
|
|
buffer.size(),
|
|
0,
|
|
reinterpret_cast<sockaddr *>(&serverAddress),
|
|
&serverAddressLength
|
|
)) {
|
|
std::cout << "[Client] received: " << size << " bytes" << std::endl;
|
|
|
|
// TODO(Faraphel): check for the error ?
|
|
error = Pa_WriteStream(
|
|
this->stream,
|
|
buffer.data(),
|
|
size / 2 / this->channels
|
|
);
|
|
|
|
// play the audio buffer
|
|
// TODO(Faraphel): the number of frames could be improved
|
|
}
|
|
}
|