Ejemplo n.º 1
0
/*! \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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/* 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);
}
Ejemplo n.º 4
0
/*! \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",
Ejemplo n.º 5
0
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;
}