Esempio n. 1
0
PJ_DEF(pj_status_t) pjmedia_bidirectional_port_create( pj_pool_t *pool,
						       pjmedia_port *get_port,
						       pjmedia_port *put_port,
						       pjmedia_port **p_port )
{
    struct bidir_port *port;

    port = PJ_POOL_ZALLOC_T(pool, struct bidir_port);

    pjmedia_port_info_init(&port->base.info, &get_port->info.name, SIGNATURE,
			   get_port->info.clock_rate,
			   get_port->info.channel_count,
			   get_port->info.bits_per_sample,
			   get_port->info.samples_per_frame);

    port->get_port = get_port;
    port->put_port = put_port;

    port->base.get_frame = &get_frame;
    port->base.put_frame = &put_frame;

    *p_port = &port->base;

    return PJ_SUCCESS;
}
Esempio n. 2
0
pjs_port::pjs_port(const char * name,unsigned signature,
			  unsigned sampling_rate,
		      unsigned channel_count,
		      unsigned samples_per_frame,
		      unsigned bits_per_sample,
		      unsigned options):m_options(options)
{
	m_rx_mute = m_tx_mute = false;

	if(name)
	{
		m_name = (char *)malloc(strlen(name)+1);
		strcpy(m_name,name);
	}
	else
		m_name = NULL;
	pj_str_t name_str = pj_str(m_name);
	memset(&m_port,0,sizeof(m_port));
    pjmedia_port_info_init(&m_port.info, &name_str, signature, sampling_rate,
			   channel_count, bits_per_sample, samples_per_frame);

    m_port.get_frame = &get_frame_s;
    m_port.put_frame = &put_frame_s;
    m_port.on_destroy = &port_destroy_s;
    m_port.port_data.pdata = this;
}
Esempio n. 3
0
PJ_DEF(pj_status_t) pjmedia_null_port_create( pj_pool_t *pool,
					      unsigned sampling_rate,
					      unsigned channel_count,
					      unsigned samples_per_frame,
					      unsigned bits_per_sample,
					      pjmedia_port **p_port )
{
    pjmedia_port *port;
    const pj_str_t name = pj_str("null-port");

    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);

    port = pj_pool_zalloc(pool, sizeof(pjmedia_port));
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    pjmedia_port_info_init(&port->info, &name, SIGNATURE, sampling_rate,
			   channel_count, bits_per_sample, samples_per_frame);

    port->get_frame = &null_get_frame;
    port->put_frame = &null_put_frame;
    port->on_destroy = &null_on_destroy;


    *p_port = port;
    
    return PJ_SUCCESS;
}
Esempio n. 4
0
PJ_DEF(pj_status_t) pjmedia_bidirectional_port_create( pj_pool_t *pool,
						       pjmedia_port *get_port,
						       pjmedia_port *put_port,
						       pjmedia_port **p_port )
{
    struct bidir_port *port;
    const pjmedia_audio_format_detail *gafd;

    port = PJ_POOL_ZALLOC_T(pool, struct bidir_port);
    gafd = pjmedia_format_get_audio_format_detail(&get_port->info.fmt, 1);

    pjmedia_port_info_init(&port->base.info, &get_port->info.name, SIGNATURE,
			   gafd->clock_rate,
			   gafd->channel_count,
			   gafd->bits_per_sample,
			   PJMEDIA_AFD_SPF(gafd));

    port->get_port = get_port;
    port->put_port = put_port;

    port->base.get_frame = &get_frame;
    port->base.put_frame = &put_frame;

    *p_port = &port->base;

    return PJ_SUCCESS;
}
Esempio n. 5
0
PJ_DEF(pj_status_t) pjmedia_stereo_port_create( pj_pool_t *pool,
						pjmedia_port *dn_port,
						unsigned channel_count,
						unsigned options,
						pjmedia_port **p_port )
{
    const pj_str_t name = pj_str("stereo");
    struct stereo_port *sport;
    unsigned samples_per_frame;

    /* Validate arguments. */
    PJ_ASSERT_RETURN(pool && dn_port && channel_count && p_port, PJ_EINVAL);

    /* Only supports 16bit samples per frame */
    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS);

    /* Validate channel counts */
    PJ_ASSERT_RETURN(((dn_port->info.channel_count>1 && channel_count==1) ||
		      (dn_port->info.channel_count==1 && channel_count>1)),
		      PJ_EINVAL);

    /* Create and initialize port. */
    sport = PJ_POOL_ZALLOC_T(pool, struct stereo_port);
    PJ_ASSERT_RETURN(sport != NULL, PJ_ENOMEM);

    samples_per_frame = dn_port->info.samples_per_frame * channel_count /
			dn_port->info.channel_count;

    pjmedia_port_info_init(&sport->base.info, &name, SIGNATURE, 
			   dn_port->info.clock_rate,
			   channel_count, 
			   dn_port->info.bits_per_sample, 
			   samples_per_frame);

    sport->dn_port = dn_port;
    sport->options = options;

    /* We always need buffer for put_frame */
    sport->put_buf = (pj_int16_t*)
		     pj_pool_alloc(pool, dn_port->info.bytes_per_frame);

    /* See if we need buffer for get_frame */
    if (dn_port->info.channel_count > channel_count) {
	sport->get_buf = (pj_int16_t*)
			 pj_pool_alloc(pool, dn_port->info.bytes_per_frame);
    }

    /* Media port interface */
    sport->base.get_frame = &stereo_get_frame;
    sport->base.put_frame = &stereo_put_frame;
    sport->base.on_destroy = &stereo_destroy;


    /* Done */
    *p_port = &sport->base;

    return PJ_SUCCESS;
}
Esempio n. 6
0
/*
 * Create the splitter/combiner.
 */
