Add sequence and session numbers to audio callbacks. #3

This commit is contained in:
Michał Słomkowski 2015-11-17 22:53:57 +01:00
parent a67dcedf0c
commit ae1e71fffc
7 changed files with 124 additions and 46 deletions

View File

@ -27,7 +27,7 @@ namespace mumlib {
Mumlib(Callback &callback, io_service &ioService); Mumlib(Callback &callback, io_service &ioService);
~Mumlib(); virtual ~Mumlib();
void connect(string host, int port, string user, string password); void connect(string host, int port, string user, string password);

View File

@ -17,14 +17,26 @@ namespace mumlib {
AudioException(string message) : MumlibException(message) { } AudioException(string message) : MumlibException(message) { }
}; };
struct IncomingAudioPacket {
AudioPacketType type;
int target;
int64_t sessionId;
int64_t sequenceNumber;
uint8_t *audioPayload;
int audioPayloadLength;
};
class Audio : boost::noncopyable { class Audio : boost::noncopyable {
public: public:
Audio(); Audio();
~Audio(); virtual ~Audio();
IncomingAudioPacket decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength);
int decodeAudioPacket(AudioPacketType type, uint8_t *inputBuffer, int inputLength, int16_t *pcmBuffer, std::pair<int, bool> decodeOpusPayload(uint8_t *inputBuffer,
int inputLength,
int16_t *pcmBuffer,
int pcmBufferSize); int pcmBufferSize);
int encodeAudioPacket( int encodeAudioPacket(

View File

@ -19,10 +19,16 @@ namespace mumlib {
string os_version) { }; string os_version) { };
virtual void audio( virtual void audio(
int target,
int sessionId,
int sequenceNumber,
int16_t *pcm_data, int16_t *pcm_data,
uint32_t pcm_data_size) { }; uint32_t pcm_data_size) { };
virtual void unsupportedAudio( virtual void unsupportedAudio(
int target,
int sessionId,
int sequenceNumber,
uint8_t *encoded_audio_data, uint8_t *encoded_audio_data,
uint32_t encoded_audio_data_size) { }; uint32_t encoded_audio_data_size) { };
@ -156,10 +162,16 @@ namespace mumlib {
string os_version); string os_version);
virtual void audio( virtual void audio(
int target,
int sessionId,
int sequenceNumber,
int16_t *pcm_data, int16_t *pcm_data,
uint32_t pcm_data_size); uint32_t pcm_data_size);
virtual void unsupportedAudio( virtual void unsupportedAudio(
int target,
int sessionId,
int sequenceNumber,
uint8_t *encoded_audio_data, uint8_t *encoded_audio_data,
uint32_t encoded_audio_data_size); uint32_t encoded_audio_data_size);

View File

@ -8,7 +8,11 @@ class MyCallback : public mumlib::BasicCallback {
public: public:
mumlib::Mumlib *mum; mumlib::Mumlib *mum;
virtual void audio(int16_t *pcm_data, uint32_t pcm_data_size) { virtual void audio(int target,
int sessionId,
int sequenceNumber,
int16_t *pcm_data,
uint32_t pcm_data_size) {
mum->sendAudioData(pcm_data, pcm_data_size); mum->sendAudioData(pcm_data, pcm_data_size);
} }

View File

@ -37,34 +37,25 @@ mumlib::Audio::~Audio() {
} }
} }
int mumlib::Audio::decodeAudioPacket(AudioPacketType type, std::pair<int, bool> mumlib::Audio::decodeOpusPayload(uint8_t *inputBuffer,
uint8_t *inputBuffer,
int inputLength, int inputLength,
int16_t *pcmBuffer, int16_t *pcmBuffer,
int pcmBufferSize) { int pcmBufferSize) {
if (type != AudioPacketType::OPUS) {
throw AudioException("codecs other than OPUS are not supported");
}
int target = inputBuffer[0] & 0x1F;
int64_t sessionId;
int64_t sequenceNumber;
int64_t opusDataLength; int64_t opusDataLength;
std::array<int64_t *, 3> varInts = {&sessionId, &sequenceNumber, &opusDataLength}; int dataPointer = 0;
VarInt varInt(inputBuffer);
int dataPointer = 1; opusDataLength = varInt.getValue();
for (int64_t *val : varInts) {
VarInt varInt(&inputBuffer[dataPointer]);
*val = varInt.getValue();
dataPointer += varInt.getEncoded().size(); dataPointer += varInt.getEncoded().size();
}
bool lastPacket = (opusDataLength & 0x2000) != 0; bool lastPacket = (opusDataLength & 0x2000) != 0;
opusDataLength = opusDataLength & 0x1fff; opusDataLength = opusDataLength & 0x1fff;
if (inputLength < opusDataLength + dataPointer) {
throw AudioException((boost::format("invalid Opus payload (%d B): header %d B, expected Opus data length %d B")
% inputLength % dataPointer % opusDataLength).str());
}
int outputSize = opus_decode(opusDecoder, int outputSize = opus_decode(opusDecoder,
reinterpret_cast<const unsigned char *>(&inputBuffer[dataPointer]), reinterpret_cast<const unsigned char *>(&inputBuffer[dataPointer]),
opusDataLength, opusDataLength,
@ -77,17 +68,10 @@ int mumlib::Audio::decodeAudioPacket(AudioPacketType type,
opus_strerror(outputSize)).str()); opus_strerror(outputSize)).str());
} }
logger.debug( logger.debug("%d B of Opus data decoded to %d PCM samples, last packet: %d.",
"Received %d B of OPUS data, decoded to %d B (target: %d, sessionID: %ld, seq num: %ld, last: %d).", opusDataLength, outputSize, lastPacket);
opusDataLength,
outputSize,
target,
sessionId,
sequenceNumber,
lastPacket);
return std::make_pair(outputSize, lastPacket);
return outputSize;
} }
int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer, int mumlib::Audio::encodeAudioPacket(int target, int16_t *inputPcmBuffer, int inputLength, uint8_t *outputBuffer,
@ -147,3 +131,38 @@ void mumlib::Audio::resetEncoder() {
outgoingSequenceNumber = 0; outgoingSequenceNumber = 0;
} }
mumlib::IncomingAudioPacket mumlib::Audio::decodeIncomingAudioPacket(uint8_t *inputBuffer, int inputBufferLength) {
mumlib::IncomingAudioPacket incomingAudioPacket;
incomingAudioPacket.type = static_cast<AudioPacketType >((inputBuffer[0] & 0xE0) >> 5);
incomingAudioPacket.target = inputBuffer[0] & 0x1F;
std::array<int64_t *, 2> varInts = {&incomingAudioPacket.sessionId, &incomingAudioPacket.sequenceNumber};
int dataPointer = 1;
for (int64_t *val : varInts) {
VarInt varInt(&inputBuffer[dataPointer]);
*val = varInt.getValue();
dataPointer += varInt.getEncoded().size();
}
incomingAudioPacket.audioPayload = &inputBuffer[dataPointer];
incomingAudioPacket.audioPayloadLength = inputBufferLength - dataPointer;
if (dataPointer >= inputBufferLength) {
throw AudioException((boost::format("invalid incoming audio packet (%d B): header %d B") % inputBufferLength %
dataPointer).str());
}
logger.debug(
"Received %d B of audio packet, %d B header, %d B payload (target: %d, sessionID: %ld, seq num: %ld).",
inputBufferLength,
dataPointer,
incomingAudioPacket.audioPayloadLength,
incomingAudioPacket.target,
incomingAudioPacket.sessionId,
incomingAudioPacket.sequenceNumber);
return incomingAudioPacket;
}

