Пример #1
0
/* Decrement the key's reference counter, and when the counter reach zero,
 * destroy the key.
 *
 * Note: MUST NOT CALL THIS FUNCTION WHILE HOLDING ioqueue's LOCK.
 */
static void decrement_counter(pj_ioqueue_key_t *key)
{
    pj_lock_acquire(key->ioqueue->lock);
    pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
    --key->ref_count;
    if (key->ref_count == 0) {

	pj_assert(key->closing == 1);
	pj_gettickcount(&key->free_time);
	key->free_time.msec += PJ_IOQUEUE_KEY_FREE_DELAY;
	pj_time_val_normalize(&key->free_time);

	pj_list_erase(key);
	pj_list_push_back(&key->ioqueue->closing_list, key);

    }
    pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
    pj_lock_release(key->ioqueue->lock);
}
Пример #2
0
PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
				 pj_ioqueue_key_t *key,
				 void *buffer,
				 pj_size_t buflen,
				 pj_sockaddr_t *addr,
				 int *addrlen)
{
    pj_mutex_lock(ioque->mutex);

    key->op |= PJ_IOQUEUE_OP_RECV_FROM;
    key->rd_buf = buffer;
    key->rd_buflen = buflen;
    key->rmt_addr = addr;
    key->rmt_addrlen = addrlen;
    PJ_FD_SET(key->fd, &ioque->rfdset);

    pj_mutex_unlock(ioque->mutex);
    return PJ_IOQUEUE_PENDING;
}
Пример #3
0
/* API: Register device change observer. */
PJ_DEF(pj_status_t) pjmedia_aud_dev_set_observer_cb(pjmedia_aud_dev_observer_callback cb)
{
    pj_status_t status;

    status = pj_mutex_lock(aud_subsys.dev_observer.lock);
    if (status != PJ_SUCCESS) {
        PJ_LOG(5, (THIS_FILE, "Could not acquire audio device change lock"));
        return status;
    }

    aud_subsys.dev_observer.cb = cb;

    status = pj_mutex_unlock(aud_subsys.dev_observer.lock);
    if (status != PJ_SUCCESS) {
        PJ_LOG(5, (THIS_FILE, "Could not release audio device change lock"));
    }

    return status;
}
Пример #4
0
/* Event worker thread function. */
static int event_worker_thread(void *arg)
{
    pjmedia_event_mgr *mgr = (pjmedia_event_mgr *)arg;

    while (1) {
	/* Wait until there is an event. */
        pj_sem_wait(mgr->sem);

        if (mgr->is_quitting)
            break;

        pj_mutex_lock(mgr->mutex);
        event_mgr_distribute_events(mgr, &mgr->ev_queue,
                                    &mgr->th_next_sub, PJ_TRUE);
        pj_mutex_unlock(mgr->mutex);
    }

    return 0;
}
Пример #5
0
PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,
			      pj_ioqueue_key_t *key,
			      const void *data,
			      pj_size_t datalen)
{
    if (pj_sock_send(key->fd, data, datalen, 0) != (pj_ssize_t)datalen)
	return -1;

    pj_mutex_lock(ioque->mutex);

    key->op |= PJ_IOQUEUE_OP_WRITE;
    key->wr_buf = NULL;
    key->wr_buflen = datalen;
    PJ_FD_SET(key->fd, &ioque->wfdset);

    pj_mutex_unlock(ioque->mutex);

    return PJ_IOQUEUE_PENDING;
}
Пример #6
0
/*
 * Allocate a new Speex codec instance.
 */
static pj_status_t spx_alloc_codec( pjmedia_codec_factory *factory, 
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pjmedia_codec *codec;
    struct spx_private *spx;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &spx_factory.base, PJ_EINVAL);


    pj_mutex_lock(spx_factory.mutex);

    /* Get free nodes, if any. */
    if (!pj_list_empty(&spx_factory.codec_list)) {
	codec = spx_factory.codec_list.next;
	pj_list_erase(codec);
    } else {
	codec = PJ_POOL_ZALLOC_T(spx_factory.pool, pjmedia_codec);
	PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
	codec->op = &spx_op;
	codec->factory = factory;
	codec->codec_data = pj_pool_alloc(spx_factory.pool,
					  sizeof(struct spx_private));
    }

    pj_mutex_unlock(spx_factory.mutex);

    spx = (struct spx_private*) codec->codec_data;
    spx->enc = NULL;
    spx->dec = NULL;

    if (id->clock_rate <= 8000)
	spx->param_id = PARAM_NB;
    else if (id->clock_rate <= 16000)
	spx->param_id = PARAM_WB;
    else
	spx->param_id = PARAM_UWB;

    *p_codec = codec;
    return PJ_SUCCESS;
}
Пример #7
0
/*
 * Find codecs by the unique codec identifier. This function will find
 * all codecs that match the codec identifier prefix. For example, if
 * "L16" is specified, then it will find "L16/8000/1", "L16/16000/1",
 * and so on, up to the maximum count specified in the argument.
 */
PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_find_codecs_by_id(
                                     pjmedia_vid_codec_mgr *mgr,
				     const pj_str_t *codec_id,
				     unsigned *count,
				     const pjmedia_vid_codec_info *p_info[],
				     unsigned prio[])
{
    unsigned i, found = 0;

    PJ_ASSERT_RETURN(codec_id && count && *count, PJ_EINVAL);

    if (!mgr) mgr = def_vid_codec_mgr;
    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);

    pj_mutex_lock(mgr->mutex);

    for (i=0; i<mgr->codec_cnt; ++i) {

	if (codec_id->slen == 0 ||
	    pj_strnicmp2(codec_id, mgr->codec_desc[i].id, 
			 codec_id->slen) == 0) 
	{

	    if (p_info)
		p_info[found] = &mgr->codec_desc[i].info;
	    if (prio)
		prio[found] = mgr->codec_desc[i].prio;

	    ++found;

	    if (found >= *count)
		break;
	}

    }

    pj_mutex_unlock(mgr->mutex);

    *count = found;

    return found ? PJ_SUCCESS : PJ_ENOTFOUND;
}
Пример #8
0
PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
			       pj_ioqueue_key_t *key,
			       const void *data,
			       pj_size_t datalen,
			       const pj_sockaddr_t *addr,
			       int addrlen)
{
    if (pj_sock_sendto(key->fd, data, datalen, 0, addr, addrlen) != (pj_ssize_t)datalen)
	return -1;

    pj_mutex_lock(ioque->mutex);

    key->op |= PJ_IOQUEUE_OP_SEND_TO;
    key->wr_buf = NULL;
    key->wr_buflen = datalen;
    PJ_FD_SET(key->fd, &ioque->wfdset);

    pj_mutex_unlock(ioque->mutex);
    return PJ_IOQUEUE_PENDING;
}
Пример #9
0
/*
 * Modify codec settings.
 */
static pj_status_t  codec_modify( pjmedia_codec *codec, 
				  const pjmedia_codec_param *attr )
{
    struct opus_data *opus_data = (struct opus_data *)codec->codec_data;

    pj_mutex_lock (opus_data->mutex);

    TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));

    /* Set bitrate */
    opus_data->cfg.bit_rate = attr->info.avg_bps;
    opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps));
    /* Set VAD */
    opus_encoder_ctl(opus_data->enc, OPUS_SET_DTX(attr->setting.vad ? 1 : 0));
    /* Set PLC */
    opus_encoder_ctl(opus_data->enc,
    		     OPUS_SET_INBAND_FEC(attr->setting.plc ? 1 : 0));

    pj_mutex_unlock (opus_data->mutex);
    return PJ_SUCCESS;
}
Пример #10
0
/*
 * Release read lock.
 *
 */
PJ_DEF(pj_status_t) pj_rwmutex_unlock_read(pj_rwmutex_t *mutex)
{
    pj_status_t status;

    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

    status = pj_mutex_lock(mutex->read_lock);
    if (status != PJ_SUCCESS) {
	pj_assert(!"This pretty much is unexpected");
	return status;
    }

    pj_assert(mutex->reader_count >= 1);

    --mutex->reader_count;
    if (mutex->reader_count == 0)
	pj_sem_post(mutex->write_lock);

    status = pj_mutex_unlock(mutex->read_lock);
    return status;
}
Пример #11
0
static pj_status_t l16_dealloc_codec(pjmedia_codec_factory *factory, 
				     pjmedia_codec *codec )
{
    struct l16_data *data;

    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);

    /* Lock mutex. */
    pj_mutex_lock(l16_factory.mutex);

    /* Just release codec data pool */
    data = (struct l16_data*) codec->codec_data;
    pj_assert(data);
    pj_pool_release(data->pool);

    /* Unlock mutex. */
    pj_mutex_unlock(l16_factory.mutex);

    return PJ_SUCCESS;
}
Пример #12
0
/*
 * Free codec.
 */
static pj_status_t spx_dealloc_codec( pjmedia_codec_factory *factory, 
				      pjmedia_codec *codec )
{
    struct spx_private *spx;

    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &spx_factory.base, PJ_EINVAL);

    /* Close codec, if it's not closed. */
    spx = (struct spx_private*) codec->codec_data;
    if (spx->enc != NULL || spx->dec != NULL) {
	spx_codec_close(codec);
    }

    /* Put in the free list. */
    pj_mutex_lock(spx_factory.mutex);
    pj_list_push_front(&spx_factory.codec_list, codec);
    pj_mutex_unlock(spx_factory.mutex);

    return PJ_SUCCESS;
}
Пример #13
0
/* If this timer callback is called, it means subscriber hasn't refreshed its
 * subscription on-time. Set the state to terminated. This will also send
 * NOTIFY with Subscription-State set to terminated.
 */
