M2-PT-DRP/source/Client.cpp

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
}
}