View File

@ -36,13 +36,23 @@ void mumlib::BasicCallback::version(
} }
void mumlib::BasicCallback::audio( void mumlib::BasicCallback::audio(
int target,
int sessionId,
int sequenceNumber,
int16_t *pcmData, int16_t *pcmData,
uint32_t pcm_data_size) { uint32_t pcm_data_size) {
impl->logger.debug("audio: %d bytes of raw PCM data.", pcm_data_size); impl->logger.debug("audio: %d bytes of raw PCM data, target: %d, session: %d, seq: %d.",
pcm_data_size, target, sessionId, sequenceNumber);
} }
void BasicCallback::unsupportedAudio(uint8_t *encoded_audio_data, uint32_t encoded_audio_data_size) { void BasicCallback::unsupportedAudio(
impl->logger.debug("unsupportedAudio: received %d bytes of encoded data.", encoded_audio_data_size); int target,
int sessionId,
int sequenceNumber,
uint8_t *encoded_audio_data,
uint32_t encoded_audio_data_size) {
impl->logger.debug("unsupportedAudio: received %d bytes of encoded data, target: %d, session: %d, seq: %d.",
encoded_audio_data_size, target, sessionId, sequenceNumber);
} }
void BasicCallback::serverSync(string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) { void BasicCallback::serverSync(string welcome_text, int32_t session, int32_t max_bandwidth, int64_t permissions) {

View File

@ -45,7 +45,7 @@ namespace mumlib {
transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3),
boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { } boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { }
~_Mumlib_Private() { virtual ~_Mumlib_Private() {
if (not externalIoService) { if (not externalIoService) {
delete &ioService; delete &ioService;
} }
@ -54,13 +54,34 @@ namespace mumlib {
bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) { bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) {
logger.info("Got %d B of encoded audio data.", length); logger.info("Got %d B of encoded audio data.", length);
try { try {
auto incomingAudioPacket = audio.decodeIncomingAudioPacket(buffer, length);
if (type == AudioPacketType::OPUS) {
int16_t pcmData[5000]; int16_t pcmData[5000];
int pcmDataLength = audio.decodeAudioPacket(type, buffer, length, pcmData, 5000); auto status = audio.decodeOpusPayload(incomingAudioPacket.audioPayload,
callback.audio(pcmData, pcmDataLength); incomingAudioPacket.audioPayloadLength,
} catch (mumlib::AudioException &exp) { pcmData,
logger.warn("Audio decode error: %s, calling unsupportedAudio callback.", exp.what()); 5000);
callback.unsupportedAudio(buffer, length);
callback.audio(incomingAudioPacket.target,
incomingAudioPacket.sessionId,
incomingAudioPacket.sequenceNumber,
pcmData,
status.first);
} else {
logger.warn("Incoming audio packet doesn't contain Opus data, calling unsupportedAudio callback.");
callback.unsupportedAudio(incomingAudioPacket.target,
incomingAudioPacket.sessionId,
incomingAudioPacket.sequenceNumber,
incomingAudioPacket.audioPayload,
incomingAudioPacket.audioPayloadLength);
} }
} catch (mumlib::AudioException &exp) {
logger.error("Audio decode error: %s.", exp.what());
}
return true;
} }
private: private: