Move Mumble code to MumbleCommunicator class.
This commit is contained in:
parent
171e6021d1
commit
795405d218
@ -16,7 +16,7 @@ include_directories(${PJSIP_INCLUDE_DIRS})
|
|||||||
link_directories(libmumble)
|
link_directories(libmumble)
|
||||||
|
|
||||||
set(SOURCE_FILES main.cpp PjsuaCommunicator.cpp PjsuaMediaPort.cpp)
|
set(SOURCE_FILES main.cpp PjsuaCommunicator.cpp PjsuaMediaPort.cpp)
|
||||||
add_executable(mumsi ${SOURCE_FILES})
|
add_executable(mumsi ${SOURCE_FILES} MumbleCommunicator.cpp MumbleCommunicator.hpp)
|
||||||
target_link_libraries(mumsi ${OPUS_LIBRARIES})
|
target_link_libraries(mumsi ${OPUS_LIBRARIES})
|
||||||
target_link_libraries(mumsi ${SNDFILE_LIBRARIES})
|
target_link_libraries(mumsi ${SNDFILE_LIBRARIES})
|
||||||
target_link_libraries(mumsi ${PJSIP_LIBRARIES})
|
target_link_libraries(mumsi ${PJSIP_LIBRARIES})
|
||||||
|
107
MumbleCommunicator.cpp
Normal file
107
MumbleCommunicator.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "MumbleCommunicator.hpp"
|
||||||
|
|
||||||
|
void mumble_serversync_callback(char *welcome_text,
|
||||||
|
int32_t session,
|
||||||
|
int32_t max_bandwidth,
|
||||||
|
int64_t permissions,
|
||||||
|
void *userData) {
|
||||||
|
printf("%s\n", welcome_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_cert(uint8_t *, uint32_t) {
|
||||||
|
// Accept every cert
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
int decodedSamples = opus_decode(opusState,
|
||||||
|
reinterpret_cast<const unsigned char *>(&audio_data[dataPointer]),
|
||||||
|
opusDataLength,
|
||||||
|
pcmData,
|
||||||
|
iAudioBufferSize,
|
||||||
|
0);
|
||||||
|
|
||||||
|
printf("\nsessionId: %ld, seqNum: %ld, opus data len: %ld, last: %d, pos: %ld, decoded: %d\n",
|
||||||
|
sessionId, sequenceNumber, opusDataLength, lastPacket, dataPointer, decodedSamples);
|
||||||
|
} else {
|
||||||
|
printf("I received %d bytes of audio data\n", audio_data_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mumble::MumbleCommunicator::MumbleCommunicator(std::string user, std::string password, std::string host, int port) {
|
||||||
|
|
||||||
|
opusState = opus_decoder_create(SAMPLE_RATE, 1, nullptr); //todo grab error
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
int quit = 0;
|
||||||
|
while (quit == 0) {
|
||||||
|
int status = mumble_tick(mumble);
|
||||||
|
if (status < 0) {
|
||||||
|
throw mumble::Exception("mumble_tick status " + status);
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo Other processing here?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
37
MumbleCommunicator.hpp
Normal file
37
MumbleCommunicator.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef MUMSI_MUMBLECOMMUNICATOR_HPP
|
||||||
|
#define MUMSI_MUMBLECOMMUNICATOR_HPP
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "libmumble.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <opus.h>
|
||||||
|
|
||||||
|
namespace mumble {
|
||||||
|
|
||||||
|
constexpr unsigned int SAMPLE_RATE = 48000;
|
||||||
|
|
||||||
|
class Exception : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
Exception(const char *message) : std::runtime_error(message) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MumbleCommunicator {
|
||||||
|
public:
|
||||||
|
MumbleCommunicator(std::string user, std::string password, std::string host, int port = 0);
|
||||||
|
|
||||||
|
~MumbleCommunicator();
|
||||||
|
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
void receiveAudioFrameCallback(uint8_t *audio_data, uint32_t audio_data_size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mumble_struct *mumble;
|
||||||
|
OpusDecoder *opusState;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //MUMSI_MUMBLECOMMUNICATOR_HPP
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace pjsua {
|
namespace pjsua {
|
||||||
|
|
||||||
constexpr int SAMPLING_RATE = 8000;
|
constexpr int SAMPLING_RATE = 48000;
|
||||||
|
|
||||||
inline pj_str_t toPjString(std::string str) {
|
inline pj_str_t toPjString(std::string str) {
|
||||||
return pj_str(const_cast<char *>(str.c_str()));
|
return pj_str(const_cast<char *>(str.c_str()));
|
||||||
|
239
main.cpp
239
main.cpp
@ -1,240 +1,29 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include "PjsuaCommunicator.hpp"
|
||||||
#include <string.h>
|
#include "PjsuaMediaPort.hpp"
|
||||||
#include <sndfile.hh>
|
#include "MumbleCommunicator.hpp"
|
||||||
#include <opus.h>
|
|
||||||
#include <pjsua-lib/pjsua.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "libmumble.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int SAMPLE_RATE =48000;
|
|
||||||
OpusDecoder *opusState;
|
|
||||||
SndfileHandle fileHandle;
|
|
||||||
|
|
||||||
static int verify_cert(uint8_t *x509_pem_certificates, uint32_t size) {
|
|
||||||
printf("I received a buffer of %d bytes!\n", size);
|
|
||||||
const char FILENAME[] = "/tmp/cert";
|
|
||||||
|
|
||||||
FILE *outfile = fopen(FILENAME, "wb");
|
|
||||||
if (outfile != NULL) {
|
|
||||||
fwrite(x509_pem_certificates, 1, size, outfile);
|
|
||||||
fclose(outfile);
|
|
||||||
printf("Written to %s\n", FILENAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept every cert
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_version_callback(uint16_t major, uint8_t minor, uint8_t patch, char *release, char *os, char *os_version) {
|
|
||||||
printf("Version Callback: v%d.%d.%d. %s/%s/%s\n", major, minor, patch, release, os, os_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_audio_callback(uint8_t *audio_data, uint32_t audio_data_size) {
|
|
||||||
int dataPointer = 1;
|
|
||||||
float pcmData[1000];
|
|
||||||
|
|
||||||
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;
|
#define SIP_DOMAIN "sip.antisip.com"
|
||||||
unsigned int iFrameSize = SAMPLE_RATE / 100;
|
#define SIP_USER "melangtone"
|
||||||
iAudioBufferSize = iFrameSize;
|
#define SIP_PASSWD "b8DU9AZXbd9tVCWg"
|
||||||
iAudioBufferSize *= 12;
|
|
||||||
int decodedSamples = opus_decode_float(opusState,
|
|
||||||
reinterpret_cast<const unsigned char *>(&audio_data[dataPointer]),
|
|
||||||
opusDataLength,
|
|
||||||
pcmData,
|
|
||||||
iAudioBufferSize,
|
|
||||||
0);
|
|
||||||
|
|
||||||
printf("\nsessionId: %ld, seqNum: %ld, opus data len: %ld, last: %d, pos: %ld, decoded: %d\n",
|
#define MUMBLE_DOMAIN "1con.pl"
|
||||||
sessionId, sequenceNumber, opusDataLength, lastPacket, dataPointer, decodedSamples);
|
#define MUMBLE_USER "mumsi"
|
||||||
|
#define MUMBLE_PASSWD "kiwi"
|
||||||
fileHandle.write(pcmData, decodedSamples);
|
|
||||||
}
|
|
||||||
printf("I received %d bytes of audio data\n", audio_data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_serversync_callback(char *welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) {
|
|
||||||
printf("%s\n", welcome_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_channelremove_callback(uint32_t channel_id) {
|
|
||||||
printf("Channel %d removed\n", channel_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_channelstate_callback(char *name, int32_t channel_id, int32_t parent, char *description, uint32_t *links,
|
|
||||||
uint32_t n_links, uint32_t *links_add, uint32_t n_links_add, uint32_t *links_remove,
|
|
||||||
uint32_t n_links_remove, int32_t temporary, int32_t position) {
|
|
||||||
printf("Obtained channel state\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_userremove_callback(uint32_t session, int32_t actor, char *reason, int32_t ban) {
|
|
||||||
printf("User %d removed\n", actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_userstate_callback(int32_t session, int32_t actor, char *name, int32_t user_id, int32_t channel_id,
|
|
||||||
int32_t mute, int32_t deaf, int32_t suppress, int32_t self_mute, int32_t self_deaf,
|
|
||||||
char *comment, int32_t priority_speaker, int32_t recording) {
|
|
||||||
printf("userstate_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_banlist_callback(uint8_t *ip_data, uint32_t ip_data_size, uint32_t mask, char *name, char *hash,
|
|
||||||
char *reason, char *start, int32_t duration) {
|
|
||||||
printf("banlist_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_textmessage_callback(uint32_t actor, uint32_t n_session, uint32_t *session, uint32_t n_channel_id,
|
|
||||||
uint32_t *channel_id, uint32_t n_tree_id, uint32_t *tree_id, char *message) {
|
|
||||||
printf("textmessage_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_permissiondenied_callback(int32_t permission, int32_t channel_id, int32_t session, char *reason,
|
|
||||||
int32_t deny_type, char *name) {
|
|
||||||
printf("permissiondenied_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_acl_callback(void) {
|
|
||||||
printf("acl_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_queryusers_callback(uint32_t n_ids, uint32_t *ids, uint32_t n_names, char **names) {
|
|
||||||
printf("queryusers_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
printf("cryptsetup_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_contextactionmodify_callback(char *action, char *text, uint32_t m_context, uint32_t operation) {
|
|
||||||
printf("contextactionmodify_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_contextaction_callback(int32_t session, int32_t channel_id, char *action) {
|
|
||||||
printf("contextaction_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_userlist_callback(uint32_t user_id, char *name, char *last_seen, int32_t last_channel) {
|
|
||||||
printf("userlist_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_voicetarget_callback(void) {
|
|
||||||
printf("voicetarget_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_permissionquery_callback(int32_t channel_id, uint32_t permissions, int32_t flush) {
|
|
||||||
printf("permissionquery_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_codecversion_callback(int32_t alpha, int32_t beta, uint32_t prefer_alpha, int32_t opus) {
|
|
||||||
printf("codecversion_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_userstats_callback(void) {
|
|
||||||
printf("userstats_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_requestblob_callback(void) {
|
|
||||||
printf("requestblob_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_serverconfig_callback(uint32_t max_bandwidth, char *welcome_text, uint32_t allow_html,
|
|
||||||
uint32_t message_length, uint32_t image_message_length) {
|
|
||||||
printf("serverconfig_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void mumble_suggestconfig_callback(uint32_t version, uint32_t positional, uint32_t push_to_talk) {
|
|
||||||
printf("suggestconfig_callback\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 2) {
|
|
||||||
printf("Usage: %s <mumble server ip> [mumble server port] [server password]\n", argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *host = argv[1];
|
mumble::MumbleCommunicator mumbleCommunicator(MUMBLE_USER, MUMBLE_PASSWD, MUMBLE_DOMAIN);
|
||||||
char *port = "64738";
|
|
||||||
char *password = "hello";
|
|
||||||
if (argc >= 3) {
|
|
||||||
port = argv[2];
|
|
||||||
}
|
|
||||||
if (argc >= 4) {
|
|
||||||
password = argv[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
opusState = opus_decoder_create(SAMPLE_RATE, 1, nullptr);
|
pjsua::PjsuaMediaPort mediaPort;
|
||||||
|
pjsua::PjsuaCommunicator pjsuaCommunicator(SIP_DOMAIN, SIP_USER, SIP_PASSWD, mediaPort);
|
||||||
|
|
||||||
fileHandle = SndfileHandle("capture.wav", SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, SAMPLE_RATE);
|
|
||||||
|
|
||||||
struct mumble_config config;
|
pjsuaCommunicator.loop();
|
||||||
memset(&config, 0, sizeof(config));
|
|
||||||
config.size = sizeof(config);
|
|
||||||
config.host = host;
|
|
||||||
config.port = port;
|
|
||||||
config.server_password = password;
|
|
||||||
config.username = "example_username";
|
|
||||||
config.user_cert_filename = NULL;
|
|
||||||
config.user_privkey_filename = NULL;
|
|
||||||
config.ssl_verification_callback = verify_cert;
|
|
||||||
|
|
||||||
config.version_callback = mumble_version_callback;
|
mumbleCommunicator.loop();
|
||||||
config.audio_callback = mumble_audio_callback;
|
|
||||||
config.serversync_callback = mumble_serversync_callback;
|
|
||||||
config.channelremove_callback = mumble_channelremove_callback;
|
|
||||||
config.channelstate_callback = mumble_channelstate_callback;
|
|
||||||
config.userremove_callback = mumble_userremove_callback;
|
|
||||||
config.userstate_callback = mumble_userstate_callback;
|
|
||||||
config.banlist_callback = mumble_banlist_callback;
|
|
||||||
config.textmessage_callback = mumble_textmessage_callback;
|
|
||||||
config.permissiondenied_callback = mumble_permissiondenied_callback;
|
|
||||||
config.acl_callback = mumble_acl_callback;
|
|
||||||
config.queryusers_callback = mumble_queryusers_callback;
|
|
||||||
config.cryptsetup_callback = mumble_cryptsetup_callback;
|
|
||||||
config.contextactionmodify_callback = mumble_contextactionmodify_callback;
|
|
||||||
config.contextaction_callback = mumble_contextaction_callback;
|
|
||||||
config.userlist_callback = mumble_userlist_callback;
|
|
||||||
config.voicetarget_callback = mumble_voicetarget_callback;
|
|
||||||
config.permissionquery_callback = mumble_permissionquery_callback;
|
|
||||||
config.codecversion_callback = mumble_codecversion_callback;
|
|
||||||
config.userstats_callback = mumble_userstats_callback;
|
|
||||||
config.requestblob_callback = mumble_requestblob_callback;
|
|
||||||
config.serverconfig_callback = mumble_serverconfig_callback;
|
|
||||||
config.suggestconfig_callback = mumble_suggestconfig_callback;
|
|
||||||
|
|
||||||
struct mumble_struct *mumble = mumble_connect(NULL, &config);
|
|
||||||
if (mumble == NULL) {
|
|
||||||
printf("Couldn't establish mumble connection\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start processing here?
|
|
||||||
|
|
||||||
int quit = 0;
|
|
||||||
while (quit == 0) {
|
|
||||||
if (mumble_tick(mumble) < 0) {
|
|
||||||
quit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other processing here?
|
|
||||||
}
|
|
||||||
|
|
||||||
mumble_close(mumble);
|
|
||||||
|
|
||||||
printf("Done\n");
|
printf("Done\n");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user