diff --git a/CMakeLists.txt b/CMakeLists.txt index 5de41e4..b1daef4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,12 +9,9 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(PJSIP "libpjproject") pkg_check_modules(LOG4CPP "log4cpp") -pkg_check_modules(SNDFILE "sndfile") - include_directories(${PJSIP_INCLUDE_DIRS}) include_directories(${LOG4CPP_INCLUDE_DIRS}) -include_directories(${SNDFILE_INCLUDE_DIRS}) include_directories(../mumlib/include) link_directories(../mumlib/build) @@ -24,7 +21,7 @@ set(SOURCE_FILES PjsuaCommunicator.hpp MumbleCommunicator.cpp MumbleCommunicator.hpp - ISamplesBuffer.hpp + ICommunicator.hpp Configuration.cpp Configuration.hpp) @@ -33,10 +30,8 @@ set(SOURCE_FILES #) add_executable(mumsi ${SOURCE_FILES} main.cpp) -target_link_libraries(mumsi ${OPUS_LIBRARIES}) target_link_libraries(mumsi ${PJSIP_LIBRARIES}) target_link_libraries(mumsi ${LOG4CPP_LIBRARIES}) -target_link_libraries(mumsi ${SNDFILE_LIBRARIES}) target_link_libraries(mumsi ${Boost_LIBRARIES}) target_link_libraries(mumsi mumlib) diff --git a/Configuration.hpp b/Configuration.hpp index 2c5ec1c..b08a526 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -1,5 +1,4 @@ -#ifndef CONFIGURATION_HPP_ -#define CONFIGURATION_HPP_ +#pragma once #include #include @@ -35,5 +34,3 @@ namespace config { ConfigurationImpl *impl; }; } - -#endif /* CONFIGURATION_HPP_ */ diff --git a/ICommunicator.hpp b/ICommunicator.hpp new file mode 100644 index 0000000..f8ca9e0 --- /dev/null +++ b/ICommunicator.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +class ICommunicator { +public: + /** + * Send samples through the Communicator. + */ + virtual void sendPcmSamples(int16_t *samples, unsigned int length) = 0; + + /** + * This callback is called when Communicator has received samples. + */ + std::function onIncomingPcmSamples; +}; diff --git a/ISamplesBuffer.hpp b/ISamplesBuffer.hpp deleted file mode 100644 index b5f4750..0000000 --- a/ISamplesBuffer.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef MUMSI_ISAMPLESBUFFER_HPP -#define MUMSI_ISAMPLESBUFFER_HPP - -#include - -class ISamplesBuffer { -public: - virtual void pushSamples(int16_t *samples, unsigned int length) = 0; - -// virtual unsigned int pullSamples(int16_t *samples, unsigned int length, bool waitWhenEmpty) = 0; -}; - - -#endif //MUMSI_ISAMPLESBUFFER_HPP diff --git a/MumbleCommunicator.cpp b/MumbleCommunicator.cpp index f4a93f8..9f19537 100644 --- a/MumbleCommunicator.cpp +++ b/MumbleCommunicator.cpp @@ -12,22 +12,21 @@ namespace mumble { virtual void audio( int16_t *pcm_data, uint32_t pcm_data_size) { - communicator->samplesBuffer.pushSamples(pcm_data, pcm_data_size); + communicator->onIncomingPcmSamples(pcm_data, pcm_data_size); } }; } -mumble::MumbleCommunicator::MumbleCommunicator( - boost::asio::io_service &ioService, - ISamplesBuffer &samplesBuffer, +mumble::MumbleCommunicator::MumbleCommunicator(boost::asio::io_service &ioService) + : ioService(ioService), + logger(log4cpp::Category::getInstance("MumbleCommunicator")) { +} + +void mumble::MumbleCommunicator::connect( std::string user, std::string password, std::string host, - int port) : ioService(ioService), - samplesBuffer(samplesBuffer), - logger(log4cpp::Category::getInstance("MumbleCommunicator")) { - - quit = false; + int port) { callback.reset(new MumlibCallback()); @@ -38,7 +37,7 @@ mumble::MumbleCommunicator::MumbleCommunicator( mum->connect(host, port, user, password); } -void mumble::MumbleCommunicator::sendAudioFrame(int16_t *samples, int length) { +void mumble::MumbleCommunicator::sendPcmSamples(int16_t *samples, unsigned int length) { mum->sendAudioData(samples, length); } diff --git a/MumbleCommunicator.hpp b/MumbleCommunicator.hpp index 4f39143..259c0f3 100644 --- a/MumbleCommunicator.hpp +++ b/MumbleCommunicator.hpp @@ -1,14 +1,12 @@ -#ifndef MUMSI_MUMBLECOMMUNICATOR_HPP -#define MUMSI_MUMBLECOMMUNICATOR_HPP +#pragma once + +#include "ICommunicator.hpp" -#include "ISamplesBuffer.hpp" #include #include #include #include -#include -#include namespace mumble { @@ -19,11 +17,12 @@ namespace mumble { class MumlibCallback; - class MumbleCommunicator { + class MumbleCommunicator : public ICommunicator { public: MumbleCommunicator( - boost::asio::io_service &ioService, - ISamplesBuffer &samplesBuffer, + boost::asio::io_service &ioService); + + void connect( std::string user, std::string password, std::string host, @@ -31,31 +30,17 @@ namespace mumble { ~MumbleCommunicator(); -// void senderThreadFunction(); - - //void receiveAudioFrameCallback(uint8_t *audio_data, uint32_t audio_data_size); - - void sendAudioFrame(int16_t *samples, int length); + virtual void sendPcmSamples(int16_t *samples, unsigned int length); public: boost::asio::io_service &ioService; log4cpp::Category &logger; - ISamplesBuffer &samplesBuffer; - std::shared_ptr mum; - std::unique_ptr senderThread; - - SndfileHandle fileHandle; - std::unique_ptr callback; - bool quit; - friend class MumlibCallback; }; } - -#endif //MUMSI_MUMBLECOMMUNICATOR_HPP diff --git a/PjsuaCommunicator.cpp b/PjsuaCommunicator.cpp index 7b81c7b..f61c936 100644 --- a/PjsuaCommunicator.cpp +++ b/PjsuaCommunicator.cpp @@ -3,22 +3,17 @@ #include #include - -#include - -#include - -//todo wywalić -#define THIS_FILE "mumsi" +#include using namespace std; - /** * This is global, because there's no way to pass it's value to onCallMediaState callback. */ static int mediaPortSlot; +static log4cpp::Category &pjLogger = log4cpp::Category::getInstance("PjSip"); + static void onCallMediaState(pjsua_call_id call_id) { pjsua_call_info ci; @@ -41,9 +36,7 @@ static void onIncomingCall(pjsua_acc_id acc_id, pjsua_call_get_info(call_id, &ci); - PJ_LOG(3, (THIS_FILE, "Incoming call from %.*s!!", - (int) ci.remote_info.slen, - ci.remote_info.ptr)); + pjLogger.notice("Incoming call from %s.", ci.remote_info.ptr); /* Automatically answer incoming calls with 200/OK */ pjsua_call_answer(call_id, 200, NULL, NULL); @@ -56,23 +49,30 @@ static void onCallState(pjsua_call_id call_id, PJ_UNUSED_ARG(e); pjsua_call_get_info(call_id, &ci); - PJ_LOG(3, (THIS_FILE, "Call %d state=%.*s", call_id, - (int) ci.state_text.slen, - ci.state_text.ptr)); + pjLogger.notice("Call %d state=%s.", call_id, ci.state_text.ptr); +} + +static void pjLogToLog4CppBridgeFunction(int level, const char *data, int len) { + using namespace log4cpp; + std::map prioritiesMap = { + {1, Priority::ERROR}, + {2, Priority::WARN}, + {3, Priority::NOTICE}, + {4, Priority::INFO}, + {5, Priority::DEBUG}, + {6, Priority::DEBUG} + }; + + string message(data); + + message = message.substr(0, message.size() - 1); // remove newline + + pjLogger << prioritiesMap.at(level) << message; } sip::PjsuaCommunicator::PjsuaCommunicator() : logger(log4cpp::Category::getInstance("SipCommunicator")), callbackLogger(log4cpp::Category::getInstance("SipCommunicatorCallback")) { - -} - -void sip::PjsuaCommunicator::connect( - std::string host, - std::string user, - std::string password, - unsigned int port) { - pj_status_t status; status = pjsua_create(); @@ -80,6 +80,8 @@ void sip::PjsuaCommunicator::connect( throw sip::Exception("Error in pjsua_create()", status); } + pj_log_set_log_func(pjLogToLog4CppBridgeFunction); + pjsua_config generalConfig; pjsua_config_default(&generalConfig); @@ -90,11 +92,10 @@ void sip::PjsuaCommunicator::connect( generalConfig.cb.on_call_media_state = &onCallMediaState; generalConfig.cb.on_call_state = &onCallState; - //todo zrobić coś z logami pjsua_logging_config logConfig; pjsua_logging_config_default(&logConfig); - - logConfig.console_level = 4; + logConfig.cb = pjLogToLog4CppBridgeFunction; + logConfig.console_level = 5; status = pjsua_init(&generalConfig, &logConfig, NULL); if (status != PJ_SUCCESS) { @@ -103,7 +104,25 @@ void sip::PjsuaCommunicator::connect( pjsua_set_null_snd_dev(); - /* Add UDP transport. */ + pj_caching_pool cachingPool; + pj_caching_pool_init(&cachingPool, &pj_pool_factory_default_policy, 0); + pj_pool_t *pool = pj_pool_create(&cachingPool.factory, "wav", 32768, 8192, nullptr); + + // todo calculate sizes + pjmedia_circ_buf_create(pool, 960 * 10, &inputBuff); + + mediaPort = createMediaPort(); + + pjsua_conf_add_port(pool, mediaPort, &mediaPortSlot); +} + +void sip::PjsuaCommunicator::connect( + std::string host, + std::string user, + std::string password, + unsigned int port) { + pj_status_t status; + pjsua_transport_config transportConfig; pjsua_transport_config_default(&transportConfig); @@ -114,18 +133,6 @@ void sip::PjsuaCommunicator::connect( throw sip::Exception("Error creating transport", status); } - pj_caching_pool cachingPool; - pj_caching_pool_init(&cachingPool, &pj_pool_factory_default_policy, 0); - pj_pool_t *pool = pj_pool_create(&cachingPool.factory, "wav", 32768, 8192, nullptr); - - // create circular buffers - pjmedia_circ_buf_create(pool, 960 * 10, &inputBuff); - pjmedia_circ_buf_create(pool, 960 * 10, &outputBuff); - - mediaPort = createMediaPort(); - - pjsua_conf_add_port(pool, mediaPort, &mediaPortSlot); - /* Initialization is done, now start sip */ status = pjsua_start(); if (status != PJ_SUCCESS) { @@ -210,16 +217,9 @@ pj_status_t sip::PjsuaCommunicator::mediaPortGetFrame(pjmedia_frame *frame) { } void sip::PjsuaCommunicator::mediaPortPutFrame(pj_int16_t *samples, pj_size_t count) { -// std::unique_lock lock(outBuffAccessMutex); -// -// callbackLogger.debug("Pushing %d samples to out-buff.", count); -// pjmedia_circ_buf_write(outputBuff, samples, count); -// -// lock.unlock(); -// -// outBuffCondVar.notify_all(); if (count > 0) { - onIncomingSamples(samples, count); + callbackLogger.debug("Calling onIncomingPcmSamples with %d samples.", count); + onIncomingPcmSamples(samples, count); } } @@ -228,7 +228,18 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa pjsua_acc_config accConfig; pjsua_acc_config_default(&accConfig); - accConfig.id = toPjString(string("sip:") + user + "@" + host); + string uri = string("sip:") + user + "@" + host; + + pj_status_t status; + + status = pjsua_verify_sip_url(uri.c_str()); + if (status != PJ_SUCCESS) { + throw sip::Exception("failed to register account", status); + } + + logger.info("Registering account for URI: %s.", uri.c_str()); + + accConfig.id = toPjString(uri); accConfig.reg_uri = toPjString(string("sip:") + host); accConfig.cred_count = 1; @@ -240,32 +251,14 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa pjsua_acc_id acc_id; - pj_status_t status = pjsua_acc_add(&accConfig, PJ_TRUE, &acc_id); + status = pjsua_acc_add(&accConfig, PJ_TRUE, &acc_id); if (status != PJ_SUCCESS) { throw sip::Exception("failed to register account", status); } } -void sip::PjsuaCommunicator::pushSamples(int16_t *samples, unsigned int length) { +void sip::PjsuaCommunicator::sendPcmSamples(int16_t *samples, unsigned int length) { std::unique_lock lock(inBuffAccessMutex); callbackLogger.debug("Pushing %d samples to in-buff.", length); pjmedia_circ_buf_write(inputBuff, samples, length); } - -//unsigned int sip::PjsuaCommunicator::pullSamples(int16_t *samples, unsigned int length, bool waitWhenEmpty) { -// std::unique_lock lock(outBuffAccessMutex); -// -// unsigned int availableSamples; -// -// while ((availableSamples = pjmedia_circ_buf_get_len(inputBuff)) < length) { -// callbackLogger.debug("Not enough samples in buffer: %d, requested %d. Waiting.", availableSamples, length); -// outBuffCondVar.wait(lock); -// } -// -// const int samplesToRead = std::min(length, availableSamples); -// -// callbackLogger.debug("Pulling %d samples from out-buff.", samplesToRead); -// pjmedia_circ_buf_read(inputBuff, samples, samplesToRead); -// -// return samplesToRead; -//} diff --git a/PjsuaCommunicator.hpp b/PjsuaCommunicator.hpp index 58b0451..a6c85d4 100644 --- a/PjsuaCommunicator.hpp +++ b/PjsuaCommunicator.hpp @@ -1,7 +1,6 @@ -#ifndef MUMSI_PJSUACOMMUNICATOR_HPP -#define MUMSI_PJSUACOMMUNICATOR_HPP +#pragma once -#include "ISamplesBuffer.hpp" +#include "ICommunicator.hpp" #include @@ -44,7 +43,7 @@ namespace sip { pj_status_t MediaPort_putFrameRawCallback(pjmedia_port *port, pjmedia_frame *frame); - class PjsuaCommunicator : public ISamplesBuffer { + class PjsuaCommunicator : public ICommunicator { public: PjsuaCommunicator(); @@ -56,11 +55,7 @@ namespace sip { ~PjsuaCommunicator(); - virtual void pushSamples(int16_t *samples, unsigned int length); - - std::function onIncomingSamples; - -// virtual unsigned int pullSamples(int16_t *samples, unsigned int length, bool waitWhenEmpty); + virtual void sendPcmSamples(int16_t *samples, unsigned int length); private: log4cpp::Category &logger; @@ -70,14 +65,9 @@ namespace sip { pjmedia_port *mediaPort; pjmedia_circ_buf *inputBuff; - pjmedia_circ_buf *outputBuff; std::mutex inBuffAccessMutex; - std::mutex outBuffAccessMutex; - std::condition_variable outBuffCondVar; - - // todo make it completely stateless pjmedia_port *createMediaPort(); @@ -101,5 +91,3 @@ namespace sip { }; } - -#endif //MUMSI_PJSUACOMMUNICATOR_HPP diff --git a/main.cpp b/main.cpp index 82ee603..904aef4 100644 --- a/main.cpp +++ b/main.cpp @@ -26,27 +26,31 @@ int main(int argc, char *argv[]) { sip::PjsuaCommunicator pjsuaCommunicator; - mumble::MumbleCommunicator mumbleCommunicator( - ioService, - pjsuaCommunicator, + mumble::MumbleCommunicator mumbleCommunicator(ioService); + + using namespace std::placeholders; + pjsuaCommunicator.onIncomingPcmSamples = std::bind( + &mumble::MumbleCommunicator::sendPcmSamples, + &mumbleCommunicator, + _1, _2); + + mumbleCommunicator.onIncomingPcmSamples = std::bind( + &sip::PjsuaCommunicator::sendPcmSamples, + &pjsuaCommunicator, + _1, _2); + + mumbleCommunicator.connect( conf.getString("mumble.user"), conf.getString("mumble.password"), conf.getString("mumble.host"), conf.getInt("mumble.port")); - using namespace std::placeholders; - pjsuaCommunicator.onIncomingSamples = std::bind( - &mumble::MumbleCommunicator::sendAudioFrame, - &mumbleCommunicator, - _1, _2); - pjsuaCommunicator.connect( conf.getString("sip.host"), conf.getString("sip.user"), conf.getString("sip.password"), conf.getInt("sip.port")); - logger.info("Application started."); ioService.run();