PJ_DEF(pj_status_t) pjmedia_splitcomb_create( pj_pool_t *pool,
					      unsigned clock_rate,
					      unsigned channel_count,
					      unsigned samples_per_frame,
					      unsigned bits_per_sample,
					      unsigned options,
					      pjmedia_port **p_splitcomb)
{
    const pj_str_t name = pj_str("splitcomb");
    struct splitcomb *sc;

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
		     samples_per_frame && bits_per_sample &&
		     p_splitcomb, PJ_EINVAL);

    /* Only supports 16 bits per sample */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

    *p_splitcomb = NULL;

    /* Create the splitter/combiner structure */
    sc = pj_pool_zalloc(pool, sizeof(struct splitcomb));
    PJ_ASSERT_RETURN(sc != NULL, PJ_ENOMEM);

    /* Create temporary buffers */
    sc->get_buf = pj_pool_alloc(pool, samples_per_frame * 
				      sizeof(TMP_SAMP_TYPE) /
				      channel_count);
    PJ_ASSERT_RETURN(sc->get_buf, PJ_ENOMEM);

    sc->put_buf = pj_pool_alloc(pool, samples_per_frame * 
				      sizeof(TMP_SAMP_TYPE) /
				      channel_count);
    PJ_ASSERT_RETURN(sc->put_buf, PJ_ENOMEM);


    /* Save options */
    sc->options = options;

    /* Initialize port */
    pjmedia_port_info_init(&sc->base.info, &name, SIGNATURE, clock_rate,
			   channel_count, bits_per_sample, samples_per_frame);

    sc->base.put_frame = &put_frame;
    sc->base.get_frame = &get_frame;
    sc->base.on_destroy = &on_destroy;

    /* Init ports array */
    sc->port_desc = pj_pool_zalloc(pool, channel_count*sizeof(*sc->port_desc));

    /* Done for now */
    *p_splitcomb = &sc->base;

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_leaky_bucket_port_create(
        pj_pool_factory *pool_factory, pjmedia_port *dn_port,
        pj_size_t bucket_size, unsigned sent_delay, unsigned bits_per_second,
        unsigned packets_per_second, pjmedia_port **p_port)
{
    const pj_str_t leaky_bucket = { "leaky", 5 };
    struct leaky_bucket_port *lb;
    pj_pool_t *pool;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool_factory && dn_port && p_port, PJ_EINVAL);

    /* Create own memory pool */
    pool = pj_pool_create(pool_factory, "leaky", 4000, 4000, NULL);

    /* Create the port itself */
    lb = PJ_POOL_ZALLOC_T(pool, struct leaky_bucket_port);

    pjmedia_port_info_init(&lb->base.info, &leaky_bucket, SIGNATURE,
			   dn_port->info.clock_rate,
			   dn_port->info.channel_count,
			   dn_port->info.bits_per_sample,
			   dn_port->info.samples_per_frame);

    /* we have an empty list */
    lb->first_item = lb->last_item = NULL;
    lb->items = 0;

    /* More init */
    lb->dn_port = dn_port;
    lb->base.get_frame = &lb_get_frame;
    lb->base.put_frame = &lb_put_frame;
    lb->base.on_destroy = &lb_on_destroy;
    lb->bucket_size = bucket_size;
    lb->pool = pool;
    lb->last_ts.u64 = 0;
    lb->frames = 0;

    /* get a sent rate */
    if (sent_delay > 0){
        lb->sent_delay = sent_delay;
    } else if (packets_per_second > 0) {
        lb->sent_delay = (unsigned) ((double)lb->base.info.clock_rate / \
                packets_per_second);
    } else if (bits_per_second > 0) {
        lb->bits_per_second = bits_per_second;
    }
    PJ_LOG(5, (THIS_FILE, "Leaky bucket port created: bps=%u pps=%u "
                "sent_delay=%u bucket_size=%u", bits_per_second,
                packets_per_second, lb->sent_delay, bucket_size));

    /* Done */
    *p_port = &lb->base;

    return PJ_SUCCESS;
}
Esempio n. 8
0
PJ_DEF(pj_status_t) pjmedia_mem_capture_create( pj_pool_t *pool,
						void *buffer,
						pj_size_t size,
						unsigned clock_rate,
						unsigned channel_count,
						unsigned samples_per_frame,
						unsigned bits_per_sample,
						unsigned options,
						pjmedia_port **p_port)
{
    struct mem_rec *rec;
    const pj_str_t name = { "memrec", 6 };

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && buffer && size && clock_rate && channel_count &&
		     samples_per_frame && bits_per_sample && p_port,
		     PJ_EINVAL);

    /* Can only support 16bit PCM */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);


    rec = PJ_POOL_ZALLOC_T(pool, struct mem_rec);
    PJ_ASSERT_RETURN(rec != NULL, PJ_ENOMEM);

    /* Create the rec */
    pjmedia_port_info_init(&rec->base.info, &name, SIGNATURE,
			   clock_rate, channel_count, bits_per_sample, 
			   samples_per_frame);


    rec->base.put_frame = &rec_put_frame;
    rec->base.get_frame = &rec_get_frame;
    rec->base.on_destroy = &rec_on_destroy;


    /* Save the buffer */
    rec->buffer = rec->write_pos = (char*)buffer;
    rec->buf_size = size;

    /* Options */
    rec->options = options;

    *p_port = &rec->base;

    return PJ_SUCCESS;
}
/*
 * Create a media port to generate sine wave samples.
 */
