AudioFramesMixer.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include "AudioFramesMixer.hpp"
  2. #include <boost/format.hpp>
  3. #include <climits>
  4. mixer::AudioFramesMixer::AudioFramesMixer(pj_pool_factory &poolFactory)
  5. : logger(log4cpp::Category::getInstance("AudioFramesMixer")) {
  6. pool = pj_pool_create(&poolFactory, "mixer_pool", 10 * 1024, 10 * 1024, nullptr);
  7. if (!pool) {
  8. throw mixer::Exception("error when creating memory pool");
  9. }
  10. }
  11. mixer::AudioFramesMixer::~AudioFramesMixer() {
  12. if (pool != nullptr) {
  13. pj_pool_release(pool);
  14. }
  15. }
  16. void mixer::AudioFramesMixer::addFrameToBuffer(int sessionId, int sequenceNumber, int16_t *samples, int samplesLength) {
  17. std::unique_lock<std::mutex> lock(inBuffAccessMutex);
  18. pjmedia_circ_buf *circBuf;
  19. pj_status_t status;
  20. auto it = buffersMap.find(sessionId);
  21. if (it != buffersMap.end()) {
  22. circBuf = it->second;
  23. } else {
  24. logger.debug("Creating circular buffer for session %d.", sessionId);
  25. status = pjmedia_circ_buf_create(pool, 960 * 10, &circBuf);
  26. if (status != PJ_SUCCESS) {
  27. throw mixer::Exception("error when creating circular buffer", status);
  28. }
  29. buffersMap.insert({{sessionId, circBuf}});
  30. }
  31. logger.debug("Pushing %d samples to buffer for session %d.", samplesLength, sessionId);
  32. status = pjmedia_circ_buf_write(circBuf, samples, samplesLength);
  33. if (status != PJ_SUCCESS and status != PJ_ETOOBIG) {
  34. throw mixer::Exception((boost::format("error when writing %d samples to circular buffer")
  35. % samplesLength).str(), status);
  36. }
  37. }
  38. int mixer::AudioFramesMixer::getMixedSamples(int16_t *mixedSamples, int requestedLength) {
  39. std::unique_lock<std::mutex> lock(inBuffAccessMutex);
  40. double mixerBuffer[MAX_BUFFER_LENGTH];
  41. memset(mixerBuffer, 0, sizeof(mixerBuffer));
  42. int longestSamples = 0;
  43. for (auto &user: buffersMap) {
  44. int16_t userBuff[MAX_BUFFER_LENGTH];
  45. int availableSamples = pjmedia_circ_buf_get_len(user.second);
  46. const int samplesToRead = std::min(requestedLength, availableSamples);
  47. longestSamples = std::max(samplesToRead, longestSamples);
  48. logger.debug("Pulling %d samples from in-buff for session ID %d.", samplesToRead, user.first);
  49. pj_status_t status = pjmedia_circ_buf_read(user.second, userBuff, samplesToRead);
  50. if (status != PJ_SUCCESS) {
  51. throw mixer::Exception(
  52. (boost::format("error when pulling %d samples from buffer for session ID %d")
  53. % samplesToRead % user.first).str(), status);
  54. }
  55. for (int i = 0; i < samplesToRead; ++i) {
  56. mixerBuffer[i] += userBuff[i];
  57. }
  58. }
  59. for (auto it = buffersMap.cbegin(); it != buffersMap.cend() /* not hoisted */; /* no increment */) {
  60. if (pjmedia_circ_buf_get_len(it->second) == 0) {
  61. logger.debug("Removing circular buffer for session %d.", it->first);
  62. pj_status_t status = pjmedia_circ_buf_reset(it->second);
  63. if (status != PJ_SUCCESS) {
  64. throw mixer::Exception(
  65. (boost::format("error when resetting circular buffer for session ID %d") % it->first).str(),
  66. status);
  67. }
  68. buffersMap.erase(it++);
  69. }
  70. else {
  71. ++it;
  72. }
  73. }
  74. double maxVal = 0;
  75. for (int i = 0; i < longestSamples; ++i) {
  76. maxVal = std::max(maxVal, std::abs(mixerBuffer[i]));
  77. }
  78. if (maxVal >= INT16_MAX) {
  79. for (int i = 0; i < longestSamples; ++i) {
  80. mixedSamples[i] = (INT16_MAX * (mixerBuffer[i] / maxVal));
  81. }
  82. logger.debug("Mixer overdrive, truncating to 16-bit.");
  83. } else {
  84. for (int i = 0; i < longestSamples; ++i) {
  85. mixedSamples[i] = mixerBuffer[i];
  86. }
  87. }
  88. logger.debug("Getting %d mixed samples.", longestSamples);
  89. return longestSamples;
  90. }
  91. void mixer::AudioFramesMixer::clear() {
  92. std::unique_lock<std::mutex> lock(inBuffAccessMutex);
  93. for (auto &entry : buffersMap) {
  94. pjmedia_circ_buf_reset(entry.second);
  95. }
  96. buffersMap.clear();
  97. }