Audio.cpp 6.0 KB

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