static pj_status_t create_sine_port(pj_pool_t *pool,
				    unsigned sampling_rate,
				    unsigned channel_count,
				    pjmedia_port **p_port)
{
    pjmedia_port *port;
    unsigned i;
    unsigned count;
    pj_str_t name;
    port_data *sine;

    PJ_ASSERT_RETURN(pool && channel_count > 0 && channel_count <= 2, 
		     PJ_EINVAL);

    port = pj_pool_zalloc(pool, sizeof(pjmedia_port));
    PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);

    /* Fill in port info. */
    name = pj_str("sine generator");
    pjmedia_port_info_init(&port->info, &name,
                           PJMEDIA_SIG_CLASS_PORT_AUD('s', 'i'),
			   sampling_rate,
			   channel_count,
			   16, sampling_rate * 20 / 1000 * channel_count);
    
    /* Set the function to feed frame */
    port->get_frame = &sine_get_frame;

    /* Create sine port data */
    port->port_data.pdata = sine = pj_pool_zalloc(pool, sizeof(port_data));

    /* Create samples */
    count = PJMEDIA_PIA_SPF(&port->info) / channel_count;
    sine->samples = pj_pool_alloc(pool, count * sizeof(pj_int16_t));
    PJ_ASSERT_RETURN(sine->samples != NULL, PJ_ENOMEM);

    /* initialise sinusoidal wavetable */
    for( i=0; i<count; i++ )
    {
        sine->samples[i] = (pj_int16_t) (10000.0 * 
		sin(((double)i/(double)count) * M_PI * 8.) );
    }

    *p_port = port;

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_echo_port_create(pj_pool_t *pool,
					     pjmedia_port *dn_port,
					     unsigned tail_ms,
					     unsigned latency_ms,
					     unsigned options,
					     pjmedia_port **p_port )
{
    const pj_str_t AEC = { "EC", 2 };
    pjmedia_audio_format_detail *afd;
    struct ec *ec;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool && dn_port && p_port, PJ_EINVAL);

    afd = pjmedia_format_get_audio_format_detail(&dn_port->info.fmt, PJ_TRUE);

    PJ_ASSERT_RETURN(afd->bits_per_sample==16 && tail_ms,
		     PJ_EINVAL);

    /* Create the port and the AEC itself */
    ec = PJ_POOL_ZALLOC_T(pool, struct ec);
    
    pjmedia_port_info_init(&ec->base.info, &AEC, SIGNATURE,
			   afd->clock_rate,
			   afd->channel_count,
			   afd->bits_per_sample,
			   PJMEDIA_AFD_SPF(afd));

    status = pjmedia_echo_create2(pool, afd->clock_rate,
				  afd->channel_count,
				  PJMEDIA_AFD_SPF(afd),
				  tail_ms, latency_ms, options, &ec->ec);
    if (status != PJ_SUCCESS)
	return status;

    /* More init */
    ec->dn_port = dn_port;
    ec->base.get_frame = &ec_get_frame;
    ec->base.put_frame = &ec_put_frame;
    ec->base.on_destroy = &ec_on_destroy;

    /* Done */
    *p_port = &ec->base;

    return PJ_SUCCESS;
}
Esempio n. 11
0
PJ_DEF(pj_status_t) pjmedia_mem_player_create( pj_pool_t *pool,
					       const void *buffer,
					       pj_size_t size,
					       unsigned clock_rate,
					       unsigned channel_count,
					       unsigned samples_per_frame,
					       unsigned bits_per_sample,
					       unsigned options,
					       pjmedia_port **p_port )
{
    struct mem_player *port;
    pj_str_t name = pj_str("memplayer");

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && buffer && size && clock_rate && channel_count &&
		     samples_per_frame && bits_per_sample && p_port,
		     PJ_EINVAL);

    /* Can only support 16bit PCM */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);


    port = pj_pool_zalloc(pool, sizeof(struct mem_player));
    PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);

    /* Create the port */
    pjmedia_port_info_init(&port->base.info, &name, SIGNATURE, clock_rate,
			   channel_count, bits_per_sample, samples_per_frame);

    port->base.put_frame = &mem_put_frame;
    port->base.get_frame = &mem_get_frame;
    port->base.on_destroy = &mem_on_destroy;


    /* Save the buffer */
    port->buffer = port->read_pos = (char*)buffer;
    port->buf_size = size;

    /* Options */
    port->options = options;

    *p_port = &port->base;

    return PJ_SUCCESS;
}
Esempio n. 12
0
static struct playlist_port *create_file_list_port(pj_pool_t *pool,
						   const pj_str_t *name)
{
    struct playlist_port *port;

    port = pj_pool_zalloc(pool, sizeof(struct playlist_port));
    if (!port)
	return NULL;

    /* Put in default values.
     * These will be overriden once the file is read.
     */
    pjmedia_port_info_init(&port->base.info, name, SIGNATURE,
			   8000, 1, 16, 80);

    port->base.get_frame = &file_list_get_frame;
    port->base.on_destroy = &file_list_on_destroy;

    return port;
}
Esempio n. 13
0
PJ_DEF(pj_status_t) pjmedia_echo_port_create(pj_pool_t *pool,
					     pjmedia_port *dn_port,
					     unsigned tail_ms,
					     unsigned latency_ms,
					     unsigned options,
					     pjmedia_port **p_port )
{
    const pj_str_t AEC = { "EC", 2 };
    struct ec *ec;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool && dn_port && p_port, PJ_EINVAL);
    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample==16 && tail_ms, 
		     PJ_EINVAL);

    /* Create the port and the AEC itself */
    ec = pj_pool_zalloc(pool, sizeof(struct ec));
    
    pjmedia_port_info_init(&ec->base.info, &AEC, SIGNATURE,
			   dn_port->info.clock_rate, 
			   dn_port->info.channel_count, 
			   dn_port->info.bits_per_sample,
			   dn_port->info.samples_per_frame);

    status = pjmedia_echo_create(pool, dn_port->info.clock_rate, 
				 dn_port->info.samples_per_frame,
				 tail_ms, latency_ms, options, &ec->ec);
    if (status != PJ_SUCCESS)
	return status;

    /* More init */
    ec->dn_port = dn_port;
    ec->base.get_frame = &ec_get_frame;
    ec->base.put_frame = &ec_put_frame;
    ec->base.on_destroy = &ec_on_destroy;

    /* Done */
    *p_port = &ec->base;

    return PJ_SUCCESS;
}
Esempio n. 14
0
PJ_DECL(pj_status_t) pjmedia_plc_port_create(pj_pool_t *pool,
        pjmedia_port *dn_port, pjmedia_codec *codec, unsigned fpp,
        em_plc_mode plc_mode, pjmedia_port **p_port)
{
    const pj_str_t plc = { "plc", 3 };
    struct plc_port *plcp;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool && dn_port && p_port, PJ_EINVAL);

    /* Create the port itself */
    plcp = PJ_POOL_ZALLOC_T(pool, struct plc_port);
    plcp->frame_buf = pj_pool_zalloc(pool, BUF_SIZE);

    pjmedia_port_info_init(&plcp->base.info, &plc, SIGNATURE,
			   dn_port->info.clock_rate,
			   dn_port->info.channel_count,
			   dn_port->info.bits_per_sample,
			   dn_port->info.samples_per_frame*fpp);

    /* More init */
    plcp->dn_port = dn_port;
    plcp->codec = codec;
    plcp->fpp = fpp;
    plcp->plc_mode = plc_mode;
    plcp->base.get_frame = &plc_get_frame;
    plcp->base.put_frame = &plc_put_frame;
    plcp->base.on_destroy = &plc_on_destroy;
    plcp->frame.type = PJMEDIA_FRAME_TYPE_NONE;
    plcp->frame.buf = plcp->frame_buf;
    plcp->stats.received = 0;
    plcp->stats.lost = 0;
    plcp->stats.total = 0;

    /* Done */
    *p_port = &plcp->base;

    return PJ_SUCCESS;
}
Esempio n. 15
0
PJ_DEF(pj_status_t) pjmedia_silence_port_create(pj_pool_t *pool,
        pjmedia_port *dn_port, unsigned buffer_size, pjmedia_port **p_port)
{
    const pj_str_t silence = { "silence", 7 };
    struct silence_port *sp;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool && dn_port && p_port, PJ_EINVAL);

    /* Create the port itself */
    sp = PJ_POOL_ZALLOC_T(pool, struct silence_port);

    pjmedia_port_info_init(&sp->base.info, &silence, SIGNATURE,
			   dn_port->info.clock_rate,
			   dn_port->info.channel_count,
			   dn_port->info.bits_per_sample,
			   dn_port->info.samples_per_frame);

    /* More init */
    sp->dn_port = dn_port;
    sp->base.get_frame = &sp_get_frame;
    sp->base.put_frame = &sp_put_frame;
    sp->base.on_destroy = &sp_on_destroy;
    sp->frames = 0;
    sp->last_ts.u64 = 0;

    /* create circular buffer */
    if (!buffer_size)
        buffer_size = dn_port->info.bits_per_sample * \
                      dn_port->info.samples_per_frame * 16;
    pjmedia_circ_buf_create (pool, buffer_size, &sp->buf);

    /* Done */
    *p_port = &sp->base;

    return PJ_SUCCESS;
}
Esempio n. 16
0
pjmedia_mp3_writer_port_create( pj_pool_t *pool,
				const char *filename,
				unsigned sampling_rate,
				unsigned channel_count,
				unsigned samples_per_frame,
				unsigned bits_per_sample,
				const pjmedia_mp3_encoder_option *param_option,
				pjmedia_port **p_port )
{
    struct mp3_file_port *fport;
    pj_status_t status;

    status = init_blade_dll();
    if (status != PJ_SUCCESS)
	return status;

    /* Check arguments. */
    PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);

    /* Only supports 16bits per sample for now. */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

    /* Create file port instance. */
    fport = pj_pool_zalloc(pool, sizeof(struct mp3_file_port));
    PJ_ASSERT_RETURN(fport != NULL, PJ_ENOMEM);

    /* Initialize port info. */
    pj_strdup2_with_null(pool, &fport->mp3_filename, filename);
    pjmedia_port_info_init(&fport->base.info, &fport->mp3_filename, SIGNATURE,
			   sampling_rate, channel_count, bits_per_sample,
			   samples_per_frame);

    fport->base.get_frame = &file_get_frame;
    fport->base.put_frame = &file_put_frame;
    fport->base.on_destroy = &file_on_destroy;


    /* Open file in write and read mode.
     * We need the read mode because we'll modify the WAVE header once
     * the recording has completed.
     */
    status = pj_file_open(pool, filename, PJ_O_WRONLY, &fport->fd);
    if (status != PJ_SUCCESS) {
	deinit_blade_dll();
	return status;
    }

    /* Copy and initialize option with default settings */
    if (param_option) {
	pj_memcpy(&fport->mp3_option, param_option, 
		   sizeof(pjmedia_mp3_encoder_option));
    } else {
	pj_bzero(&fport->mp3_option, sizeof(pjmedia_mp3_encoder_option));
	fport->mp3_option.vbr = PJ_TRUE;
    }

    /* Calculate bitrate if it's not specified, only if it's not VBR. */
    if (fport->mp3_option.bit_rate == 0 && !fport->mp3_option.vbr) 
	fport->mp3_option.bit_rate = sampling_rate * channel_count;

    /* Set default quality if it's not specified */
    if (fport->mp3_option.quality == 0) 
	fport->mp3_option.quality = 2;

    /* Init mp3 encoder */
    status = init_mp3_encoder(fport, pool);
    if (status != PJ_SUCCESS) {
	pj_file_close(fport->fd);
	deinit_blade_dll();
	return status;
    }

    /* Done. */
    *p_port = &fport->base;

    PJ_LOG(4,(THIS_FILE, 
	      "MP3 file writer '%.*s' created: samp.rate=%dKHz, "
	      "bitrate=%dkbps%s, quality=%d",
	      (int)fport->base.info.name.slen,
	      fport->base.info.name.ptr,
	      fport->base.info.clock_rate/1000,
	      fport->mp3_option.bit_rate/1000,
	      (fport->mp3_option.vbr ? " (VBR)" : ""),
	      fport->mp3_option.quality));

    return PJ_SUCCESS;
}
Esempio n. 17
0
pjmedia_splitcomb_create_rev_channel( pj_pool_t *pool,
				      pjmedia_port *splitcomb,
				      unsigned ch_num,
				      unsigned options,
				      pjmedia_port **p_chport)
{
    const pj_str_t name = pj_str("splitcomb-ch");
    struct splitcomb *sc = (struct splitcomb*) splitcomb;
    struct reverse_port *rport;
    unsigned i;
    pjmedia_port *port;

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL);

    /* Make sure this is really a splitcomb port */
    PJ_ASSERT_RETURN(sc->base.info.signature == SIGNATURE, PJ_EINVAL);

    /* Check the channel number */
    PJ_ASSERT_RETURN(ch_num < sc->base.info.channel_count, PJ_EINVAL);

    /* options is unused for now */
    PJ_UNUSED_ARG(options);

    /* Create the port */
    rport = pj_pool_zalloc(pool, sizeof(struct reverse_port));
    rport->parent = sc;
    rport->ch_num = ch_num;

    /* Initialize port info... */
    port = &rport->base;
    pjmedia_port_info_init(&port->info, &name, SIGNATURE_PORT, 
			   splitcomb->info.clock_rate, 1, 
			   splitcomb->info.bits_per_sample, 
			   splitcomb->info.samples_per_frame / 
				   splitcomb->info.channel_count);

    /* ... and the callbacks */
    port->put_frame = &rport_put_frame;
    port->get_frame = &rport_get_frame;
    port->on_destroy = &rport_on_destroy;


    rport->buf_cnt = options & 0xFF;
    if (rport->buf_cnt == 0)
	rport->buf_cnt = MAX_BUF_CNT;

    /* Create put buffers */
    for (i=0; i<rport->buf_cnt; ++i) {
	rport->dnstream_buf[i] = pj_pool_zalloc(pool, port->info.bytes_per_frame);
	PJ_ASSERT_RETURN(rport->dnstream_buf[i], PJ_ENOMEM);
    }
    rport->dn_write_pos = rport->buf_cnt/2;

    /* Create get buffers */
    for (i=0; i<rport->buf_cnt; ++i) {
	rport->upstream_buf[i] = pj_pool_zalloc(pool, 
						port->info.bytes_per_frame);
	PJ_ASSERT_RETURN(rport->upstream_buf[i], PJ_ENOMEM);
    }
    rport->up_write_pos = rport->buf_cnt/2;


    /* Save port in the splitcomb */
    sc->port_desc[ch_num].port = &rport->base;
    sc->port_desc[ch_num].reversed = PJ_TRUE;


    /* Done */
    *p_chport = port;
    return PJ_SUCCESS;
}
Esempio n. 18
0
/*
 * Create file writer port.
 */
