Refactor current Mumble->SIP audio stream to separate AudioFramesMixer class. #1
This commit is contained in:
		
							parent
							
								
									0548fca0dd
								
							
						
					
					
						commit
						45f8536e09
					
				
							
								
								
									
										61
									
								
								AudioFramesMixer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								AudioFramesMixer.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | |||||||
|  | #include "AudioFramesMixer.hpp" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //// Reset mix buffer.
 | ||||||
|  | //Arrays.fill(tempMix, 0);
 | ||||||
|  | //
 | ||||||
|  | //// Sum the buffers.
 | ||||||
|  | //for (final AudioUser user : mix) {
 | ||||||
|  | //for (int i = 0; i < tempMix.length; i++) {
 | ||||||
|  | //tempMix[i] += user.lastFrame[i];
 | ||||||
|  | //}
 | ||||||
|  | //}
 | ||||||
|  | //
 | ||||||
|  | //// Clip buffer for real output.
 | ||||||
|  | //for (int i = 0; i < MumbleProtocol.FRAME_SIZE; i++) {
 | ||||||
|  | //clipOut[i] = (short) (Short.MAX_VALUE * (tempMix[i] < -1.0f ? -1.0f
 | ||||||
|  | //: (tempMix[i] > 1.0f ? 1.0f : tempMix[i])));
 | ||||||
|  | //}
 | ||||||
|  | 
 | ||||||