static void uas_expire_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry)
{
    pjsip_event_sub *sub = entry->user_data;
    pj_str_t reason = { "timeout", 7 };

    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): UAS subscription expired!", 
			 sub, state[sub->state].ptr));

    pj_mutex_lock(sub->mutex);
    sub->timer.id = 0;

    if (sub->cb.on_sub_terminated && sub->state!=PJSIP_EVENT_SUB_STATE_TERMINATED) {
	/* Notify application, but prevent app from destroying the sub. */
	++sub->pending_tsx;
	(*sub->cb.on_sub_terminated)(sub, &reason);
	--sub->pending_tsx;
    }
    //pjsip_event_sub_notify( sub, PJSIP_EVENT_SUB_STATE_TERMINATED, 
    //			    &reason, NULL);
    pj_mutex_unlock(sub->mutex);

}
Пример #14
0
/*
 * Allocate a new SILK codec instance.
 */
static pj_status_t silk_alloc_codec(pjmedia_codec_factory *factory,
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pjmedia_codec *codec;
    struct silk_private *silk;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &silk_factory.base, PJ_EINVAL);


    pj_mutex_lock(silk_factory.mutex);

    /* Get free nodes, if any. */
    if (!pj_list_empty(&silk_factory.codec_list)) {
		codec = silk_factory.codec_list.next;
		pj_list_erase(codec);
    } else {
		codec = PJ_POOL_ZALLOC_T(silk_factory.pool, pjmedia_codec);
		PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
		codec->op = &silk_op;
		codec->factory = factory;
		codec->codec_data = pj_pool_alloc(silk_factory.pool,
						  sizeof(struct silk_private));
    }

    pj_mutex_unlock(silk_factory.mutex);

    silk = (struct silk_private*) codec->codec_data;
    silk->enc_ready = PJ_FALSE;
    silk->dec_ready = PJ_FALSE;
    silk->param_id = silk_get_type_for_clock_rate(id->clock_rate);

    /* Create pool for codec instance */
    silk->pool = pjmedia_endpt_create_pool(silk_factory.endpt, "silkcodec", 512, 512);

    *p_codec = codec;
    return PJ_SUCCESS;
}
Пример #15
0
/*!
 * \internal
 * \brief Find the request tdata to get the serializer it used.
 * \since 14.0.0
 *
 * \param rdata The incoming message.
 *
 * \retval serializer on success.
 * \retval NULL on error or could not find the serializer.
 */
static struct ast_taskprocessor *find_request_serializer(pjsip_rx_data *rdata)
{
	struct ast_taskprocessor *serializer = NULL;
	pj_str_t tsx_key;
	pjsip_transaction *tsx;

	pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC,
		&rdata->msg_info.cseq->method, rdata);

	tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
	if (!tsx) {
		ast_debug(1, "Could not find %.*s transaction for %d response.\n",
			(int) pj_strlen(&rdata->msg_info.cseq->method.name),
			pj_strbuf(&rdata->msg_info.cseq->method.name),
			rdata->msg_info.msg->line.status.code);
		return NULL;
	}

	if (tsx->last_tx) {
		const char *serializer_name;

		serializer_name = tsx->last_tx->mod_data[distributor_mod.id];
		if (!ast_strlen_zero(serializer_name)) {
			serializer = ast_taskprocessor_get(serializer_name, TPS_REF_IF_EXISTS);
			if (serializer) {
				ast_debug(3, "Found serializer %s on transaction %s\n",
						serializer_name, tsx->obj_name);
			}
		}
	}

#ifdef HAVE_PJ_TRANSACTION_GRP_LOCK
	pj_grp_lock_release(tsx->grp_lock);
#else
	pj_mutex_unlock(tsx->mutex);
#endif

	return serializer;
}
Пример #16
0
static pj_status_t event_mgr_distribute_events(pjmedia_event_mgr *mgr,
                                               event_queue *ev_queue,
                                               esub **next_sub,
                                               pj_bool_t rls_lock)
{
    pj_status_t err = PJ_SUCCESS;
    esub * sub = mgr->esub_list.next;
    pjmedia_event *ev = &ev_queue->events[ev_queue->head];

    while (sub != &mgr->esub_list) {
        *next_sub = sub->next;

        /* Check if the subscriber is interested in 
         * receiving the event from the publisher.
         */
        if (sub->epub == ev->epub || !sub->epub) {
            pjmedia_event_cb *cb = sub->cb;
            void *user_data = sub->user_data;
            pj_status_t status;
            
            if (rls_lock)
                pj_mutex_unlock(mgr->mutex);

            status = (*cb)(ev, user_data);
            if (status != PJ_SUCCESS && err == PJ_SUCCESS)
	        err = status;

            if (rls_lock)
                pj_mutex_lock(mgr->mutex);
        }
	sub = *next_sub;
    }
    *next_sub = NULL;

    ev_queue->head = (ev_queue->head + 1) % MAX_EVENTS;
    ev_queue->is_full = PJ_FALSE;

    return err;
}
Пример #17
0
/*
 * Set route-set.
 */
PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,
						   const pjsip_route_hdr *route_set )
{
    const pjsip_route_hdr *hdr;

    pj_mutex_lock(sub->mutex);

    /* Clear existing route set. */
    pj_list_init(&sub->route_set);

    /* Duplicate route headers. */
    hdr = route_set->next;
    while (hdr != route_set) {
	pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr);
	pj_list_insert_before(&sub->route_set, new_hdr);
	hdr = hdr->next;
    }

    pj_mutex_unlock(sub->mutex);

    return 0;
}
Пример #18
0
pjmedia_event_unsubscribe(pjmedia_event_mgr *mgr,
                          pjmedia_event_cb *cb,
                          void *user_data,
                          void *epub)
{
    esub *sub;

    PJ_ASSERT_RETURN(cb, PJ_EINVAL);

    if (!mgr) mgr = pjmedia_event_mgr_instance();
    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);

    pj_mutex_lock(mgr->mutex);
    sub = mgr->esub_list.next;
    while (sub != &mgr->esub_list) {
	esub *next = sub->next;
        if (sub->cb == cb && (sub->user_data == user_data || !user_data) &&
            (sub->epub == epub || !epub))
        {
            /* If the worker thread or pjmedia_event_publish() API is
             * in the process of distributing events, make sure that
             * its pointer to the next subscriber stays valid.
             */
            if (mgr->th_next_sub == sub)
                mgr->th_next_sub = sub->next;
            if (mgr->pub_next_sub == sub)
                mgr->pub_next_sub = sub->next;
            pj_list_erase(sub);
            pj_list_push_back(&mgr->free_esub_list, sub);
            if (user_data && epub)
                break;
        }
	sub = next;
    }
    pj_mutex_unlock(mgr->mutex);

    return PJ_SUCCESS;
}
Пример #19
0
PJ_DEF(pj_status_t) pjmedia_codec_g711_deinit(void)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (g711_factory.endpt == NULL) {
	/* Not registered. */
	return PJ_SUCCESS;
    }

    /* Lock mutex. */
    pj_mutex_lock(g711_factory.mutex);

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(g711_factory.endpt);
    if (!codec_mgr) {
	g711_factory.endpt = NULL;
	pj_mutex_unlock(g711_factory.mutex);
	return PJ_EINVALIDOP;
    }

    /* Unregister G711 codec factory. */
    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
						  &g711_factory.base);
    g711_factory.endpt = NULL;

    /* Destroy mutex. */
    pj_mutex_destroy(g711_factory.mutex);
    g711_factory.mutex = NULL;


    /* Release pool. */
    pj_pool_release(g711_factory.pool);
    g711_factory.pool = NULL;


    return status;
}
Пример #20
0
/* Find subscription in the hash table. 
 * If found, lock the subscription before returning to caller.
 */
static pjsip_event_sub *find_sub(pjsip_rx_data *rdata)
{
    pj_str_t key;
    pjsip_role_e role;
    pjsip_event_sub *sub;
    pjsip_method *method = &rdata->msg->line.req.method;
    pj_str_t *tag;

    if (rdata->msg->type == PJSIP_REQUEST_MSG) {
	if (pjsip_method_cmp(method, &SUBSCRIBE)==0) {
	    role = PJSIP_ROLE_UAS;
	    tag = &rdata->to_tag;
	} else {
	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);
	    role = PJSIP_ROLE_UAC;
	    tag = &rdata->to_tag;
	}
    } else {
	if (pjsip_method_cmp(&rdata->cseq->method, &SUBSCRIBE)==0) {
	    role = PJSIP_ROLE_UAC;
	    tag = &rdata->from_tag;
	} else {
	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);
	    role = PJSIP_ROLE_UAS;
	    tag = &rdata->from_tag;
	}
    }
    create_subscriber_key( &key, rdata->pool, role, &rdata->call_id, tag);

    pj_mutex_lock(mgr.mutex);
    sub = pj_hash_get(mgr.ht, key.ptr, key.slen);
    if (sub)
	pj_mutex_lock(sub->mutex);
    pj_mutex_unlock(mgr.mutex);

    return sub;
}
Пример #21
0
/*
 * Free codec.
 */
static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory, 
				      pjmedia_codec *codec )
{
    struct gsm_data *gsm_data;
    int i;

    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);

    gsm_data = (struct gsm_data*) codec->codec_data;

    /* Close codec, if it's not closed. */
    gsm_codec_close(codec);

#if !PLC_DISABLED
    /* Clear left samples in the PLC, since codec+plc will be reused
     * next time.
     */
    for (i=0; i<2; ++i) {
	pj_int16_t frame[160];
	pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
	pjmedia_plc_save(gsm_data->plc, frame);
    }
#else
    PJ_UNUSED_ARG(i);
#endif

    /* Re-init silence_period */
    pj_set_timestamp32(&gsm_data->last_tx, 0, 0);

    /* Put in the free list. */
    pj_mutex_lock(gsm_codec_factory.mutex);
    pj_list_push_front(&gsm_codec_factory.codec_list, codec);
    pj_mutex_unlock(gsm_codec_factory.mutex);

    return PJ_SUCCESS;
}
Пример #22
0
PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
					       pj_ioqueue_t *ioque,
					       pj_oshandle_t sock,
					       void *user_data,
					       const pj_ioqueue_callback *cb)
{
    pj_ioqueue_key_t *key = NULL;
    pj_uint32_t value;
    
    pj_mutex_lock(ioque->mutex);

    if (ioque->count >= ioque->max)
	goto on_return;

    /* Set socket to nonblocking. */
    value = 1;
    if (pj_sock_ioctl((pj_sock_t)sock, PJ_FIONBIO, &value)) {
	PJ_PERROR(("ioqueue", "Error setting FIONBIO"));
	goto on_return;
    }

    /* Create key. */
    key = (pj_ioqueue_key_t*)pj_pool_calloc(pool, 1, sizeof(pj_ioqueue_key_t));
    key->fd = (pj_sock_t)sock;
    key->user_data = user_data;

    /* Save callback. */
    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));

    /* Register */
    pj_list_insert_before(&ioque->hlist, key);
    ++ioque->count;

on_return:
    pj_mutex_unlock(ioque->mutex);
    return key;
}
Пример #23
0
/*
 * Allocate a new OPUS codec instance.
 */
static pj_status_t opus_alloc_codec(pjmedia_codec_factory *factory,
                                    const pjmedia_codec_info *id,
                                    pjmedia_codec **p_codec) {
  pjmedia_codec *codec;
  struct opus_private *opus;

  PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
  PJ_ASSERT_RETURN(factory == &opus_factory.base, PJ_EINVAL);

  pj_mutex_lock(opus_factory.mutex);

  /* Get free nodes, if any. */
  if (!pj_list_empty(&opus_factory.codec_list)) {
    codec = opus_factory.codec_list.next;
    pj_list_erase(codec);
  } else {
    codec = PJ_POOL_ZALLOC_T(opus_factory.pool, pjmedia_codec);
    PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
    codec->op = &opus_op;
    codec->factory = factory;
    codec->codec_data =
        pj_pool_alloc(opus_factory.pool, sizeof(struct opus_private));
  }

  pj_mutex_unlock(opus_factory.mutex);

  opus = (struct opus_private *)codec->codec_data;
  opus->enc_ready = PJ_FALSE;
  opus->dec_ready = PJ_FALSE;

  /* Create pool for codec instance */
  opus->pool =
      pjmedia_endpt_create_pool(opus_factory.endpt, "opuscodec", 512, 512);

  *p_codec = codec;
  return PJ_SUCCESS;
}
Пример #24
0
/*
 * Initiate overlapped connect() operation (well, it's non-blocking actually,
 * since there's no overlapped version of connect()).
 */
PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
					const pj_sockaddr_t *addr,
					int addrlen )
{
    pj_status_t status;
    
    /* check parameters. All must be specified! */
    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);

    /* Check if key is closing. */
    if (IS_CLOSING(key))
	return PJ_ECANCELLED;

    /* Check if socket has not been marked for connecting */
    if (key->connecting != 0)
        return PJ_EPENDING;
    
    status = pj_sock_connect(key->fd, addr, addrlen);
    if (status == PJ_SUCCESS) {
	/* Connected! */
	return PJ_SUCCESS;
    } else {
	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
	    /* Pending! */
            pj_mutex_lock(key->mutex);
	    key->connecting = PJ_TRUE;
            ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
            ioqueue_add_to_set(key->ioqueue, key, EXCEPTION_EVENT);
            pj_mutex_unlock(key->mutex);
	    return PJ_EPENDING;
	} else {
	    /* Error! */
	    return status;
	}
    }
}
Пример #25
0
/*
 * Close codec.
 */