PJ_DEF(pj_status_t) pjmedia_wav_writer_port_create( pj_pool_t *pool,
						     const char *filename,
						     unsigned sampling_rate,
						     unsigned channel_count,
						     unsigned samples_per_frame,
						     unsigned bits_per_sample,
						     unsigned flags,
						     pj_ssize_t buff_size,
						     pjmedia_port **p_port )
{
    struct file_port *fport;
    pjmedia_wave_hdr wave_hdr;
    pj_ssize_t size;
    pj_str_t name;
    pj_status_t status;

    /* Check arguments. */
    PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);

    /* Only supports 16bits per sample for now.
     * See flush_buffer().
     */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

    /* Create file port instance. */
    fport = PJ_POOL_ZALLOC_T(pool, struct file_port);
    PJ_ASSERT_RETURN(fport != NULL, PJ_ENOMEM);

    /* Initialize port info. */
    pj_strdup2(pool, &name, filename);
    pjmedia_port_info_init(&fport->base.info, &name, SIGNATURE,
			   sampling_rate, channel_count, bits_per_sample,
			   samples_per_frame);

    fport->base.get_frame = &file_get_frame;
    fport->base.put_frame = &file_put_frame;
    fport->base.on_destroy = &file_on_destroy;

    if (flags == PJMEDIA_FILE_WRITE_ALAW) {
	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ALAW;
	fport->bytes_per_sample = 1;
    } else if (flags == PJMEDIA_FILE_WRITE_ULAW) {
	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ULAW;
	fport->bytes_per_sample = 1;
    } else {
	fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_PCM;
	fport->bytes_per_sample = 2;
    }

    /* Open file in write and read mode.
     * We need the read mode because we'll modify the WAVE header once
     * the recording has completed.
     */
    status = pj_file_open(pool, filename, PJ_O_WRONLY, &fport->fd);
    if (status != PJ_SUCCESS)
	return status;

    /* Initialize WAVE header */
    pj_bzero(&wave_hdr, sizeof(pjmedia_wave_hdr));
    wave_hdr.riff_hdr.riff = PJMEDIA_RIFF_TAG;
    wave_hdr.riff_hdr.file_len = 0; /* will be filled later */
    wave_hdr.riff_hdr.wave = PJMEDIA_WAVE_TAG;

    wave_hdr.fmt_hdr.fmt = PJMEDIA_FMT_TAG;
    wave_hdr.fmt_hdr.len = 16;
    wave_hdr.fmt_hdr.fmt_tag = (pj_uint16_t)fport->fmt_tag;
    wave_hdr.fmt_hdr.nchan = (pj_int16_t)channel_count;
    wave_hdr.fmt_hdr.sample_rate = sampling_rate;
    wave_hdr.fmt_hdr.bytes_per_sec = sampling_rate * channel_count * 
				     fport->bytes_per_sample;
    wave_hdr.fmt_hdr.block_align = (pj_uint16_t)
				   (fport->bytes_per_sample * channel_count);
    wave_hdr.fmt_hdr.bits_per_sample = (pj_uint16_t)
				       (fport->bytes_per_sample * 8);

    wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG;
    wave_hdr.data_hdr.len = 0;	    /* will be filled later */


    /* Convert WAVE header from host byte order to little endian
     * before writing the header.
     */
    pjmedia_wave_hdr_host_to_file(&wave_hdr);


    /* Write WAVE header */
    if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) {
	pjmedia_wave_subchunk fact_chunk;
	pj_uint32_t tmp = 0;

	fact_chunk.id = PJMEDIA_FACT_TAG;
	fact_chunk.len = 4;

	PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&fact_chunk);

	/* Write WAVE header without DATA chunk header */
	size = sizeof(pjmedia_wave_hdr) - sizeof(wave_hdr.data_hdr);
	status = pj_file_write(fport->fd, &wave_hdr, &size);
	if (status != PJ_SUCCESS) {
	    pj_file_close(fport->fd);
	    return status;
	}

	/* Write FACT chunk if it stores compressed data */
	size = sizeof(fact_chunk);
	status = pj_file_write(fport->fd, &fact_chunk, &size);
	if (status != PJ_SUCCESS) {
	    pj_file_close(fport->fd);
	    return status;
	}
	size = 4;
	status = pj_file_write(fport->fd, &tmp, &size);
	if (status != PJ_SUCCESS) {
	    pj_file_close(fport->fd);
	    return status;
	}

	/* Write DATA chunk header */
	size = sizeof(wave_hdr.data_hdr);
	status = pj_file_write(fport->fd, &wave_hdr.data_hdr, &size);
	if (status != PJ_SUCCESS) {
	    pj_file_close(fport->fd);
	    return status;
	}
    } else {
	size = sizeof(pjmedia_wave_hdr);
	status = pj_file_write(fport->fd, &wave_hdr, &size);
	if (status != PJ_SUCCESS) {
	    pj_file_close(fport->fd);
	    return status;
	}
    }

    /* Set buffer size. */
    if (buff_size < 1) buff_size = PJMEDIA_FILE_PORT_BUFSIZE;
    fport->bufsize = buff_size;

    /* Check that buffer size is greater than bytes per frame */
    pj_assert(fport->bufsize >= PJMEDIA_PIA_AVG_FSZ(&fport->base.info));


    /* Allocate buffer and set initial write position */
    fport->buf = (char*) pj_pool_alloc(pool, fport->bufsize);
    if (fport->buf == NULL) {
	pj_file_close(fport->fd);
	return PJ_ENOMEM;
    }
    fport->writepos = fport->buf;

    /* Done. */
    *p_port = &fport->base;

    PJ_LOG(4,(THIS_FILE, 
	      "File writer '%.*s' created: samp.rate=%d, bufsize=%uKB",
	      (int)fport->base.info.name.slen,
	      fport->base.info.name.ptr,
	      PJMEDIA_PIA_SRATE(&fport->base.info),
	      fport->bufsize / 1000));


    return PJ_SUCCESS;
}
Esempio n. 19
0
PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool,
						  pjmedia_port *dn_port,
						  unsigned clock_rate,
						  unsigned opt,
						  pjmedia_port **p_port  )
{
    const pj_str_t name = pj_str("resample");
    struct resample_port *rport;
    unsigned ptime;
    pj_status_t status;

    /* Validate arguments. */
    PJ_ASSERT_RETURN(pool && dn_port && clock_rate && p_port, PJ_EINVAL);

    /* Only supports 16bit samples per frame */
    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS);

    ptime = dn_port->info.samples_per_frame * 1000 / 
	    dn_port->info.clock_rate;
    
    /* Create and initialize port. */
    rport = PJ_POOL_ZALLOC_T(pool, struct resample_port);
    PJ_ASSERT_RETURN(rport != NULL, PJ_ENOMEM);

    pjmedia_port_info_init(&rport->base.info, &name, SIGNATURE, clock_rate,
			   dn_port->info.channel_count, BYTES_PER_SAMPLE * 8, 
			   clock_rate * ptime / 1000);

    rport->dn_port = dn_port;
    rport->options = opt;


    /* Create buffers. 
     * We need separate buffer for get_frame() and put_frame() since
     * both functions may run simultaneously.
     */
    rport->get_buf = (pj_int16_t*)
		     pj_pool_alloc(pool, dn_port->info.bytes_per_frame);
    PJ_ASSERT_RETURN(rport->get_buf != NULL, PJ_ENOMEM);

    rport->put_buf = (pj_int16_t*)
		     pj_pool_alloc(pool, dn_port->info.bytes_per_frame);
    PJ_ASSERT_RETURN(rport->put_buf != NULL, PJ_ENOMEM);


    /* Create "get_frame" resample */
    status = pjmedia_resample_create(pool, 
				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0,
				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
				     dn_port->info.channel_count,
				     dn_port->info.clock_rate, 
				     rport->base.info.clock_rate,
				     dn_port->info.samples_per_frame, 
				     &rport->resample_get);
    if (status != PJ_SUCCESS)
	return status;

    /* Create "put_frame" resample */
    status = pjmedia_resample_create(pool, 
				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, 
				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
				     dn_port->info.channel_count,
				     rport->base.info.clock_rate, 
				     dn_port->info.clock_rate,
				     rport->base.info.samples_per_frame,
				     &rport->resample_put);

    /* Media port interface */
    rport->base.get_frame = &resample_get_frame;
    rport->base.put_frame = &resample_put_frame;
    rport->base.on_destroy = &resample_destroy;


    /* Done */
    *p_port = &rport->base;

    return PJ_SUCCESS;
}
Esempio n. 20
0
/*
 * Create opus writer port.
 */
