#include "WebRtcJitterBuffer.h" //#include <time.h> #define TAG "WebRtcJitterBuffer" static volatile int running = 0; WebRtcJitterBuffer::WebRtcJitterBuffer(AudioCodec &codec) : neteq(NULL), webRtcCodec(codec) { running = 1; } int WebRtcJitterBuffer::init() { webrtc::NetEq::Config config; config.sample_rate_hz = 8000; neteq = webrtc::NetEq::Create(config); if (neteq == NULL) { __android_log_print(ANDROID_LOG_WARN, TAG, "Failed to construct NetEq!"); return -1; } if (neteq->RegisterExternalDecoder(&webRtcCodec, webrtc::kDecoderPCMu, 0) != 0) { __android_log_print(ANDROID_LOG_WARN, TAG, "Failed to register external codec!"); return -1; } // pthread_t thread; // pthread_create(&thread, NULL, &WebRtcJitterBuffer::collectStats, this); return 0; } WebRtcJitterBuffer::~WebRtcJitterBuffer() { if (neteq != NULL) { delete neteq; } } void WebRtcJitterBuffer::addAudio(RtpPacket *packet, uint32_t tick) { webrtc::WebRtcRTPHeader header; header.header.payloadType = packet->getPayloadType(); header.header.sequenceNumber = packet->getSequenceNumber(); header.header.timestamp = packet->getTimestamp(); header.header.ssrc = packet->getSsrc(); uint8_t *payload = (uint8_t*)malloc(packet->getPayloadLen()); memcpy(payload, packet->getPayload(), packet->getPayloadLen()); if (neteq->InsertPacket(header, payload, packet->getPayloadLen(), tick) != 0) { __android_log_print(ANDROID_LOG_WARN, TAG, "neteq->InsertPacket() failed!"); } } int WebRtcJitterBuffer::getAudio(short *rawData, int maxRawData) { int samplesPerChannel = 0; int numChannels = 0; if (neteq->GetAudio(maxRawData, rawData, &samplesPerChannel, &numChannels, NULL) != 0) { __android_log_print(ANDROID_LOG_WARN, TAG, "neteq->GetAudio() failed!"); } return samplesPerChannel; } void WebRtcJitterBuffer::stop() { running = 0; } void WebRtcJitterBuffer::collectStats() { while (running) { webrtc::NetEqNetworkStatistics stats; neteq->NetworkStatistics(&stats); __android_log_print(ANDROID_LOG_WARN, "WebRtcJitterBuffer", "Jitter Stats:\n{\n" \ " current_buffer_size_ms: %d,\n" \ " preferred_buffer_size_ms: %d\n" \ " jitter_peaks_found: %d\n" \ " packet_loss_rate: %d\n" \ " packet_discard_rate: %d\n" \ " expand_rate: %d\n" \ " preemptive_rate: %d\n" \ " accelerate_rate: %d\n" \ " clockdrift_ppm: %d\n" \ " added_zero_samples: %d\n" \ "}", stats.current_buffer_size_ms, stats.preferred_buffer_size_ms, stats.jitter_peaks_found, stats.packet_loss_rate, stats.packet_discard_rate, stats.expand_rate, stats.preemptive_rate, stats.accelerate_rate, stats.clockdrift_ppm, stats.added_zero_samples); // struct timespec timeToWait; // struct timeval now; // gettimeofday(&now, NULL); // // timeToWait.tv_sec = now.tv_sec; // timeToWait.tv_nsec = now.tv_usec * 1000; // timeToWait.tv_sec += 30; // // pthread_mutex_lock(&lock); // // if (running) { // pthread_cond_timedwait(&condition, &lock, &timeToWait); // } // // pthread_mutex_unlock(&lock); sleep(30); } } void* WebRtcJitterBuffer::collectStats(void *context) { WebRtcJitterBuffer* jitterBuffer = static_cast<WebRtcJitterBuffer*>(context); jitterBuffer->collectStats(); return 0; }