/*! \internal \brief Create a test frame * \param timestamp the time in ms of the frame * \param seqno the frame's sequence number * \returns a malloc'd frame */ static struct ast_frame *create_test_frame(long timestamp, int seqno) { struct ast_frame f = {0}; f.subclass.format.id = AST_FORMAT_SLINEAR; f.frametype = AST_FRAME_VOICE; f.src = "TEST"; f.ts = timestamp; f.len = DEFAULT_FRAME_MS; f.seqno = seqno; return ast_frisolate(&f); }
static struct ast_frame *jpeg_read_image(int fd, int len) { struct ast_frame fr; int res; char buf[65536]; if (len > sizeof(buf) || len < 0) { ast_log(LOG_WARNING, "JPEG image too large to read\n"); return NULL; } res = read(fd, buf, len); if (res < len) { ast_log(LOG_WARNING, "Only read %d of %d bytes: %s\n", res, len, strerror(errno)); } memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_IMAGE; fr.subclass.format = ast_format_jpeg; fr.data.ptr = buf; fr.src = "JPEG Read"; fr.datalen = len; return ast_frisolate(&fr); }
/* And decode everything we can in the buffer */ static struct ast_frame *lintosilk_frameout(struct ast_trans_pvt *pvt) { struct silk_coder_pvt *coder = pvt->pvt; SKP_int ret = 0; SKP_int16 nBytesOut = 0; int datalen = 0; int samples = 0; int numPackets = 0; struct ast_frame *f; /* we can only work on multiples of a 10 ms sample * and no more than encControl->packetSize. * So we shove in packetSize samples repeatedly until * we are out */ /* We only do stuff if we have more than packetSize */ if (pvt->samples < coder->encControl.packetSize) { return NULL; } while (pvt->samples >= coder->encControl.packetSize) { nBytesOut = SILK_BUFFER_SIZE_BYTES - datalen; ret = SKP_Silk_SDK_Encode(coder->psEnc, &coder->encControl, (SKP_int16*)(coder->buf + samples), coder->encControl.packetSize, (SKP_uint8*)(pvt->outbuf.ui8 + datalen), &nBytesOut); if (ret) { ast_log(LOG_WARNING, "Silk_Encode returned %d\n", ret); } /* nBytesOut now holds the number of bytes encoded */ datalen += nBytesOut; samples += coder->encControl.packetSize; pvt->samples -= coder->encControl.packetSize; if(nBytesOut > 0){ /* if stuff came out, we have encoded a packet */ numPackets++; } } /* Move the remaining buffer stuff down */ if (pvt->samples) { memmove(coder->buf, coder->buf + samples, pvt->samples *2); } if(datalen == 0){ /* we shoved a bunch of samples in, but got no packets * out. We return NULL to the caller, like * if we could not encode anything */ return NULL; } /* we build the frame ourselves because we have an explicit dest */ f = &pvt->f; f->samples = coder->encControl.packetSize * numPackets; f->datalen = datalen; f->frametype = AST_FRAME_VOICE; ast_format_copy(&f->subclass.format, &pvt->explicit_dst); f->mallocd = 0; f->offset = AST_FRIENDLY_OFFSET; f->src = pvt->t->name; f->data.ptr = pvt->outbuf.c; return ast_frisolate(f); }
/*! \brief convert work buffer and produce output frame */ static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt) { struct speex_coder_pvt *tmp = pvt->pvt; int is_speech=1; int datalen = 0; /* output bytes */ int samples = 0; /* output samples */ /* We can't work on anything less than a frame in size */ if (pvt->samples < tmp->framesize) return NULL; speex_bits_reset(&tmp->bits); while (pvt->samples >= tmp->framesize) { #ifdef _SPEEX_TYPES_H /* Preprocess audio */ if (preproc) is_speech = speex_preprocess(tmp->pp, tmp->buf + samples, NULL); /* Encode a frame of data */ if (is_speech) { /* If DTX enabled speex_encode returns 0 during silence */ is_speech = speex_encode_int(tmp->speex, tmp->buf + samples, &tmp->bits) || !dtx; } else { /* 5 zeros interpreted by Speex as silence (submode 0) */ speex_bits_pack(&tmp->bits, 0, 5); } #else { float fbuf[1024]; int x; /* Convert to floating point */ for (x = 0; x < tmp->framesize; x++) fbuf[x] = tmp->buf[samples + x]; /* Encode a frame of data */ is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx; } #endif samples += tmp->framesize; pvt->samples -= tmp->framesize; } /* Move the data at the end of the buffer to the front */ if (pvt->samples) memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2); /* Use AST_FRAME_CNG to signify the start of any silence period */ if (is_speech) { tmp->silent_state = 0; } else { if (tmp->silent_state) { return NULL; } else { struct ast_frame frm = { .frametype = AST_FRAME_CNG, .src = pvt->t->name, }; /* * XXX I don't think the AST_FRAME_CNG code has ever * really worked for speex. There doesn't seem to be * any consumers of the frame type. Everyone that * references the type seems to pass the frame on. */ tmp->silent_state = 1; /* XXX what now ? format etc... */ return ast_frisolate(&frm); } } /* Terminate bit stream */ speex_bits_pack(&tmp->bits, 15, 5); datalen = speex_bits_write(&tmp->bits, pvt->outbuf.c, pvt->t->buf_size); return ast_trans_frameout(pvt, datalen, samples); } static void speextolin_destroy(struct ast_trans_pvt *arg) { struct speex_coder_pvt *pvt = arg->pvt; speex_decoder_destroy(pvt->speex); speex_bits_destroy(&pvt->bits); } static void lintospeex_destroy(struct ast_trans_pvt *arg) { struct speex_coder_pvt *pvt = arg->pvt; #ifdef _SPEEX_TYPES_H if (preproc) speex_preprocess_state_destroy(pvt->pp); #endif speex_encoder_destroy(pvt->speex); speex_bits_destroy(&pvt->bits); } static struct ast_translator speextolin = { .name = "speextolin", .src_codec = { .name = "speex", .type = AST_MEDIA_TYPE_AUDIO, .sample_rate = 8000, }, .dst_codec = { .name = "slin", .type = AST_MEDIA_TYPE_AUDIO, .sample_rate = 8000, }, .format = "slin",
static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data) { struct jb_framedata *framedata = data; struct timeval now_tv; unsigned long now; int putframe = 0; /* signifies if audio frame was placed into the buffer or not */ switch (event) { case AST_FRAMEHOOK_EVENT_READ: break; case AST_FRAMEHOOK_EVENT_ATTACHED: case AST_FRAMEHOOK_EVENT_DETACHED: case AST_FRAMEHOOK_EVENT_WRITE: return frame; } if (ast_channel_fdno(chan) == AST_JITTERBUFFER_FD && framedata->timer) { if (ast_timer_ack(framedata->timer, 1) < 0) { ast_log(LOG_ERROR, "Failed to acknowledge timer in jitter buffer\n"); return frame; } } if (!frame) { return frame; } now_tv = ast_tvnow(); now = ast_tvdiff_ms(now_tv, framedata->start_tv); if (frame->frametype == AST_FRAME_VOICE) { int res; struct ast_frame *jbframe; if (!ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO) || frame->len < 2 || frame->ts < 0) { /* only frames with timing info can enter the jitterbuffer */ return frame; } jbframe = ast_frisolate(frame); ao2_replace(framedata->last_format, frame->subclass.format); if (frame->len && (frame->len != framedata->timer_interval)) { framedata->timer_interval = frame->len; ast_timer_set_rate(framedata->timer, 1000 / framedata->timer_interval); } if (!framedata->first) { framedata->first = 1; res = framedata->jb_impl->put_first(framedata->jb_obj, jbframe, now); } else { res = framedata->jb_impl->put(framedata->jb_obj, jbframe, now); } if (res == AST_JB_IMPL_OK) { if (jbframe != frame) { ast_frfree(frame); } frame = &ast_null_frame; } else if (jbframe != frame) { ast_frfree(jbframe); } putframe = 1; } if (frame->frametype == AST_FRAME_NULL) { int res; long next = framedata->jb_impl->next(framedata->jb_obj); /* If now is earlier than the next expected output frame * from the jitterbuffer we may choose to pass on retrieving * a frame during this read iteration. The only exception * to this rule is when an audio frame is placed into the buffer * and the time for the next frame to come out of the buffer is * at least within the timer_interval of the next output frame. By * doing this we are able to feed off the timing of the input frames * and only rely on our jitterbuffer timer when frames are dropped. * During testing, this hybrid form of timing gave more reliable results. */ if (now < next) { long int diff = next - now; if (!putframe) { return frame; } else if (diff >= framedata->timer_interval) { return frame; } } ast_frfree(frame); frame = &ast_null_frame; res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, framedata->timer_interval); switch (res) { case AST_JB_IMPL_OK: /* got it, and pass it through */ break; case AST_JB_IMPL_DROP: ast_frfree(frame); frame = &ast_null_frame; break; case AST_JB_IMPL_INTERP: if (framedata->last_format) { struct ast_frame tmp = { 0, }; tmp.frametype = AST_FRAME_VOICE; tmp.subclass.format = framedata->last_format; /* example: 8000hz / (1000 / 20ms) = 160 samples */ tmp.samples = ast_format_get_sample_rate(framedata->last_format) / (1000 / framedata->timer_interval); tmp.delivery = ast_tvadd(framedata->start_tv, ast_samp2tv(next, 1000)); tmp.offset = AST_FRIENDLY_OFFSET; tmp.src = "func_jitterbuffer interpolation"; ast_frfree(frame); frame = ast_frdup(&tmp); break; } /* else fall through */ case AST_JB_IMPL_NOFRAME: ast_frfree(frame); frame = &ast_null_frame; break; } } if (frame->frametype == AST_FRAME_CONTROL) { switch(frame->subclass.integer) { case AST_CONTROL_HOLD: case AST_CONTROL_UNHOLD: case AST_CONTROL_T38_PARAMETERS: case AST_CONTROL_SRCUPDATE: case AST_CONTROL_SRCCHANGE: framedata->jb_impl->force_resync(framedata->jb_obj); break; default: break; } } return frame; }