PJ_DEF(pj_status_t) pjmedia_opus_writer_port_create( pj_pool_t *pool,
						     const char *filename,
						     unsigned sampling_rate,
						     unsigned channel_count,
						     unsigned samples_per_frame,
						     unsigned bits_per_sample,
						     unsigned flags,
						     pj_ssize_t buff_size,
						     pjmedia_port **p_port ) {
  struct opus_port *oport;
  struct opus_tool_param *otp;
  pj_str_t         name;
  pj_status_t      status;
  pjmedia_frame    tempframe;
  int              i,ret;

  /* Check arguments. */
  PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);

  /* Only supports 16bits per sample for now. */
  PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

  /* Create file port instance. */
  oport = PJ_POOL_ZALLOC_T(pool, struct opus_port);
  PJ_ASSERT_RETURN(oport != NULL, PJ_ENOMEM);

  /* Initialize port info. */
  pj_strdup2(pool, &name, filename);
  pjmedia_port_info_init(&oport->base.info, &name, SIGNATURE,
      sampling_rate, channel_count, bits_per_sample,
      samples_per_frame);

  oport->base.get_frame = &opus_get_frame;
  oport->base.put_frame = &opus_put_frame;
  oport->base.on_destroy = &opus_on_destroy;
  oport->bytes_per_sample = 2;


  /**********************
   * opus-tool Start
   *********************/
  otp = PJ_POOL_ZALLOC_T(pool, struct opus_tool_param);
  PJ_ASSERT_RETURN(otp != NULL, PJ_ENOMEM);

  /* Initialize some default parameters. */
  otp->opt_ctls_ctlval=NULL;
  otp->frange=NULL;
  otp->range_file=NULL;
  otp->inopt.channels=channel_count;
  otp->inopt.rate=otp->coding_rate=otp->rate=sampling_rate;

  /* Some default value */
  otp->frame_size=960;
  otp->bitrate=-1;
  otp->with_hard_cbr=0;
  otp->with_cvbr=0;
  otp->complexity=10;
  otp->expect_loss=0;
  otp->lookahead=0;
  otp->bytes_written=0;
  otp->pages_out=0;
  otp->comment_padding=512;
  otp->eos=0;
  otp->nb_samples=-1;
  otp->id=-1;
  otp->nb_encoded=0;
  otp->enc_granulepos=0;
  otp->total_bytes=0;
  otp->peak_bytes=0;
  otp->max_ogg_delay=48000;

  /* 0 dB gain is recommended unless you know what you're doing */
  otp->inopt.gain=0;
  otp->inopt.samplesize=(oport->bytes_per_sample)*8;
  otp->inopt.endianness=0;
  otp->inopt.rawmode=0;
  otp->inopt.ignorelength=0;
  otp->inopt.copy_comments=1;
  otp->inopt.skip=0;

  otp->start_time = time(NULL);
  srand(((_getpid()&65535)<<15)^(otp->start_time));
  otp->serialno=rand();

  otp->opus_version="libopus 1.0.3";
  /* Vendor string should just be the encoder library,
     the ENCODER comment specifies the tool used. */
  comment_init(&otp->inopt.comments, &otp->inopt.comments_length, otp->opus_version);
  snprintf(otp->ENCODER_string, sizeof(otp->ENCODER_string), "opusenc from %s %s", PACKAGE_NAME, PACKAGE_VERSION);
  comment_add(&otp->inopt.comments, &otp->inopt.comments_length, "ENCODER", otp->ENCODER_string);

  otp->outFile=(char *)filename;
  otp->rate=otp->inopt.rate;
  otp->chan=otp->inopt.channels;
  otp->inopt.skip=0;

  if(otp->rate>24000)otp->coding_rate=48000;
  else if(otp->rate>16000)otp->coding_rate=24000;
  else if(otp->rate>12000)otp->coding_rate=16000;
  else if(otp->rate>8000)otp->coding_rate=12000;
  else otp->coding_rate=8000;

  otp->frame_size=otp->frame_size/(48000/otp->coding_rate);

  /*OggOpus headers*/ /*FIXME: broke forcemono*/
  otp->header.channels=otp->chan;
  otp->header.channel_mapping=otp->header.channels>8?255:otp->chan>2;
  otp->header.input_sample_rate=otp->rate;
  otp->header.gain=otp->inopt.gain;

  /* Initialize OPUS encoder */
  /* Framesizes <10ms can only use the MDCT modes, so we switch on RESTRICTED_LOWDELAY
     to save the extra 2.5ms of codec lookahead when we'll be using only small frames. */
  otp->st=opus_multistream_surround_encoder_create(otp->coding_rate, otp->chan, otp->header.channel_mapping, &otp->header.nb_streams, &otp->header.nb_coupled,
    otp->header.stream_map, otp->frame_size<480/(48000/otp->coding_rate)?OPUS_APPLICATION_RESTRICTED_LOWDELAY:OPUS_APPLICATION_AUDIO, &ret);

  if(ret!=OPUS_OK) {
    fprintf(stderr, "Error cannot create encoder: %s\n", opus_strerror(ret));
    exit(1);
  }

  otp->min_bytes=otp->max_frame_bytes=(1275*3+7)*otp->header.nb_streams;
  otp->packet=(unsigned char*)malloc(sizeof(unsigned char)*otp->max_frame_bytes);
  if(otp->packet==NULL) {
    fprintf(stderr, "Error allocating packet buffer.\n");
    exit(1);
  }

  if(otp->bitrate<0) {
    /* Lower default rate for sampling rates [8000-44100) by a factor of (rate+16k)/(64k) */
    otp->bitrate=((64000*otp->header.nb_streams+32000*otp->header.nb_coupled)*
        (IMIN(48,IMAX(8,((otp->rate<44100?otp->rate:48000)+1000)/1000))+16)+32)>>6;
  }
