Audio.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include "mumlib/Audio.hpp"
  2. #include <boost/format.hpp>
  3. static boost::posix_time::seconds RESET_SEQUENCE_NUMBER_INTERVAL(5);
  4. mumlib::Audio::Audio(int opusEncoderBitrate)
  5. : logger(log4cpp::Category::getInstance("mumlib.Audio")),
  6. opusDecoder(nullptr),
  7. opusEncoder(nullptr),
  8. outgoingSequenceNumber(0) {
  9. int error;
  10. opusDecoder = opus_decoder_create(SAMPLE_RATE, 1, &error);
  11. if (error != OPUS_OK) {
  12. throw AudioException((boost::format("failed to initialize OPUS decoder: %s") % opus_strerror(error)).str());
  13. }
  14. opusEncoder = opus_encoder_create(SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &error);
  15. if (error != OPUS_OK) {
  16. throw AudioException((boost::format("failed to initialize OPUS encoder: %s") % opus_strerror(error)).str());
  17. }
  18. opus_encoder_ctl(opusEncoder, OPUS_SET_VBR(0));
  19. setOpusEncoderBitrate(opusEncoderBitrate);
  20. resetEncoder();
  21. }
  22. mumlib::Audio::~Audio() {
  23. if (opusDecoder) {
  24. opus_decoder_destroy(opusDecoder);
  25. }
  26. if (opusEncoder) {
  27. opus_encoder_destroy(opusEncoder);
  28. }
  29. }
  30. void mumlib::Audio::setOpusEncoderBitrate(int bitrate) {
  31. int error = opus_encoder_ctl(opusEncoder, OPUS_SET_BITRATE(bitrate));
  32. if (error != OPUS_OK) {
  33. throw AudioException((boost::format("failed to initialize transmission bitrate to %d B/s: %s")
  34. % bitrate % opus_strerror(error)).str());
  35. }
  36. }
  37. int mumlib::Audio::getOpusEncoderBitrate() {
  38. opus_int32 bitrate;
  39. int error = opus_encoder_ctl(opusEncoder, OPUS_GET_BITRATE(&bitrate));
  40. if (error != OPUS_OK) {
  41. throw AudioException((boost::format("failed to read Opus bitrate: %s") % opus_strerror(error)).str());
  42. }
  43. return bitrate;
  44. }
  45. std::pair<int, bool> mumlib::Audio::decodeOpusPayload(uint8_t *inputBuffer,
  46. int inputLength,
  47. int16_t *pcmBuffer,
  48. int pcmBufferSize) {
  49. int64_t opusDataLength;
  50. int dataPointer = 0;
  51. VarInt varInt(inputBuffer);
  52. opusDataLength = varInt.getValue();
  53. dataPointer += varInt.getEncoded().size();
  54. bool lastPacket = (opusDataLength & 0x2000) != 0;
  55. opusDataLength = opusDataLength & 0x1fff;
  56. if (inputLength < opusDataLength + dataPointer) {
  57. throw AudioException((boost::format("invalid Opus payload (%d B): header %d B, expected Opus data length %d B")
  58. % inputLength % dataPointer % opusDataLength).str());
  59. }
  60. int outputSize = opus_decode(opusDecoder,
  61. reinterpret_cast<const unsigned char *>(&inputBuffer[dataPointer]),
  62. opusDataLength,
  63. pcmBuffer,
  64. pcmBufferSize,
  65. 0);
  66. if (outputSize <= 0) {
  67. throw AudioException((boost::format("failed to decode %d B of OPUS data: %s") % inputLength %
  68. opus_strerror(outputSize)).str());
  69. }
  70. logger.debug("%d B of Opus data decoded to %d PCM samples, last packet: %d.",
  71. opusDataLength, outputSize, lastPacket);
  72. return std::make_pair(outputSize, lastPacket);
  73. }
  74. int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer,
  75. int outputBufferSize) {
  76. using namespace std::chrono;
  77. const int lastAudioPacketSentInterval = duration_cast<milliseconds>(
  78. system_clock::now() - lastEncodedAudioPacketTimestamp).count();
  79. if (lastAudioPacketSentInterval > RESET_SEQUENCE_NUMBER_INTERVAL.total_milliseconds() + 1000) {
  80. logger.debug("Last audio packet was sent %d ms ago, resetting encoder.", lastAudioPacketSentInterval);
  81. resetEncoder();
  82. }
  83. std::vector<uint8_t> header;
  84. header.push_back(0x80 | target);
  85. auto sequenceNumberEnc = VarInt(outgoingSequenceNumber).getEncoded();
  86. header.insert(header.end(), sequenceNumberEnc.begin(), sequenceNumberEnc.end());
  87. uint8_t tmpOpusBuffer[1024];
  88. const int outputSize = opus_encode(opusEncoder,
  89. inputPcmBuffer,
  90. inputLength,
  91. tmpOpusBuffer,
  92. min(outputBufferSize, 1024)
  93. );
  94. if (outputSize <= 0) {
  95. throw AudioException((boost::format("failed to encode %d B of PCM data: %s") % inputLength %
  96. opus_strerror(outputSize)).str());
  97. }
  98. auto outputSizeEnc = VarInt(outputSize).getEncoded();
  99. header.insert(header.end(), outputSizeEnc.begin(), outputSizeEnc.end());
  100. memcpy(outputBuffer, &header[0], header.size());
  101. memcpy(outputBuffer + header.size(), tmpOpusBuffer, outputSize);
  102. int incrementNumber = 100 * inputLength / SAMPLE_RATE;
  103. outgoingSequenceNumber += incrementNumber;
  104. lastEncodedAudioPacketTimestamp = std::chrono::system_clock::now();
  105. return outputSize + header.size();
  106. }
  107. void mumlib::Audio::resetEncoder() {
  108. int status = opus_encoder_ctl(opusEncoder, OPUS_RESET_STATE, nullptr);
  109. if (status != OPUS_OK) {
  110. throw AudioException((boost::format("failed to reset encoder: %s") % opus_strerror(status)).str());
  111. }
  112. outgoingSequenceNumber = 0;
  113. }
  114. mumlib::IncomingAudioPacket mumlib::Audio::decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength) {
  115. mumlib::IncomingAudioPacket incomingAudioPacket;
  116. incomingAudioPacket.type = static_cast<AudioPacketType >((inputBuffer[0] & 0xE0) >> 5);
  117. incomingAudioPacket.target = inputBuffer[0] & 0x1F;
  118. std::array<int64_t *, 2> varInts = {&incomingAudioPacket.sessionId, &incomingAudioPacket.sequenceNumber};
  119. int dataPointer = 1;
  120. for (int64_t *val : varInts) {
  121. VarInt varInt(&inputBuffer[dataPointer]);
  122. *val = varInt.getValue();
  123. dataPointer += varInt.getEncoded().size();
  124. }
  125. incomingAudioPacket.audioPayload = &inputBuffer[dataPointer];
  126. incomingAudioPacket.audioPayloadLength = inputBufferLength - dataPointer;
  127. if (dataPointer >= inputBufferLength) {
  128. throw AudioException((boost::format("invalid incoming audio packet (%d B): header %d B") % inputBufferLength %
  129. dataPointer).str());
  130. }
  131. logger.debug(
  132. "Received %d B of audio packet, %d B header, %d B payload (target: %d, sessionID: %ld, seq num: %ld).",
  133. inputBufferLength,
  134. dataPointer,
  135. incomingAudioPacket.audioPayloadLength,
  136. incomingAudioPacket.target,
  137. incomingAudioPacket.sessionId,
  138. incomingAudioPacket.sequenceNumber);
  139. return incomingAudioPacket;
  140. }