|  | mixer::AudioFramesMixer::AudioFramesMixer(pj_pool_factory &poolFactory) | ||||||
|  |         : logger(log4cpp::Category::getInstance("AudioFramesMixer")) { | ||||||
|  | 
 | ||||||
|  |     pool = pj_pool_create(&poolFactory, "media", 32768, 8192, nullptr); | ||||||
|  |     if (!pool) { | ||||||
|  |         throw mixer::Exception("error when creating memory pool"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // todo calculate sizes
 | ||||||
|  |     pj_status_t status = pjmedia_circ_buf_create(pool, 960 * 10, &inputBuff); | ||||||
|  |     if (status != PJ_SUCCESS) { | ||||||
|  |         throw mixer::Exception("error when creating circular buffer", status); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | mixer::AudioFramesMixer::~AudioFramesMixer() { | ||||||
|  |     if (pool != nullptr) { | ||||||
|  |         pj_pool_release(pool); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void mixer::AudioFramesMixer::addFrameToBuffer(int sessionId, int sequenceNumber, int16_t *samples, int samplesLength) { | ||||||
|  |     std::unique_lock<std::mutex> lock(inBuffAccessMutex); | ||||||
|  |     logger.debug("Pushing %d samples to in-buff.", samplesLength); | ||||||
|  |     pjmedia_circ_buf_write(inputBuff, samples, samplesLength); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int mixer::AudioFramesMixer::getMixedSamples(int16_t *mixedSamples, int requestedLength) { | ||||||
|  |     std::unique_lock<std::mutex> lock(inBuffAccessMutex); | ||||||
|  | 
 | ||||||
|  |     int availableSamples = pjmedia_circ_buf_get_len(inputBuff); | ||||||
|  |     const int samplesToRead = std::min(requestedLength, availableSamples); | ||||||
|  | 
 | ||||||
|  |     logger.debug("Pulling %d samples from in-buff.", samplesToRead); | ||||||
|  |     pjmedia_circ_buf_read(inputBuff, mixedSamples, samplesToRead); | ||||||
|  | 
 | ||||||
|  |     return samplesToRead; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void mixer::AudioFramesMixer::clean() { | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								AudioFramesMixer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								AudioFramesMixer.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <pjmedia.h> | ||||||
|  | 
 | ||||||
|  | #include <log4cpp/Category.hh> | ||||||
|  | #include <boost/noncopyable.hpp> | ||||||
|  | 
 | ||||||
|  | #include <mutex> | ||||||
|  | 
 | ||||||
|  | namespace mixer { | ||||||
|  | 
 | ||||||
|  |     class Exception : public std::runtime_error { | ||||||
|  |     public: | ||||||
|  |         Exception(const char *title) : std::runtime_error(title) { | ||||||
|  |             mesg += title; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Exception(const char *title, pj_status_t status) : std::runtime_error(title) { | ||||||
|  |             char errorMsgBuffer[500]; | ||||||
|  |             pj_strerror(status, errorMsgBuffer, sizeof(errorMsgBuffer)); | ||||||
|  | 
 | ||||||
|  |             mesg += title; | ||||||
|  |             mesg += ": "; | ||||||
|  |             mesg += errorMsgBuffer; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         virtual const char *what() const throw() override { | ||||||
|  |             return mesg.c_str(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         std::string mesg; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class AudioFramesMixer : boost::noncopyable { | ||||||
|  |     public: | ||||||
|  |         AudioFramesMixer(pj_pool_factory &poolFactory); | ||||||
|  | 
 | ||||||
|  |         virtual ~AudioFramesMixer(); | ||||||
|  | 
 | ||||||
|  |         void addFrameToBuffer(int sessionId, int sequenceNumber, int16_t *samples, int samplesLength); | ||||||
|  | 
 | ||||||
|  |         int getMixedSamples(int16_t *mixedSamples, int requestedLength); | ||||||
|  | 
 | ||||||
|  |         void clean(); | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         log4cpp::Category &logger; | ||||||
|  | 
 | ||||||
|  |         pj_pool_t *pool = nullptr; | ||||||
|  | 
 | ||||||
|  |         pjmedia_circ_buf *inputBuff; | ||||||
|  | 
 | ||||||
|  |         std::mutex inBuffAccessMutex; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -24,11 +24,12 @@ set(SOURCE_FILES | |||||||
|         PjsuaCommunicator.hpp |         PjsuaCommunicator.hpp | ||||||
|         MumbleCommunicator.cpp |         MumbleCommunicator.cpp | ||||||
|         MumbleCommunicator.hpp |         MumbleCommunicator.hpp | ||||||
|         ICommunicator.hpp |  | ||||||
|         Configuration.cpp |         Configuration.cpp | ||||||
|         Configuration.hpp |         Configuration.hpp | ||||||
|         IncomingConnectionValidator.cpp |         IncomingConnectionValidator.cpp | ||||||
|         IncomingConnectionValidator.hpp) |         IncomingConnectionValidator.hpp | ||||||
|  |         AudioFramesMixer.hpp | ||||||
|  |         AudioFramesMixer.cpp) | ||||||
| 
 | 
 | ||||||
| add_executable(mumsi ${SOURCE_FILES} main.cpp) | add_executable(mumsi ${SOURCE_FILES} main.cpp) | ||||||
| target_link_libraries(mumsi ${PJSIP_LIBRARIES}) | target_link_libraries(mumsi ${PJSIP_LIBRARIES}) | ||||||
|  | |||||||
| @ -1,17 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <functional> |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| 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<void(int16_t *, int)> onIncomingPcmSamples; |  | ||||||
| }; |  | ||||||
| @ -15,7 +15,7 @@ namespace mumble { | |||||||
|                 int sequenceNumber, |                 int sequenceNumber, | ||||||
|                 int16_t *pcm_data, |                 int16_t *pcm_data, | ||||||
|                 uint32_t pcm_data_size) override { |                 uint32_t pcm_data_size) override { | ||||||
|             communicator->onIncomingPcmSamples(pcm_data, pcm_data_size); |             communicator->onIncomingPcmSamples(sessionId, sequenceNumber, pcm_data, pcm_data_size); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "ICommunicator.hpp" |  | ||||||
| 
 |  | ||||||
| #include <mumlib.hpp> | #include <mumlib.hpp> | ||||||
| 
 | 
 | ||||||
| #include <log4cpp/Category.hh> | #include <log4cpp/Category.hh> | ||||||
| @ -19,7 +17,7 @@ namespace mumble { | |||||||
| 
 | 
 | ||||||
|     class MumlibCallback; |     class MumlibCallback; | ||||||
| 
 | 
 | ||||||
|     class MumbleCommunicator : public ICommunicator, boost::noncopyable { |     class MumbleCommunicator : boost::noncopyable { | ||||||
|     public: |     public: | ||||||
|         MumbleCommunicator( |         MumbleCommunicator( | ||||||
|                 boost::asio::io_service &ioService); |                 boost::asio::io_service &ioService); | ||||||
| @ -30,9 +28,15 @@ namespace mumble { | |||||||
|                 std::string host, |                 std::string host, | ||||||
|                 int port = 0); |                 int port = 0); | ||||||
| 
 | 
 | ||||||
|         ~MumbleCommunicator(); |         virtual ~MumbleCommunicator(); | ||||||
| 
 | 
 | ||||||
|         virtual void sendPcmSamples(int16_t *samples, unsigned int length) override; |         void sendPcmSamples(int16_t *samples, unsigned int length); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * This callback is called when communicator has received samples. | ||||||
|  |          * Arguments: session ID, sequence number, PCM samples, length of samples | ||||||
|  |          */ | ||||||
|  |         std::function<void(int, int, int16_t *, int)> onIncomingPcmSamples; | ||||||
| 
 | 
 | ||||||
|         void sendTextMessage(std::string message); |         void sendTextMessage(std::string message); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -226,19 +226,9 @@ sip::PjsuaCommunicator::PjsuaCommunicator(IncomingConnectionValidator &validator | |||||||
| 
 | 
 | ||||||
|     endpoint.libInit(endpointConfig); |     endpoint.libInit(endpointConfig); | ||||||
| 
 | 
 | ||||||
|     pj_status_t status; |  | ||||||
|     pj_caching_pool cachingPool; |  | ||||||
|     pj_caching_pool_init(&cachingPool, &pj_pool_factory_default_policy, 0); |     pj_caching_pool_init(&cachingPool, &pj_pool_factory_default_policy, 0); | ||||||
|     pool = pj_pool_create(&cachingPool.factory, "media", 32768, 8192, nullptr); |  | ||||||
|     if (!pool) { |  | ||||||
|         throw sip::Exception("error when creating memory pool", status); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // todo calculate sizes
 |     mixer.reset(new mixer::AudioFramesMixer(cachingPool.factory)); | ||||||
|     status = pjmedia_circ_buf_create(pool, 960 * 10, &inputBuff); |  | ||||||
|     if (status != PJ_SUCCESS) { |  | ||||||
|         throw sip::Exception("error when creating circular buffer", status); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     media.reset(new _MumlibAudioMedia(*this)); |     media.reset(new _MumlibAudioMedia(*this)); | ||||||
| } | } | ||||||
| @ -269,25 +259,22 @@ sip::PjsuaCommunicator::~PjsuaCommunicator() { | |||||||
|     endpoint.libDestroy(); |     endpoint.libDestroy(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void sip::PjsuaCommunicator::sendPcmSamples(int sessionId, int sequenceNumber, int16_t *samples, unsigned int length) { | ||||||
|  |     mixer->addFrameToBuffer(sessionId, sequenceNumber, samples, length); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| pj_status_t sip::PjsuaCommunicator::mediaPortGetFrame(pjmedia_port *port, pjmedia_frame *frame) { | pj_status_t sip::PjsuaCommunicator::mediaPortGetFrame(pjmedia_port *port, pjmedia_frame *frame) { | ||||||
|     std::unique_lock<std::mutex> lock(inBuffAccessMutex); |  | ||||||
| 
 |  | ||||||
|     frame->type = PJMEDIA_FRAME_TYPE_AUDIO; |     frame->type = PJMEDIA_FRAME_TYPE_AUDIO; | ||||||
|     pj_int16_t *samples = static_cast<pj_int16_t *>(frame->buf); |     pj_int16_t *samples = static_cast<pj_int16_t *>(frame->buf); | ||||||
|     pj_size_t count = frame->size / 2 / PJMEDIA_PIA_CCNT(&(port->info)); |     pj_size_t count = frame->size / 2 / PJMEDIA_PIA_CCNT(&(port->info)); | ||||||
| 
 | 
 | ||||||
|     pj_size_t availableSamples = pjmedia_circ_buf_get_len(inputBuff); |     const int readSamples = mixer->getMixedSamples(samples, count); | ||||||
|     const int samplesToRead = std::min(count, availableSamples); |  | ||||||
| 
 | 
 | ||||||
|     pjsuaLogger.debug("Pulling %d samples from in-buff.", samplesToRead); |     if (readSamples < count) { | ||||||
|     pjmedia_circ_buf_read(inputBuff, samples, samplesToRead); |         pjsuaLogger.debug("Requested %d samples, available %d, filling remaining with zeros.", | ||||||
|  |                           count, readSamples); | ||||||
| 
 | 
 | ||||||
|     if (availableSamples < count) { |         for (int i = readSamples; i < count; ++i) { | ||||||
|         pjsuaLogger.debug("Requested %d samples, available %d, filling remaining with zeros.", count, |  | ||||||
|                           availableSamples); |  | ||||||
| 
 |  | ||||||
|         for (int i = samplesToRead; i < count; ++i) { |  | ||||||
|             samples[i] = 0; |             samples[i] = 0; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -321,10 +308,4 @@ void sip::PjsuaCommunicator::registerAccount(string host, string user, string pa | |||||||
|     logger.info("Registering account for URI: %s.", uri.c_str()); |     logger.info("Registering account for URI: %s.", uri.c_str()); | ||||||
|     account.reset(new _Account(*this)); |     account.reset(new _Account(*this)); | ||||||
|     account->create(accountConfig); |     account->create(accountConfig); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| void sip::PjsuaCommunicator::sendPcmSamples(int16_t *samples, unsigned int length) { |  | ||||||
|     std::unique_lock<std::mutex> lock(inBuffAccessMutex); |  | ||||||
|     pjsuaLogger.debug("Pushing %d samples to in-buff.", length); |  | ||||||
|     pjmedia_circ_buf_write(inputBuff, samples, length); |  | ||||||
| } |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "ICommunicator.hpp" |  | ||||||
| #include "IncomingConnectionValidator.hpp" | #include "IncomingConnectionValidator.hpp" | ||||||
|  | #include "AudioFramesMixer.hpp" | ||||||
| 
 | 
 | ||||||
| #include <pjmedia.h> | #include <pjmedia.h> | ||||||
| #include <pjsua-lib/pjsua.h> | #include <pjsua-lib/pjsua.h> | ||||||
| @ -15,7 +15,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <string> | #include <string> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <mutex> |  | ||||||
| #include <climits> | #include <climits> | ||||||
| #include <bits/unique_ptr.h> | #include <bits/unique_ptr.h> | ||||||
| 
 | 
 | ||||||
| @ -55,7 +54,7 @@ namespace sip { | |||||||
| 
 | 
 | ||||||
|     class _MumlibAudioMedia; |     class _MumlibAudioMedia; | ||||||
| 
 | 
 | ||||||
|     class PjsuaCommunicator : public ICommunicator, boost::noncopyable { |     class PjsuaCommunicator : boost::noncopyable { | ||||||
|     public: |     public: | ||||||
|         PjsuaCommunicator(IncomingConnectionValidator &validator); |         PjsuaCommunicator(IncomingConnectionValidator &validator); | ||||||
| 
 | 
 | ||||||
| @ -65,9 +64,15 @@ namespace sip { | |||||||
|                 std::string password, |                 std::string password, | ||||||
|                 unsigned int port = DEFAULT_PORT); |                 unsigned int port = DEFAULT_PORT); | ||||||
| 
 | 
 | ||||||
|         ~PjsuaCommunicator(); |         virtual ~PjsuaCommunicator(); | ||||||
| 
 | 
 | ||||||
|         virtual void sendPcmSamples(int16_t *samples, unsigned int length) override; |         void sendPcmSamples( | ||||||
|  |                 int sessionId, | ||||||
|  |                 int sequenceNumber, | ||||||
|  |                 int16_t *samples, | ||||||
|  |                 unsigned int length); | ||||||
|  | 
 | ||||||
|  |         std::function<void(int16_t *, int)> onIncomingPcmSamples; | ||||||
| 
 | 
 | ||||||
|         std::function<void(std::string)> onStateChange; |         std::function<void(std::string)> onStateChange; | ||||||
| 
 | 
 | ||||||
| @ -79,18 +84,16 @@ namespace sip { | |||||||
|         log4cpp::Category &logger; |         log4cpp::Category &logger; | ||||||
|         log4cpp::Category &pjsuaLogger; |         log4cpp::Category &pjsuaLogger; | ||||||
| 
 | 
 | ||||||
|  |         std::unique_ptr<mixer::AudioFramesMixer> mixer; | ||||||
|  | 
 | ||||||
|         std::unique_ptr<_LogWriter> logWriter; |         std::unique_ptr<_LogWriter> logWriter; | ||||||
|         std::unique_ptr<_Account> account; |         std::unique_ptr<_Account> account; | ||||||
|         std::unique_ptr<_MumlibAudioMedia> media; |         std::unique_ptr<_MumlibAudioMedia> media; | ||||||
| 
 | 
 | ||||||
|  |         pj_caching_pool cachingPool; | ||||||
|  | 
 | ||||||
|         pj::Endpoint endpoint; |         pj::Endpoint endpoint; | ||||||
| 
 | 
 | ||||||
|         pj_pool_t *pool = nullptr; |  | ||||||
| 
 |  | ||||||
|         pjmedia_circ_buf *inputBuff; |  | ||||||
| 
 |  | ||||||
|         std::mutex inBuffAccessMutex; |  | ||||||
| 
 |  | ||||||
|         IncomingConnectionValidator &uriValidator; |         IncomingConnectionValidator &uriValidator; | ||||||
| 
 | 
 | ||||||
|         void registerAccount(std::string host, |         void registerAccount(std::string host, | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.cpp
									
									
									
									
									
								
							| @ -45,7 +45,7 @@ int main(int argc, char *argv[]) { | |||||||
|     mumbleCommunicator.onIncomingPcmSamples = std::bind( |     mumbleCommunicator.onIncomingPcmSamples = std::bind( | ||||||
|             &sip::PjsuaCommunicator::sendPcmSamples, |             &sip::PjsuaCommunicator::sendPcmSamples, | ||||||
|             &pjsuaCommunicator, |             &pjsuaCommunicator, | ||||||
|             _1, _2); |             _1, _2, _3, _4); | ||||||
| 
 | 
 | ||||||
|     mumbleCommunicator.connect( |     mumbleCommunicator.connect( | ||||||
|             conf.getString("mumble.user"), |             conf.getString("mumble.user"), | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Michał Słomkowski
						Michał Słomkowski