Esempio n. 21
0
pj_status_t pjmedia_sxs_port_server_create(// pj_pool_t *pool,
                                           // const char *filename,
                                            unsigned sampling_rate,
                                            unsigned channel_count,
                                            unsigned samples_per_frame,
                                            unsigned bits_per_sample,
                                            unsigned flags,
                                            pj_ssize_t buff_size,
                                            pjmedia_port **p_port)
{
    sxs_port *fport;
    pjmedia_wave_hdr wave_hdr;
    pj_ssize_t size;
    pj_str_t name;
    pj_status_t status;
    char f_type;

    /* Check arguments. */
    // PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);

    /* Only supports 16bits per sample for now.
     * See flush_buffer().
     */
    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);

    fport = (sxs_port_t *)calloc(1, sizeof(sxs_port_t));
    memset(fport, 0, sizeof(sxs_port_t));
    fport->eph = g_param->epfd;
    // fport->in_vocie_frame_rb = ringbuffer_create(1024*1024*2);
    fport->use_frame_buff = true;
    // fport->use_frame_buff = false;
    memset(fport->lock_free_rbuf_ptr, 0, sizeof(fport->lock_free_rbuf_ptr));
    fport->lock_free_rbuf_head_pos = fport->lock_free_rbuf_tail_pos = 0;

    name = pj_str("hahahahahaha");
    pjmedia_port_info_init(&fport->base.info, &name, SIGNATURE,
                           sampling_rate, channel_count, bits_per_sample,
                           samples_per_frame);

    // fport->base.get_frame = &file_get_frame;
    // fport->base.put_frame = &file_put_frame;
    fport->base.get_frame = NULL;
    fport->base.put_frame = NULL;
    //    fport->base.on_destroy = &file_on_destroy;

    if (flags == PJMEDIA_FILE_WRITE_ALAW) {
        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ALAW;
        fport->bytes_per_sample = 1;
    } else if (flags == PJMEDIA_FILE_WRITE_ULAW) {
        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ULAW;
        fport->bytes_per_sample = 1;
    } else {
        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_PCM;
        fport->bytes_per_sample = 2;
    }
    

    /* Set buffer size. */
    if (buff_size < 1) buff_size = PJMEDIA_FILE_PORT_BUFSIZE;
    fport->bufsize = buff_size;

    /* Check that buffer size is greater than bytes per frame */
    // pj_assert(fport->bufsize >= fport->base.info.bytes_per_frame);

    // socket, bind, listen, accept
    g_param->mpo_serv_sock = fport->out_serv_fd = create_tcp_server();
    g_param->mpi_serv_sock = fport->in_serv_fd = create_tcp_server();

    /* Done. */
    *p_port = &fport->base;

    PJ_LOG(4,(THIS_FILE, 
              "File writer '%.*s' created: samp.rate=%d, bufsize=%uKB, bytes per frame=%d", 
              (int)fport->base.info.name.slen,
              fport->base.info.name.ptr,
              fport->base.info.clock_rate,
              fport->bufsize / 1000, 
              fport->base.info.bytes_per_frame));


    return PJ_SUCCESS;
    return 0;
}
Esempio n. 22
0
/*
 * Create reverse phase port for the specified channel.
 */