static pj_status_t ffmpeg_codec_close( pjmedia_vid_codec *codec )
{
    ffmpeg_private *ff;
    pj_mutex_t *ff_mutex;

    PJ_ASSERT_RETURN(codec, PJ_EINVAL);
    ff = (ffmpeg_private*)codec->codec_data;
    ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;

    pj_mutex_lock(ff_mutex);
    if (ff->enc_ctx) {
        avcodec_close(ff->enc_ctx);
        av_free(ff->enc_ctx);
    }
    if (ff->dec_ctx && ff->dec_ctx!=ff->enc_ctx) {
        avcodec_close(ff->dec_ctx);
        av_free(ff->dec_ctx);
    }
    ff->enc_ctx = NULL;
    ff->dec_ctx = NULL;
    pj_mutex_unlock(ff_mutex);

    return PJ_SUCCESS;
}
Пример #26
0
/* Increment key's reference counter */
static void increment_counter(pj_ioqueue_key_t *key)
{
    pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
    ++key->ref_count;
    pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
}
Пример #27
0
/* Test with recursive mutex. */
static int recursive_mutex_test(pj_pool_t *pool)
{
    pj_status_t rc;
    pj_mutex_t *mutex;

    PJ_LOG(3,("", "...testing recursive mutex"));

    /* Create mutex. */
    TRACE_(("", "....create mutex"));
    rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_create", rc);
	return -10;
    }

    /* Normal lock/unlock cycle. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_lock", rc);
	return -20;
    }
    TRACE_(("", "....unlock mutex"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_unlock", rc);
	return -30;
    }
    
    /* Lock again. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) return -40;

    /* Try-lock should NOT fail. . */
    TRACE_(("", "....trylock mutex"));
    rc = pj_mutex_trylock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: recursive mutex is not recursive!", rc);
	return -40;
    }

    /* Locking again should not fail. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: recursive mutex is not recursive!", rc);
	return -45;
    }

    /* Unlock several times and done. */
    TRACE_(("", "....unlock mutex 3x"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -50;
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -51;
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -52;

    TRACE_(("", "....destroy mutex"));
    rc = pj_mutex_destroy(mutex);
    if (rc != PJ_SUCCESS) return -60;

    TRACE_(("", "....done"));
    return PJ_SUCCESS;
}
Пример #28
0
/*
 * Decode frame.
 */
static pj_status_t  codec_decode( pjmedia_codec *codec, 
				  const struct pjmedia_frame *input,
				  unsigned output_buf_len, 
				  struct pjmedia_frame *output )
{
    struct opus_data *opus_data = (struct opus_data *)codec->codec_data;
    int decoded_samples;
    pjmedia_frame *inframe;
    int fec = 0;

    pj_mutex_lock (opus_data->mutex);

    if (opus_data->dec_frame_index == -1) {
        /* First packet, buffer it. */
        opus_data->dec_frame[0].type = input->type;
        opus_data->dec_frame[0].size = input->size;
        opus_data->dec_frame[0].timestamp = input->timestamp;
        pj_memcpy(opus_data->dec_frame[0].buf, input->buf, input->size);
        opus_data->dec_frame_index = 0;
        pj_mutex_unlock (opus_data->mutex);

        /* Return zero decoded bytes */
        output->size = 0;
        output->type = PJMEDIA_FRAME_TYPE_NONE;
        output->timestamp = input->timestamp;

        return PJ_SUCCESS;
    }

    inframe = &opus_data->dec_frame[opus_data->dec_frame_index];

    if (inframe->type != PJMEDIA_FRAME_TYPE_AUDIO) {
        /* Update current frame index */
        opus_data->dec_frame_index++;
        if (opus_data->dec_frame_index > 1)
            opus_data->dec_frame_index = 0;
        /* Copy original input buffer to current indexed frame */
        inframe = &opus_data->dec_frame[opus_data->dec_frame_index];
        inframe->type = input->type;
        inframe->size = input->size;
        inframe->timestamp = input->timestamp;
        pj_memcpy(inframe->buf, input->buf, input->size);
        fec = 1;
     }

     decoded_samples = opus_decode(opus_data->dec,
                                   inframe->type==PJMEDIA_FRAME_TYPE_AUDIO ?
                                   inframe->buf : NULL,
                                   inframe->type==PJMEDIA_FRAME_TYPE_AUDIO ?
                                   inframe->size : 0,
                                   (opus_int16*)output->buf,
                                   output->size / (sizeof(opus_int16) *
				   opus_data->cfg.channel_cnt),
                                   fec);
     output->timestamp = inframe->timestamp;
     
     if (inframe->type == PJMEDIA_FRAME_TYPE_AUDIO) {
        /* Mark current indexed frame as invalid */
        inframe->type = PJMEDIA_FRAME_TYPE_NONE;
        /* Update current frame index */
        opus_data->dec_frame_index++;
        if (opus_data->dec_frame_index > 1)
            opus_data->dec_frame_index = 0;
        /* Copy original input buffer to current indexed frame */
        inframe = &opus_data->dec_frame[opus_data->dec_frame_index];
        inframe->type = input->type;
        inframe->size = input->size;
        inframe->timestamp = input->timestamp;
        pj_memcpy(inframe->buf, input->buf, input->size);
    }

    if (decoded_samples < 0) {
        PJ_LOG(4, (THIS_FILE, "Decode failed!"));
        pj_mutex_unlock (opus_data->mutex);
        return PJMEDIA_CODEC_EFAILED;
    }

    output->size = decoded_samples * sizeof(opus_int16) * 
    		   opus_data->cfg.channel_cnt;
    output->type = PJMEDIA_FRAME_TYPE_AUDIO;

    pj_mutex_unlock (opus_data->mutex);
    return PJ_SUCCESS;
}
Пример #29
0
/*
 * Encode frame.
 */
static pj_status_t codec_encode( pjmedia_codec *codec, 
				 const struct pjmedia_frame *input,
				 unsigned output_buf_len, 
				 struct pjmedia_frame *output )
{
    struct opus_data *opus_data = (struct opus_data *)codec->codec_data;
    opus_int32 size  = 0;
    unsigned in_pos  = 0;
    unsigned out_pos = 0;
    unsigned frame_size;
    unsigned samples_per_frame;
    unsigned char tmp_buf[MAX_ENCODED_PACKET_SIZE];
    unsigned tmp_bytes_left = sizeof(tmp_buf);

    pj_mutex_lock (opus_data->mutex);

    samples_per_frame = (opus_data->cfg.sample_rate *
			 opus_data->ptime) / 1000;
    frame_size = samples_per_frame * opus_data->cfg.channel_cnt *
    		 sizeof(opus_int16);

    opus_repacketizer_init(opus_data->enc_packer);
    while (input->size - in_pos >= frame_size) {
	size = opus_encode(opus_data->enc,
			   (const opus_int16*)(((char*)input->buf) + in_pos),
			   samples_per_frame,
			   tmp_buf + out_pos,
			   (tmp_bytes_left < frame_size ?
			    tmp_bytes_left : frame_size));
	if (size < 0) {
	    PJ_LOG(4, (THIS_FILE, "Encode failed! (%d)", size));
            pj_mutex_unlock (opus_data->mutex);
	    return PJMEDIA_CODEC_EFAILED;
	} else if (size > 0) {
	    /* Only add packets containing more than the TOC */
	    opus_repacketizer_cat(opus_data->enc_packer,
				  tmp_buf + out_pos,
				  size);
	    out_pos += size;
	    tmp_bytes_left -= size;
	}
	in_pos += frame_size;
    }

    if (!opus_repacketizer_get_nb_frames(opus_data->enc_packer)) {
	/* Empty packet */
	output->size      = 0;
	output->type      = PJMEDIA_FRAME_TYPE_NONE;
	output->timestamp = input->timestamp;
    }

    if (size) {
	size = opus_repacketizer_out(opus_data->enc_packer,
				     output->buf,
				     output_buf_len);
	if (size < 0) {
	    PJ_LOG(4, (THIS_FILE, "Encode failed! (%d), out_size: %u",
	    			  size, output_buf_len));
	    pj_mutex_unlock (opus_data->mutex);
	    return PJMEDIA_CODEC_EFAILED;
	}
    }

    output->size      = (unsigned)size;
    output->type      = PJMEDIA_FRAME_TYPE_AUDIO;
    output->timestamp = input->timestamp;

    pj_mutex_unlock (opus_data->mutex);
    return PJ_SUCCESS;
}
Пример #30
0
/*
 * Open codec.
 */
static pj_status_t  codec_open( pjmedia_codec *codec,
				pjmedia_codec_param *attr )
{
    struct opus_data *opus_data = (struct opus_data *)codec->codec_data;
    int idx, err;

    PJ_ASSERT_RETURN(codec && attr && opus_data, PJ_EINVAL);

    pj_mutex_lock (opus_data->mutex);

    TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));

    opus_data->cfg.sample_rate = attr->info.clock_rate;
    opus_data->cfg.channel_cnt = attr->info.channel_cnt;
    opus_data->ptime       = attr->info.frm_ptime;

    /* Allocate memory used by the codec */
    if (!opus_data->enc) {
	/* Allocate memory for max 2 channels */
	opus_data->enc = pj_pool_zalloc(opus_data->pool,
					opus_encoder_get_size(2));
    }
    if (!opus_data->dec) {
	/* Allocate memory for max 2 channels */
	opus_data->dec = pj_pool_zalloc(opus_data->pool,
					opus_decoder_get_size(2));
    }
    if (!opus_data->enc_packer) {
	opus_data->enc_packer = pj_pool_zalloc(opus_data->pool,
					       opus_repacketizer_get_size());
    }
    if (!opus_data->dec_packer) {
	opus_data->dec_packer = pj_pool_zalloc(opus_data->pool,
					       opus_repacketizer_get_size());
    }
    if (!opus_data->enc || !opus_data->dec ||
	!opus_data->enc_packer || !opus_data->dec_packer)
    {
	PJ_LOG(2, (THIS_FILE, "Unable to allocate memory for the codec"));
        pj_mutex_unlock (opus_data->mutex);
	return PJ_ENOMEM;
    }

    /* Check max average bit rate */
    idx = find_fmtp(&attr->setting.enc_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE);
    if (idx >= 0) {
	unsigned rate;
	rate = (unsigned)pj_strtoul(&attr->setting.enc_fmtp.param[idx].val);
	if (rate < attr->info.avg_bps)
	    attr->info.avg_bps = rate;
    }

    /* Check plc */
    idx = find_fmtp(&attr->setting.enc_fmtp, &STR_INBAND_FEC, PJ_FALSE);
    if (idx >= 0) {
	unsigned plc;
	plc = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val);
	attr->setting.plc = plc > 0? PJ_TRUE: PJ_FALSE;
    }

    /* Check vad */
    idx = find_fmtp(&attr->setting.enc_fmtp, &STR_DTX, PJ_FALSE);
    if (idx >= 0) {
	unsigned vad;
	vad = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val);
	attr->setting.vad = vad > 0? PJ_TRUE: PJ_FALSE;
    }

    /* Check cbr */
    idx = find_fmtp(&attr->setting.enc_fmtp, &STR_CBR, PJ_FALSE);
    if (idx >= 0) {
	unsigned cbr;
	cbr = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val);
	opus_data->cfg.cbr = cbr > 0? PJ_TRUE: PJ_FALSE;
    }
    
    /* Check max average bit rate */
    idx = find_fmtp(&attr->setting.dec_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE);
    if (idx >= 0) {
	unsigned rate;
	rate = (unsigned) pj_strtoul(&attr->setting.dec_fmtp.param[idx].val);
	if (rate < attr->info.avg_bps)
	    attr->info.avg_bps = rate;
    }

    TRACE_((THIS_FILE, "%s:%d: sample_rate: %u",
	    __FUNCTION__, __LINE__, opus_data->cfg.sample_rate));

    /* Initialize encoder */
    err = opus_encoder_init(opus_data->enc,
			    opus_data->cfg.sample_rate,
			    attr->info.channel_cnt,
			    OPUS_APPLICATION_VOIP);
    if (err != OPUS_OK) {
	PJ_LOG(2, (THIS_FILE, "Unable to create encoder"));
	return PJMEDIA_CODEC_EFAILED;
    }
    
    /* Set signal type */
    opus_encoder_ctl(opus_data->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
    /* Set bitrate */
    opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps));
    /* Set VAD */
    opus_encoder_ctl(opus_data->enc, OPUS_SET_DTX(attr->setting.vad ? 1 : 0));
    /* Set PLC */
    opus_encoder_ctl(opus_data->enc,
    		     OPUS_SET_INBAND_FEC(attr->setting.plc ? 1 : 0));
    /* Set bandwidth */
    opus_encoder_ctl(opus_data->enc,
    		     OPUS_SET_MAX_BANDWIDTH(get_opus_bw_constant(
    					    opus_data->cfg.sample_rate)));
    /* Set expected packet loss */
    opus_encoder_ctl(opus_data->enc,
    		OPUS_SET_PACKET_LOSS_PERC(opus_data->cfg.packet_loss));
    /* Set complexity */
    opus_encoder_ctl(opus_data->enc,
		     OPUS_SET_COMPLEXITY(opus_data->cfg.complexity));
    /* Set constant bit rate */
    opus_encoder_ctl(opus_data->enc,
    		     OPUS_SET_VBR(opus_data->cfg.cbr ? 0 : 1));

    PJ_LOG(5, (THIS_FILE, "Initialize Opus encoder, sample rate: %d, "
    			  "avg bitrate: %d, vad: %d, plc: %d, pkt loss: %d, "
    			  "complexity: %d, constant bit rate: %d",
               		  opus_data->cfg.sample_rate,
               		  attr->info.avg_bps, attr->setting.vad?1:0,
               		  attr->setting.plc?1:0,
               		  opus_data->cfg.packet_loss,
               		  opus_data->cfg.complexity,
               		  opus_data->cfg.cbr?1:0));

    /* Initialize decoder */
    err = opus_decoder_init (opus_data->dec,
			     opus_data->cfg.sample_rate,
			     attr->info.channel_cnt);
    if (err != OPUS_OK) {
	PJ_LOG(2, (THIS_FILE, "Unable to initialize decoder"));
	return PJMEDIA_CODEC_EFAILED;
    }

    /* Initialize temporary decode frames used for FEC */
    opus_data->dec_frame[0].type = PJMEDIA_FRAME_TYPE_NONE;
    opus_data->dec_frame[0].buf  = pj_pool_zalloc(opus_data->pool,                                   
        	(opus_data->cfg.sample_rate / 1000)
                * 60 * attr->info.channel_cnt * 2 /* bytes per sample */);
    opus_data->dec_frame[1].type = PJMEDIA_FRAME_TYPE_NONE;
    opus_data->dec_frame[1].buf  = pj_pool_zalloc(opus_data->pool,
		(opus_data->cfg.sample_rate / 1000)
                * 60 * attr->info.channel_cnt * 2 /* bytes per sample */);
    opus_data->dec_frame_index = -1;

    /* Initialize the repacketizers */
    opus_repacketizer_init(opus_data->enc_packer);
    opus_repacketizer_init(opus_data->dec_packer);

    pj_mutex_unlock (opus_data->mutex);
    return PJ_SUCCESS;
}