int maintestjitter() { char buffer[65536]; JitterBufferPacket in, out; int i; JitterBuffer *jb = jitter_buffer_init(10); out.data = buffer; /* Frozen sender case */ jitterFill(jb); for(i=0;i<100;++i) { out.len = 65536; jitter_buffer_get(jb, &out, 10, NULL); jitter_buffer_tick(jb); } synthIn(&in, 100, 1); jitter_buffer_put(jb, &in); out.len = 65536; if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { printf("Failed frozen sender resynchronize\n"); } else { printf("Frozen sender: Jitter %d\n", out.timestamp - 100*10); } return 0; }
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp) { JitterBufferPacket p; p.data = packet; p.len = len; p.timestamp = timestamp; p.span = jitter->frame_size; jitter_buffer_put(jitter->packets, &p); }
JNIEXPORT void JNICALL Native_NATIVE(jitter_1buffer_1put) (JNIEnv *env, jclass that, jlong arg0, jobject arg1) { JitterBufferPacket _arg1, *lparg1=NULL; Native_NATIVE_ENTER(env, that, Native_jitter_1buffer_1put_FUNC); if (arg1) if ((lparg1 = getJitterBufferPacketFields(env, arg1, &_arg1)) == NULL) goto fail; jitter_buffer_put((JitterBuffer *)(intptr_t)arg0, lparg1); fail: Native_NATIVE_EXIT(env, that, Native_jitter_1buffer_1put_FUNC); }
void speex_jitter_put(SpeexJitter *jitter, char *packet, int len, int timestamp, void* userData) { JitterBufferPacket p; p.data = packet; p.len = len; p.timestamp = timestamp; p.span = jitter->frame_size; p.user_data = (spx_uint32_t)userData; jitter_buffer_put(jitter->packets, &p); }
void AudioOutputSpeech::addFrameToBuffer(const QByteArray &qbaPacket, unsigned int iSeq) { QMutexLocker lock(&qmJitter); if (qbaPacket.size() < 2) return; PacketDataStream pds(qbaPacket); pds.next(); int frames = 0; unsigned int header = 0; do { header = static_cast<unsigned char>(pds.next()); frames++; pds.skip(header & 0x7f); } while ((header & 0x80) && pds.isValid()); if (pds.isValid()) { JitterBufferPacket jbp; jbp.data = const_cast<char *>(qbaPacket.constData()); jbp.len = qbaPacket.size(); jbp.span = iFrameSize * frames; jbp.timestamp = iFrameSize * iSeq; #ifdef REPORT_JITTER if (g.s.bUsage && (umtType != MessageHandler::UDPVoiceSpeex) && p && ! p->qsHash.isEmpty() && (p->qlTiming.count() < 3000)) { QMutexLocker qml(& p->qmTiming); ClientUser::JitterRecord jr; jr.iSequence = iSeq; jr.iFrames = frames; jr.uiElapsed = p->tTiming.restart(); if (! p->qlTiming.isEmpty()) { jr.iFrames -= p->iFrames; jr.iSequence -= p->iSequence + p->iFrames; } p->iFrames = frames; p->iSequence = iSeq; p->qlTiming.append(jr); } #endif jitter_buffer_put(jbJitter, &jbp); } }
void AudioInput::addEcho(const void *data, unsigned int nsamp) { while (nsamp > 0) { unsigned int left = qMin(nsamp, iEchoLength - iEchoFilled); imfEcho(pfEchoInput + iEchoFilled, data, left, iEchoChannels); iEchoFilled += left; nsamp -= left; if (nsamp > 0) { if (eEchoFormat == SampleFloat) data = reinterpret_cast<const float *>(data) + left * iEchoChannels; else data = reinterpret_cast<const short *>(data) + left * iEchoChannels; } if (iEchoFilled == iEchoLength) { iEchoFilled = 0; STACKVAR(short, outbuff, iFrameSize); float *ptr = srsEcho ? pfOutput : pfEchoInput; if (srsEcho) { spx_uint32_t inlen = iEchoLength; spx_uint32_t outlen = iFrameSize; speex_resampler_process_float(srsEcho, 0, pfEchoInput, &inlen, pfOutput, &outlen); } const float mul = 32768.f; for (int j=0;j<iFrameSize;++j) outbuff[j] = static_cast<short>(ptr[j] * mul); JitterBufferPacket jbp; jbp.data = reinterpret_cast<char *>(outbuff); jbp.len = iFrameSize * sizeof(short); jbp.timestamp = ++iJitterSeq * 10; jbp.span = 10; jbp.sequence = static_cast<unsigned short>(iJitterSeq); jbp.user_data = 0; jitter_buffer_put(jb, &jbp); } } }
void jitterFill(JitterBuffer *jb) { char buffer[65536]; JitterBufferPacket in, out; int i; out.data = buffer; jitter_buffer_reset(jb); for(i=0;i<100;++i) { synthIn(&in, i, 1); jitter_buffer_put(jb, &in); out.len = 65536; if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) { printf("Fill test failed iteration %d\n", i); } if (out.timestamp != i * 10) { printf("Fill test expected %d got %d\n", i*10, out.timestamp); } jitter_buffer_tick(jb); } }
static int tdav_speex_jitterbuffer_put(tmedia_jitterbuffer_t* self, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr) { tdav_speex_jitterbuffer_t *jb = (tdav_speex_jitterbuffer_t *)self; const trtp_rtp_header_t* rtp_hdr; JitterBufferPacket jb_packet; static uint16_t seq_num = 0; if(!data || !data_size || !proto_hdr){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!jb->state){ TSK_DEBUG_ERROR("Invalid state"); return -2; } rtp_hdr = TRTP_RTP_HEADER(proto_hdr); jb_packet.user_data = 0; jb_packet.span = jb->frame_duration; jb_packet.len = jb->x_data_size; if(jb->x_data_size == data_size){ /* ptime match */ jb_packet.data = data; jb_packet.sequence = rtp_hdr->seq_num; jb_packet.timestamp = (rtp_hdr->seq_num * jb_packet.span); jitter_buffer_put(jb->state, &jb_packet); } else{ /* ptime mismatch */ tsk_size_t i; jb_packet.sequence = 0; // Ignore if((jb->buff.index + data_size) > jb->buff.size){ if(!(jb->buff.ptr = tsk_realloc(jb->buff.ptr, (jb->buff.index + data_size)))){ jb->buff.size = 0; jb->buff.index = 0; return 0; } jb->buff.size = (jb->buff.index + data_size); } memcpy(&jb->buff.ptr[jb->buff.index], data, data_size); jb->buff.index += data_size; if(jb->buff.index >= jb->x_data_size){ tsk_size_t copied = 0; for(i = 0; (i + jb->x_data_size) <= jb->buff.index; i += jb->x_data_size){ jb_packet.data = (char*)&jb->buff.ptr[i]; jb_packet.timestamp = (++jb->fake_seqnum * jb_packet.span);// reassembled pkt will have fake seqnum jitter_buffer_put(jb->state, &jb_packet); copied += jb->x_data_size; } if(copied == jb->buff.index){ // all copied jb->buff.index = 0; } else{ memmove(&jb->buff.ptr[0], &jb->buff.ptr[copied], (jb->buff.index - copied)); jb->buff.index -= copied; } } } return 0; }
int main(int argc, char **argv) { int sd, rc, n, tmp; char msg[MAX_MSG]; int nfds; int send_timestamp = 0; int recv_started = 0; struct pollfd *pfds; struct alsa_dev *dev; CELTEncoder *enc_state; CELTDecoder *dec_state; CELTMode *mode; struct sched_param param; JitterBuffer *jitter; SpeexEchoState *echo_state; char mac_own[6], mac_remote[6]; if (argc != 4) panic("Usage %s plughw:0,0 <lmac in xx:xx:xx:xx:xx:xx> <rmac>\n", argv[0]); register_signal(SIGINT, sighandler); hack_mac(mac_own, argv[2], strlen(argv[2])); hack_mac(mac_remote, argv[3], strlen(argv[3])); sd = socket(AF_LANA, SOCK_RAW, 0); if (sd < 0) panic("%s: cannot open socket \n", argv[0]); printf("If ready hit key!\n"); //user must do binding getchar(); dev = alsa_open(argv[1], SAMPLING_RATE, CHANNELS, FRAME_SIZE); mode = celt_mode_create(SAMPLING_RATE, FRAME_SIZE, NULL); enc_state = celt_encoder_create(mode, CHANNELS, NULL); dec_state = celt_decoder_create(mode, CHANNELS, NULL); param.sched_priority = sched_get_priority_min(SCHED_FIFO); if (sched_setscheduler(0, SCHED_FIFO, ¶m)) whine("sched_setscheduler error!\n"); /* Setup all file descriptors for poll()ing */ nfds = alsa_nfds(dev); pfds = xmalloc(sizeof(*pfds) * (nfds + 1)); alsa_getfds(dev, pfds, nfds); pfds[nfds].fd = sd; pfds[nfds].events = POLLIN; /* Setup jitter buffer using decoder */ jitter = jitter_buffer_init(FRAME_SIZE); tmp = FRAME_SIZE; jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MARGIN, &tmp); /* Echo canceller with 200 ms tail length */ echo_state = speex_echo_state_init(FRAME_SIZE, 10 * FRAME_SIZE); tmp = SAMPLING_RATE; speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp); register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO); alsa_start(dev); printf("ALSA started!\n"); itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = interval; itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = interval; setitimer(ITIMER_REAL, &itimer, NULL); while (!sigint) { poll(pfds, nfds + 1, -1); /* Received packets */ if (pfds[nfds].revents & POLLIN) { memset(msg, 0, MAX_MSG); n = recv(sd, msg, MAX_MSG, 0); if (n <= 0) goto do_alsa; pkts_in++; int recv_timestamp; memcpy(&recv_timestamp, msg, sizeof(recv_timestamp)); JitterBufferPacket packet; packet.data = msg+4/*+6+6+2*/; packet.len = n-4/*-6-6-2*/; packet.timestamp = recv_timestamp; packet.span = FRAME_SIZE; packet.sequence = 0; /* Put content of the packet into the jitter buffer, except for the pseudo-header */ jitter_buffer_put(jitter, &packet); recv_started = 1; } do_alsa: /* Ready to play a frame (playback) */ if (alsa_play_ready(dev, pfds, nfds)) { short pcm[FRAME_SIZE * CHANNELS] = {0}; if (recv_started) { JitterBufferPacket packet; /* Get audio from the jitter buffer */ packet.data = msg; packet.len = MAX_MSG; jitter_buffer_tick(jitter); jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL); if (packet.len == 0) packet.data=NULL; celt_decode(dec_state, (const unsigned char *) packet.data, packet.len, pcm); } /* Playback the audio and reset the echo canceller if we got an underrun */ alsa_write(dev, pcm, FRAME_SIZE); // if (alsa_write(dev, pcm, FRAME_SIZE)) // speex_echo_state_reset(echo_state); /* Put frame into playback buffer */ // speex_echo_playback(echo_state, pcm); } /* Audio available from the soundcard (capture) */ if (alsa_cap_ready(dev, pfds, nfds)) { short pcm[FRAME_SIZE * CHANNELS]; //pcm2[FRAME_SIZE * CHANNELS]; char outpacket[MAX_MSG]; alsa_read(dev, pcm, FRAME_SIZE); /* Perform echo cancellation */ // speex_echo_capture(echo_state, pcm, pcm2); // for (i = 0; i < FRAME_SIZE * CHANNELS; ++i) // pcm[i] = pcm2[i]; celt_encode(enc_state, pcm, NULL, (unsigned char *) (outpacket+4+6+6+2), PACKETSIZE); /* Pseudo header: four null bytes and a 32-bit timestamp; XXX hack */ memcpy(outpacket,mac_remote,6); memcpy(outpacket+6,mac_own,6); outpacket[6+6] = (uint8_t) 0xac; outpacket[6+6+1] = (uint8_t) 0xdc; memcpy(outpacket+6+6+2, &send_timestamp, sizeof(send_timestamp)); send_timestamp += FRAME_SIZE; rc = sendto(sd, outpacket, PACKETSIZE+4+6+6+2, 0, NULL, 0); if (rc < 0) panic("cannot send to socket"); pkts_out++; } } itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, NULL); close(sd); return 0; }