PJ_DEF(pj_status_t) pjmedia_splitcomb_create_rev_channel( pj_pool_t *pool,
				      pjmedia_port *splitcomb,
				      unsigned ch_num,
				      unsigned options,
				      pjmedia_port **p_chport)
{
    const pj_str_t name = pj_str("scomb-rev");
    struct splitcomb *sc = (struct splitcomb*) splitcomb;
    struct reverse_port *rport;
    unsigned buf_cnt;
    const pjmedia_audio_format_detail *sc_afd, *p_afd;
    pjmedia_port *port;
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL);

    /* Make sure this is really a splitcomb port */
    PJ_ASSERT_RETURN(sc->base.info.signature == SIGNATURE, PJ_EINVAL);

    /* Check the channel number */
    PJ_ASSERT_RETURN(ch_num < PJMEDIA_PIA_CCNT(&sc->base.info), PJ_EINVAL);

    /* options is unused for now */
    PJ_UNUSED_ARG(options);

    sc_afd = pjmedia_format_get_audio_format_detail(&splitcomb->info.fmt, 1);

    /* Create the port */
    rport = PJ_POOL_ZALLOC_T(pool, struct reverse_port);
    rport->parent = sc;
    rport->ch_num = ch_num;

    /* Initialize port info... */
    port = &rport->base;
    pjmedia_port_info_init(&port->info, &name, SIGNATURE_PORT, 
			   sc_afd->clock_rate, 1,
			   sc_afd->bits_per_sample,
			   PJMEDIA_PIA_SPF(&splitcomb->info) /
				   sc_afd->channel_count);

    p_afd = pjmedia_format_get_audio_format_detail(&port->info.fmt, 1);

    /* ... and the callbacks */
    port->put_frame = &rport_put_frame;
    port->get_frame = &rport_get_frame;
    port->on_destroy = &rport_on_destroy;

    /* Buffer settings */
    buf_cnt = options & 0xFF;
    if (buf_cnt == 0)
	buf_cnt = MAX_BUF_CNT;

    rport->max_burst = MAX_BURST;
    rport->max_null_frames = MAX_NULL_FRAMES;

    /* Create downstream/put buffers */
    status = pjmedia_delay_buf_create(pool, "scombdb-dn",
				      p_afd->clock_rate,
				      PJMEDIA_PIA_SPF(&port->info),
				      p_afd->channel_count,
				      buf_cnt * p_afd->frame_time_usec / 1000,
				      0, &rport->buf[DIR_DOWNSTREAM].dbuf);
    if (status != PJ_SUCCESS) {
	return status;
    }

    /* Create upstream/get buffers */
    status = pjmedia_delay_buf_create(pool, "scombdb-up",
				      p_afd->clock_rate,
				      PJMEDIA_PIA_SPF(&port->info),
				      p_afd->channel_count,
				      buf_cnt * p_afd->frame_time_usec / 1000,
				      0, &rport->buf[DIR_UPSTREAM].dbuf);
    if (status != PJ_SUCCESS) {
	pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf);
	return status;
    }

    /* And temporary upstream/get buffer */
    rport->tmp_up_buf = (pj_int16_t*)
	                pj_pool_alloc(pool,
				      PJMEDIA_PIA_AVG_FSZ(&port->info));

    /* Save port in the splitcomb */
    sc->port_desc[ch_num].port = &rport->base;
    sc->port_desc[ch_num].reversed = PJ_TRUE;


    /* Done */
    *p_chport = port;
    return status;
}