2015-09-28 23:25:12 +02:00
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
|
|
#include "MumbleCommunicator.hpp"
|
|
|
|
|
|
|
|
|
|
void mumble::MumbleCommunicator::receiveAudioFrameCallback(uint8_t *audio_data, uint32_t audio_data_size) {
|
|
|
|
|
int dataPointer = 1;
|
|
|
|
|
opus_int16 pcmData[1024];
|
|
|
|
|
|
|
|
|
|
if (audio_data[0] == 0x80) {
|
|
|
|
|
int64_t sessionId;
|
|
|
|
|
int64_t sequenceNumber;
|
|
|
|
|
int64_t opusDataLength;
|
|
|
|
|
bool lastPacket;
|
|
|
|
|
|
|
|
|
|
dataPointer += mumble_parse_variant(&sessionId, &audio_data[dataPointer]);
|
|
|
|
|
dataPointer += mumble_parse_variant(&sequenceNumber, &audio_data[dataPointer]);
|
|
|
|
|
dataPointer += mumble_parse_variant(&opusDataLength, &audio_data[dataPointer]);
|
|
|
|
|
|
|
|
|
|
lastPacket = (opusDataLength & 0x2000) != 0;
|
|
|
|
|
opusDataLength = opusDataLength & 0x1fff;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int iAudioBufferSize;
|
|
|
|
|
unsigned int iFrameSize = mumble::SAMPLE_RATE / 100;
|
|
|
|
|
iAudioBufferSize = iFrameSize;
|
|
|
|
|
iAudioBufferSize *= 12;
|
2015-09-29 02:26:45 +02:00
|
|
|
|
int decodedSamples = opus_decode(opusDecoder,
|
2015-09-28 23:25:12 +02:00
|
|
|
|
reinterpret_cast<const unsigned char *>(&audio_data[dataPointer]),
|
|
|
|
|
opusDataLength,
|
|
|
|
|
pcmData,
|
|
|
|
|
iAudioBufferSize,
|
|
|
|
|
0);
|
|
|
|
|
|
2015-10-04 22:30:10 +02:00
|
|
|
|
fileHandle.write(pcmData, decodedSamples);
|
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
logger.debug("Received %d bytes of Opus data (seq %ld), decoded to %d bytes. Push it to outputQueue.",
|
|
|
|
|
opusDataLength, sequenceNumber, decodedSamples);
|
|
|
|
|
|
2015-10-16 22:41:37 +02:00
|
|
|
|
samplesBuffer.pushSamples(pcmData, decodedSamples);
|
2015-10-04 22:30:10 +02:00
|
|
|
|
|
2015-09-28 23:25:12 +02:00
|
|
|
|
} else {
|
2015-09-29 02:26:45 +02:00
|
|
|
|
logger.warn("Received %d bytes of non-recognisable audio data.", audio_data_size);
|
2015-09-28 23:25:12 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mumble_audio_callback(uint8_t *audio_data, uint32_t audio_data_size, void *userData) {
|
|
|
|
|
mumble::MumbleCommunicator *mumbleCommunicator = static_cast<mumble::MumbleCommunicator *>(userData);
|
|
|
|
|
mumbleCommunicator->receiveAudioFrameCallback(audio_data, audio_data_size);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
static void mumble_serversync_callback(char *welcome_text,
|
|
|
|
|
int32_t session,
|
|
|
|
|
int32_t max_bandwidth,
|
|
|
|
|
int64_t permissions,
|
2015-10-04 22:30:10 +02:00
|
|
|
|
void *usterData) {
|
2015-09-29 02:26:45 +02:00
|
|
|
|
printf("%s\n", welcome_text);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-17 22:27:37 +02:00
|
|
|
|
void mumble_cryptsetup_callback(uint32_t key_size,
|
|
|
|
|
uint8_t *key,
|
|
|
|
|
uint32_t client_nonce_size,
|
|
|
|
|
uint8_t *client_nonce,
|
|
|
|
|
uint32_t server_nonce_size,
|
|
|
|
|
uint8_t *server_nonce,
|
|
|
|
|
void *userData) {
|
|
|
|
|
mumble::MumbleCommunicator *mumbleCommunicator = static_cast<mumble::MumbleCommunicator *>(userData);
|
|
|
|
|
printf("received crypto nonce\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
static int verify_cert(uint8_t *, uint32_t) {
|
|
|
|
|
// Accept every cert
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2015-09-28 23:25:12 +02:00
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
mumble::MumbleCommunicator::MumbleCommunicator(
|
2015-10-16 22:41:37 +02:00
|
|
|
|
ISamplesBuffer &samplesBuffer,
|
2015-09-29 02:26:45 +02:00
|
|
|
|
std::string user,
|
|
|
|
|
std::string password,
|
|
|
|
|
std::string host,
|
2015-10-16 22:41:37 +02:00
|
|
|
|
int port) : samplesBuffer(samplesBuffer),
|
2015-09-29 02:26:45 +02:00
|
|
|
|
outgoingAudioSequenceNumber(1),
|
|
|
|
|
logger(log4cpp::Category::getInstance("MumbleCommunicator")) {
|
2015-09-28 23:25:12 +02:00
|
|
|
|
|
2015-10-16 22:41:37 +02:00
|
|
|
|
quit = false;
|
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
opusDecoder = opus_decoder_create(SAMPLE_RATE, 1, nullptr); //todo grab error
|
2015-10-04 22:30:10 +02:00
|
|
|
|
|
2015-09-29 02:26:45 +02:00
|
|
|
|
opusEncoder = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, nullptr);
|
2015-10-04 22:30:10 +02:00
|
|
|
|
opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0));
|
|
|
|
|
|
|
|
|
|
fileHandle = SndfileHandle("capture_mumble.wav", SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 1, SAMPLE_RATE);
|
2015-09-28 23:25:12 +02:00
|
|
|
|
|
|
|
|
|
struct mumble_config config;
|
|
|
|
|
std::memset(&config, 0, sizeof(config));
|
|
|
|
|
|
|
|
|
|
config.user_data = this;
|
|
|
|
|
|
|
|
|
|
config.size = sizeof(config);
|
|
|
|
|
config.host = const_cast<char *>(host.c_str());
|
|
|
|
|
if (port > 0) {
|
|
|
|
|
config.port = const_cast<char *>(std::to_string(port).c_str());
|
|
|
|
|
}
|
|
|
|
|
config.server_password = const_cast<char *>(password.c_str());
|
|
|
|
|
config.username = const_cast<char *>(user.c_str());
|
|
|
|
|
config.user_cert_filename = nullptr;
|
|
|
|
|
config.user_privkey_filename = nullptr;
|
|
|
|
|
|
|
|
|
|
config.ssl_verification_callback = verify_cert;
|
|
|
|
|
config.audio_callback = mumble_audio_callback;
|
|
|
|
|
config.serversync_callback = mumble_serversync_callback;
|
2015-10-17 22:27:37 +02:00
|
|
|
|
config.cryptsetup_callback = mumble_cryptsetup_callback;
|
2015-09-28 23:25:12 +02:00
|
|
|
|
|
|
|
|
|
mumble = mumble_connect(nullptr, &config);
|
|
|
|
|
|
|
|
|
|
if (mumble == nullptr) {
|
|
|
|
|
throw mumble::Exception("couldn't establish mumble connection");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mumble::MumbleCommunicator::~MumbleCommunicator() {
|
|
|
|
|
mumble_close(mumble);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mumble::MumbleCommunicator::loop() {
|
2015-09-29 02:26:45 +02:00
|
|
|
|
|
2015-10-17 22:27:37 +02:00
|
|
|
|
senderThread.reset(new std::thread(&MumbleCommunicator::senderThreadFunction, this));
|
2015-09-29 02:26:45 +02:00
|
|
|
|
|
2015-10-16 22:41:37 +02:00
|
|
|
|
while (!quit) {
|
2015-09-28 23:25:12 +02:00
|
|
|
|
int status = mumble_tick(mumble);
|
2015-10-16 22:41:37 +02:00
|
|
|
|
logger.debug("tick");
|
2015-09-28 23:25:12 +02:00
|
|
|
|
if (status < 0) {
|
|
|
|
|
throw mumble::Exception("mumble_tick status " + status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//todo Other processing here?
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-16 22:41:37 +02:00
|
|
|
|
void mumble::MumbleCommunicator::senderThreadFunction() {
|
|
|
|
|
while (!quit) {
|
|
|
|
|
opus_int16 pcmData[1024];
|
|
|
|
|
unsigned char outputBuffer[1024];
|
|
|
|
|
|
2015-10-17 22:27:37 +02:00
|
|
|
|
int pcmLength = samplesBuffer.pullSamples(pcmData, 480, true);
|
2015-10-16 22:41:37 +02:00
|
|
|
|
|
|
|
|
|
logger.debug("Pop %d samples from inputQueue.", pcmLength);
|
|
|
|
|
|
|
|
|
|
int encodedSamples = opus_encode(opusEncoder, pcmData, pcmLength, outputBuffer, sizeof(outputBuffer));
|
|
|
|
|
|
|
|
|
|
if (encodedSamples < 1) {
|
|
|
|
|
logger.warn("opus_encode returned %d: %s", encodedSamples, opus_strerror(encodedSamples));
|
|
|
|
|
} else {
|
2015-10-17 22:27:37 +02:00
|
|
|
|
logger.debug("Sending %d bytes of Opus audio data (seq %d).", encodedSamples,
|
|
|
|
|
outgoingAudioSequenceNumber);
|
|
|
|
|
|
|
|
|
|
//todo to powinno dać się bezpiecznie wykonać w osobnym wątku
|
|
|
|
|
mumble_send_audio_data(mumble, outgoingAudioSequenceNumber, outputBuffer, encodedSamples);
|
|
|
|
|
|
|
|
|
|
outgoingAudioSequenceNumber += 1;
|
2015-10-16 22:41:37 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|