static void $UPROTO$_server_init_int($UPROTO$_server_t *userver, char *conn_str, pj_pool_t *pool) { userver->pool = pool; ansi_copy_str(userver->connect_str, conn_str); userver->is_online = 1; CHECK(__FILE__, pj_mutex_create_simple(pool, "", &userver->mutex)); if (userver->on_init_done_f != NULL){ userver->on_init_done_f(userver); } }
PJ_DEF(pj_status_t) pjmedia_codec_g711_init(pjmedia_endpt *endpt) { pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (g711_factory.endpt != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Init factory */ g711_factory.base.op = &g711_factory_op; g711_factory.base.factory_data = NULL; g711_factory.endpt = endpt; pj_list_init(&g711_factory.codec_list); /* Create pool */ g711_factory.pool = pjmedia_endpt_create_pool(endpt, "g711", 4000, 4000); if (!g711_factory.pool) return PJ_ENOMEM; /* Create mutex. */ status = pj_mutex_create_simple(g711_factory.pool, "g611", &g711_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { return PJ_EINVALIDOP; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &g711_factory.base); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; on_error: if (g711_factory.mutex) { pj_mutex_destroy(g711_factory.mutex); g711_factory.mutex = NULL; } if (g711_factory.pool) { pj_pool_release(g711_factory.pool); g711_factory.pool = NULL; } return status; }
static pj_status_t ioqueue_init_key( pj_pool_t *pool, pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *key, pj_sock_t sock, void *user_data, const pj_ioqueue_callback *cb) { pj_status_t rc; int optlen; PJ_UNUSED_ARG(pool); key->ioqueue = ioqueue; key->fd = sock; key->user_data = user_data; pj_list_init(&key->read_list); pj_list_init(&key->write_list); #if PJ_HAS_TCP pj_list_init(&key->accept_list); key->connecting = 0; #endif /* Save callback. */ pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* Set initial reference count to 1 */ pj_assert(key->ref_count == 0); ++key->ref_count; key->closing = 0; #endif rc = pj_ioqueue_set_concurrency(key, ioqueue->default_concurrency); if (rc != PJ_SUCCESS) return rc; /* Get socket type. When socket type is datagram, some optimization * will be performed during send to allow parallel send operations. */ optlen = sizeof(key->fd_type); rc = pj_sock_getsockopt(sock, pj_SOL_SOCKET(), pj_SO_TYPE(), &key->fd_type, &optlen); if (rc != PJ_SUCCESS) key->fd_type = pj_SOCK_STREAM(); /* Create mutex for the key. */ #if !PJ_IOQUEUE_HAS_SAFE_UNREG rc = pj_mutex_create_simple(pool, NULL, &key->mutex); #endif return rc; }
/* * Create the ZRTP transport. */ PJ_DEF(pj_status_t) pjmedia_transport_zrtp_create(pjmedia_endpt *endpt, const char *name, pjmedia_transport *transport, pjmedia_transport **p_tp, pj_bool_t close_slave) { pj_pool_t *pool; struct tp_zrtp *zrtp; pj_status_t rc; if (name == NULL) name = "tzrtp%p"; /* Create the pool and initialize the adapter structure */ pool = pjmedia_endpt_create_pool(endpt, name, 5*1024, 512); zrtp = PJ_POOL_ZALLOC_T(pool, struct tp_zrtp); zrtp->pool = pool; pj_ansi_strncpy(zrtp->base.name, pool->obj_name, sizeof(zrtp->base.name)); zrtp->base.type = (pjmedia_transport_type) (PJMEDIA_TRANSPORT_TYPE_USER + 2); zrtp->base.op = &tp_zrtp_op; if (timer_pool == NULL) { timer_pool = pjmedia_endpt_create_pool(endpt, "zrtp_timer", 256, 256); rc = timer_initialize(); if (rc != PJ_SUCCESS) { pj_pool_release(timer_pool); pj_pool_release(zrtp->pool); return rc; } } /* Create the empty wrapper */ zrtp->zrtpCtx = zrtp_CreateWrapper(); /* Initialize standard values */ zrtp->clientIdString = clientId; /* Set standard name */ zrtp->zrtpSeq = 1; /* TODO: randomize */ rc = pj_mutex_create_simple(zrtp->pool, "zrtp", &zrtp->zrtpMutex); zrtp->zrtpBuffer = pj_pool_zalloc(pool, MAX_ZRTP_SIZE); zrtp->sendBuffer = pj_pool_zalloc(pool, MAX_RTP_BUFFER_LEN); zrtp->slave_tp = transport; zrtp->close_slave = close_slave; /* Done */ zrtp->refcount++; *p_tp = &zrtp->base; return PJ_SUCCESS; }
/* * Initialize and register G722 codec factory to pjmedia endpoint. */ PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt ) { pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (g722_codec_factory.pool != NULL) return PJ_SUCCESS; /* Create G722 codec factory. */ g722_codec_factory.base.op = &g722_factory_op; g722_codec_factory.base.factory_data = NULL; g722_codec_factory.endpt = endpt; g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT; g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000, 1000); if (!g722_codec_factory.pool) return PJ_ENOMEM; pj_list_init(&g722_codec_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(g722_codec_factory.pool, "g722", &g722_codec_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { status = PJ_EINVALIDOP; goto on_error; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &g722_codec_factory.base); if (status != PJ_SUCCESS) goto on_error; TRACE_((THIS_FILE, "G722 codec factory initialized")); /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(g722_codec_factory.pool); g722_codec_factory.pool = NULL; return status; }
/* * Initialize and register GSM codec factory to pjmedia endpoint. */ PJ_DEF(pj_status_t) pjmedia_codec_gsm_init( pjmedia_endpt *endpt ) { pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (gsm_codec_factory.pool != NULL) return PJ_SUCCESS; /* Create GSM codec factory. */ gsm_codec_factory.base.op = &gsm_factory_op; gsm_codec_factory.base.factory_data = NULL; gsm_codec_factory.endpt = endpt; gsm_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "gsm", 4000, 4000); if (!gsm_codec_factory.pool) return PJ_ENOMEM; pj_list_init(&gsm_codec_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(gsm_codec_factory.pool, "gsm", &gsm_codec_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { status = PJ_EINVALIDOP; goto on_error; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &gsm_codec_factory.base); if (status != PJ_SUCCESS) goto on_error; /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(gsm_codec_factory.pool); gsm_codec_factory.pool = NULL; return status; }
*/PJ_DEF(pj_status_t) pjmedia_codec_vpx_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) { pj_pool_t *pool; pj_status_t status; unsigned i; PJ_LOG(4, (THIS_FILE, "Init px codec")); if (vpx_factory.pool != NULL ) { /* Already initialized. */ return PJ_SUCCESS; } if (!mgr) mgr = pjmedia_vid_codec_mgr_instance(); PJ_ASSERT_RETURN(mgr, PJ_EINVAL); /* Create VPX codec factory. */ vpx_factory.base.op = &vpx_factory_op; vpx_factory.base.factory_data = NULL; vpx_factory.mgr = mgr; vpx_factory.pf = pf; pool = pj_pool_create(pf, "vpx codec factory", 256, 256, NULL ); if (!pool) return PJ_ENOMEM; /* Create mutex. */ status = pj_mutex_create_simple(pool, "vpx codec factory", &vpx_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Register codec factory to codec manager. */ status = pjmedia_vid_codec_mgr_register_factory(mgr, &vpx_factory.base); if (status != PJ_SUCCESS) goto on_error; vpx_factory.pool = pool; /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(pool); return status; }
PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_param *param, pjmedia_aud_test_results *result) { pj_status_t status = PJ_SUCCESS; pjmedia_aud_stream *strm; struct test_data test_data; unsigned ptime, tmp; /* * Init test parameters */ pj_bzero(&test_data, sizeof(test_data)); test_data.param = param; test_data.result = result; test_data.pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "audtest", 1000, 1000, NULL); pj_mutex_create_simple(test_data.pool, "sndtest", &test_data.mutex); /* * Open device. */ status = pjmedia_aud_stream_create(test_data.param, &rec_cb, &play_cb, &test_data, &strm); if (status != PJ_SUCCESS) { app_perror("Unable to open device", status); pj_pool_release(test_data.pool); return status; } /* Sleep for a while to let sound device "settles" */ pj_thread_sleep(200); /* * Start the stream. */ status = pjmedia_aud_stream_start(strm); if (status != PJ_SUCCESS) { app_perror("Unable to start capture stream", status); pjmedia_aud_stream_destroy(strm); pj_pool_release(test_data.pool); return status; } PJ_LOG(3,(THIS_FILE, " Please wait while test is in progress (~%d secs)..", (DURATION+SKIP_DURATION)/1000)); /* Let the stream runs for few msec/sec to get stable result. * (capture normally begins with frames available simultaneously). */ pj_thread_sleep(SKIP_DURATION); /* Begin gather data */ test_data.running = 1; /* * Let the test runs for a while. */ pj_thread_sleep(DURATION); /* * Close stream. */ test_data.running = 0; pjmedia_aud_stream_destroy(strm); pj_pool_release(test_data.pool); /* * Gather results */ ptime = param->samples_per_frame * 1000 / param->clock_rate; tmp = pj_math_stat_get_stddev(&test_data.capture_data.delay); result->rec.frame_cnt = test_data.capture_data.delay.n; result->rec.min_interval = DIV_ROUND(test_data.capture_data.delay.min, 1000); result->rec.max_interval = DIV_ROUND(test_data.capture_data.delay.max, 1000); result->rec.avg_interval = DIV_ROUND(test_data.capture_data.delay.mean, 1000); result->rec.dev_interval = DIV_ROUND(tmp, 1000); result->rec.max_burst = DIV_ROUND_UP(result->rec.max_interval, ptime); tmp = pj_math_stat_get_stddev(&test_data.playback_data.delay); result->play.frame_cnt = test_data.playback_data.delay.n; result->play.min_interval = DIV_ROUND(test_data.playback_data.delay.min, 1000); result->play.max_interval = DIV_ROUND(test_data.playback_data.delay.max, 1000); result->play.avg_interval = DIV_ROUND(test_data.capture_data.delay.mean, 1000); result->play.dev_interval = DIV_ROUND(tmp, 1000); result->play.max_burst = DIV_ROUND_UP(result->play.max_interval, ptime); /* Check drifting */ if (param->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) { int end_diff, start_diff, drift; end_diff = test_data.capture_data.last_timestamp - test_data.playback_data.last_timestamp; start_diff = test_data.capture_data.first_timestamp- test_data.playback_data.first_timestamp; drift = end_diff > start_diff? end_diff - start_diff : start_diff - end_diff; /* Allow one frame tolerance for clock drift detection */ if (drift < (int)param->samples_per_frame) { result->rec_drift_per_sec = 0; } else { unsigned msec_dur; msec_dur = (test_data.capture_data.last_timestamp - test_data.capture_data.first_timestamp) * 1000 / test_data.param->clock_rate; result->rec_drift_per_sec = drift * 1000 / msec_dur; } } return test_data.has_error? PJ_EUNKNOWN : PJ_SUCCESS; }
static int timer_initialize() { pj_status_t rc; pj_mutex_t* temp_mutex; rc = pj_mutex_create_simple(timer_pool, "zrtp_timer", &temp_mutex); if (rc != PJ_SUCCESS) { return rc; } pj_enter_critical_section(); if (timer_mutex == NULL) timer_mutex = temp_mutex; else pj_mutex_destroy(temp_mutex); pj_leave_critical_section(); pj_mutex_lock(timer_mutex); if (timer_initialized) { pj_mutex_unlock(timer_mutex); return PJ_SUCCESS; } rc = pj_timer_heap_create(timer_pool, 4, &timer); if (rc != PJ_SUCCESS) { goto ERROR; } rc = pj_sem_create(timer_pool, "zrtp_timer", 0, 1, &timer_sem); if (rc != PJ_SUCCESS) { goto ERROR; } rc = pj_thread_create(timer_pool, "zrtp_timer", &timer_thread_run, NULL, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread_run); if (rc != PJ_SUCCESS) { goto ERROR; } timer_initialized = 1; pj_mutex_unlock(timer_mutex); return PJ_SUCCESS; ERROR: if (timer != NULL) { pj_timer_heap_destroy(timer); timer = NULL; } if (timer_sem != NULL) { pj_sem_destroy(timer_sem); timer_sem = NULL; } if (timer_mutex != NULL) { pj_mutex_unlock(timer_mutex); pj_mutex_destroy(timer_mutex); timer_mutex = NULL; } return rc; }
/* * pj_ioqueue_create() * * Create select ioqueue. */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; pj_status_t rc; pj_lock_t *lock; int i; /* Check that arguments are valid. */ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && max_fd > 0, PJ_EINVAL); /* Check that size of pj_ioqueue_op_key_t is sufficient */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); ioqueue_init(ioqueue); ioqueue->max = max_fd; ioqueue->count = 0; pj_list_init(&ioqueue->active_list); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* When safe unregistration is used (the default), we pre-create * all keys and put them in the free list. */ /* Mutex to protect key's reference counter * We don't want to use key's mutex or ioqueue's mutex because * that would create deadlock situation in some cases. */ rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex); if (rc != PJ_SUCCESS) return rc; /* Init key list */ pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Pre-create all keys according to max_fd */ for ( i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t); key->ref_count = 0; rc = pj_lock_create_recursive_mutex(pool, NULL, &key->lock); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_lock_destroy(key->lock); key = key->next; } pj_mutex_destroy(ioqueue->ref_cnt_mutex); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock); if (rc != PJ_SUCCESS) return rc; rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE); if (rc != PJ_SUCCESS) return rc; ioqueue->epfd = os_epoll_create(max_fd); if (ioqueue->epfd < 0) { ioqueue_destroy(ioqueue); return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); } /*ioqueue->events = pj_pool_calloc(pool, max_fd, sizeof(struct epoll_event)); PJ_ASSERT_RETURN(ioqueue->events != NULL, PJ_ENOMEM); ioqueue->queue = pj_pool_calloc(pool, max_fd, sizeof(struct queue)); PJ_ASSERT_RETURN(ioqueue->queue != NULL, PJ_ENOMEM); */ PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue)); *p_ioqueue = ioqueue; return PJ_SUCCESS; }
/* * pj_thread_create(...) */ PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name, pj_thread_proc *proc, void *arg, pj_size_t stack_size, unsigned flags, pj_thread_t **ptr_thread) { #if PJ_HAS_THREADS pj_thread_t *rec; pthread_attr_t thread_attr; void *stack_addr; int rc; PJ_UNUSED_ARG(stack_addr); PJ_CHECK_STACK(); PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); /* Create thread record and assign name for the thread */ rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t)); PJ_ASSERT_RETURN(rec, PJ_ENOMEM); /* Set name. */ if (!thread_name) thread_name = "thr%p"; if (strchr(thread_name, '%')) { pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); } else { strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; } /* Set default stack size */ if (stack_size == 0) stack_size = PJ_THREAD_DEFAULT_STACK_SIZE; #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_size = stack_size; rec->stk_max_usage = 0; #endif /* Emulate suspended thread with mutex. */ if (flags & PJ_THREAD_SUSPENDED) { rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex); if (rc != PJ_SUCCESS) { return rc; } pj_mutex_lock(rec->suspended_mutex); } else { pj_assert(rec->suspended_mutex == NULL); } /* Init thread attributes */ pthread_attr_init(&thread_attr); #if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0 /* Set thread's stack size */ rc = pthread_attr_setstacksize(&thread_attr, stack_size); if (rc != 0) return PJ_RETURN_OS_ERROR(rc); #endif /* PJ_THREAD_SET_STACK_SIZE */ #if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0 /* Allocate memory for the stack */ stack_addr = pj_pool_alloc(pool, stack_size); PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM); rc = pthread_attr_setstackaddr(&thread_attr, stack_addr); if (rc != 0) return PJ_RETURN_OS_ERROR(rc); #endif /* PJ_THREAD_ALLOCATE_STACK */ /* Create the thread. */ rec->proc = proc; rec->arg = arg; rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec); if (rc != 0) { return PJ_RETURN_OS_ERROR(rc); } *ptr_thread = rec; PJ_LOG(6, (rec->obj_name, "Thread created")); return PJ_SUCCESS; #else pj_assert(!"Threading is disabled!"); return PJ_EINVALIDOP; #endif }
/* API: Initialize the audio subsystem. */ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf) { unsigned i; pj_status_t status; /* Allow init() to be called multiple times as long as there is matching * number of shutdown(). */ if (aud_subsys.init_count++ != 0) { return PJ_SUCCESS; } /* Register error subsystem */ status = pj_register_strerror(PJMEDIA_AUDIODEV_ERRNO_START, PJ_ERRNO_SPACE_SIZE, &pjmedia_audiodev_strerror); pj_assert(status == PJ_SUCCESS); /* Init */ aud_subsys.pf = pf; aud_subsys.drv_cnt = 0; aud_subsys.dev_cnt = 0; /* Register creation functions */ #if PJMEDIA_AUDIO_DEV_HAS_OPENSL aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_opensl_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_ANDROID_JNI aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_android_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_BB10 aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_ALSA aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_WMME aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_BDIMAD aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bdimad_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory; #endif #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory; #endif /* Initialize audio device observer objects */ pj_status_t st; aud_subsys.dev_observer.pool = pj_pool_create(pf, "aud_dev_observer_pool", 512, 512, NULL); if (!aud_subsys.dev_observer.pool) { return PJ_ENOMEM; } st = pj_mutex_create_simple(aud_subsys.dev_observer.pool, "aud_dev_observer_lock", &aud_subsys.dev_observer.lock); if (st != PJ_SUCCESS) { return st; } aud_subsys.dev_observer.cb = NULL; /* Initialize each factory and build the device ID list */ for (i=0; i<aud_subsys.drv_cnt; ++i) { status = init_driver(i, PJ_FALSE); if (status != PJ_SUCCESS) { deinit_driver(i); continue; } } return aud_subsys.dev_cnt ? PJ_SUCCESS : status; }
/* * Initialize and register openh264 codec factory to pjmedia endpoint. */ PJ_DEF(pj_status_t) pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) { pj_pool_t *pool; pj_status_t status; openh264_codec_desc *desc = &codec_desc[0]; if (openh264_factory.pool != NULL) { /* Already initialized. */ return PJ_SUCCESS; } if (!mgr) mgr = pjmedia_vid_codec_mgr_instance(); PJ_ASSERT_RETURN(mgr, PJ_EINVAL); /* Create openh264 codec factory. */ openh264_factory.base.op = &openh264_factory_op; openh264_factory.base.factory_data = NULL; openh264_factory.mgr = mgr; openh264_factory.pf = pf; pool = pj_pool_create(pf, "openh264 codec factory", 256, 256, NULL); if (!pool) return PJ_ENOMEM; /* Create mutex. */ status = pj_mutex_create_simple(pool, "openh264 codec factory", &openh264_factory.mutex); if (status != PJ_SUCCESS) goto on_error; desc->info.dec_fmt_id[0] = PJMEDIA_FORMAT_I420; desc->info.dec_fmt_id_cnt = 1; desc->info.dir |= PJMEDIA_DIR_ENCODING; desc->info.dir |= PJMEDIA_DIR_DECODING; desc->enabled = PJ_TRUE; if (desc->info.clock_rate == 0) desc->info.clock_rate = 90000; desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE; if (desc->packetize && desc->unpacketize) desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS; /* Registering format match for SDP negotiation */ if (desc->sdp_fmt_match) { status = pjmedia_sdp_neg_register_fmt_match_cb( &desc->info.encoding_name, desc->sdp_fmt_match); pj_assert(status == PJ_SUCCESS); } /* Register codec factory to codec manager. */ status = pjmedia_vid_codec_mgr_register_factory(mgr, &openh264_factory.base); if (status != PJ_SUCCESS) goto on_error; openh264_factory.pool = pool; /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(pool); return status; }
PJ_DEF(pj_status_t) pjmedia_natnl_stream_create(pj_pool_t *pool, pjsua_call *call, pjmedia_stream_info *si, natnl_stream **stream) { pj_status_t status = PJ_SUCCESS; unsigned strm_idx = 0; strm_idx = call->index; /* TODO: * - Create and start your media stream based on the parameters * in si */ PJ_ASSERT_RETURN(pool, PJ_EINVAL); PJ_LOG(4,(THIS_FILE,"natnl audio channel update..strm_idx=%d", strm_idx)); /* Check if no media is active */ if (si->dir != PJMEDIA_DIR_NONE) { /* Create session based on session info. */ #if 0 pool = pj_pool_create(strm_pool->factory, "strm%p", NATNL_STREAM_SIZE, NATNL_STREAM_INC, NULL); PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); #endif pj_mutex_lock(call->tnl_stream_lock); pj_mutex_lock(call->tnl_stream_lock2); pj_mutex_lock(call->tnl_stream_lock3); // DEAN don't re-create natnl stream if (call->tnl_stream) { *stream = call->tnl_stream; pj_mutex_unlock(call->tnl_stream_lock3); pj_mutex_unlock(call->tnl_stream_lock2); pj_mutex_unlock(call->tnl_stream_lock); return PJ_SUCCESS; } call->tnl_stream = *stream = PJ_POOL_ZALLOC_T(pool, natnl_stream); PJ_ASSERT_RETURN(*stream != NULL, PJ_ENOMEM); (*stream)->call = call; (*stream)->own_pool = pool; (*stream)->med_tp = call->med_tp; pj_memcpy(&(*stream)->rem_addr, &si->rem_addr, sizeof(pj_sockaddr)); pj_list_init(&(*stream)->rbuff); pj_list_init(&(*stream)->gcbuff); pj_get_timestamp(&(*stream)->last_data_or_ka); pj_get_timestamp(&(*stream)->last_data); (*stream)->rbuff_cnt = 0; (*stream)->rx_band = (pj_band_t *)malloc(sizeof(pj_band_t)); (*stream)->tx_band = (pj_band_t *)malloc(sizeof(pj_band_t)); pj_memset((*stream)->rx_band, 0, sizeof(pj_band_t)); pj_memset((*stream)->tx_band, 0, sizeof(pj_band_t)); pj_bandwidthSetLimited((*stream)->rx_band, PJ_FALSE); pj_bandwidthSetLimited((*stream)->tx_band, PJ_FALSE); /* Create mutex to protect jitter buffer: */ status = pj_mutex_create_simple(pool, NULL, &(*stream)->rbuff_mutex); if (status != PJ_SUCCESS) { //pj_pool_t *tmp_pool = (*stream)->own_pool; (*stream)->own_pool = NULL; //pj_pool_release(tmp_pool); goto on_return; } status = pj_mutex_create_simple(pool, NULL, &(*stream)->gcbuff_mutex); if (status != PJ_SUCCESS) { (*stream)->own_pool = NULL; goto on_return; } /* Create semaphore */ status = pj_sem_create(pool, "client", 0, 65535, &(*stream)->rbuff_sem); if (status != PJ_SUCCESS) { (*stream)->own_pool = NULL; goto on_return; } // +Roger - Create Send buffer Mutex status = pj_mutex_create_simple(pool, NULL, &(*stream)->sbuff_mutex); if (status != PJ_SUCCESS) { //pj_pool_t *tmp_pool = (*stream)->own_pool; (*stream)->own_pool = NULL; //pj_pool_release(tmp_pool); goto on_return; } //------------------------------------// #if 0 /* Attach our RTP and RTCP callbacks to the media transport */ status = pjmedia_transport_attach(call_med->tp, stream, //call_med, &si->rem_addr, &si->rem_rtcp, pj_sockaddr_get_len(&si->rem_addr), &aud_rtp_cb, &aud_rtcp_cb); #endif } on_return: pj_mutex_unlock(call->tnl_stream_lock3); pj_mutex_unlock(call->tnl_stream_lock2); pj_mutex_unlock(call->tnl_stream_lock); return status; }
/* * pj_ioqueue_create() * * Create select ioqueue. */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; pj_lock_t *lock; unsigned i; pj_status_t rc; /* Check that arguments are valid. */ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, PJ_EINVAL); /* Check that size of pj_ioqueue_op_key_t is sufficient */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); /* Create and init common ioqueue stuffs */ ioqueue = PJ_POOL_ALLOC_T(pool, pj_ioqueue_t); ioqueue_init(ioqueue); ioqueue->max = max_fd; ioqueue->count = 0; PJ_FD_ZERO(&ioqueue->rfdset); PJ_FD_ZERO(&ioqueue->wfdset); #if PJ_HAS_TCP PJ_FD_ZERO(&ioqueue->xfdset); #endif pj_list_init(&ioqueue->active_list); rescan_fdset(ioqueue); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* When safe unregistration is used (the default), we pre-create * all keys and put them in the free list. */ /* Mutex to protect key's reference counter * We don't want to use key's mutex or ioqueue's mutex because * that would create deadlock situation in some cases. */ rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex); if (rc != PJ_SUCCESS) return rc; /* Init key list */ pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Pre-create all keys according to max_fd */ for (i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t); key->ref_count = 0; rc = pj_mutex_create_recursive(pool, NULL, &key->mutex); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_mutex_destroy(key->mutex); key = key->next; } pj_mutex_destroy(ioqueue->ref_cnt_mutex); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif /* Create and init ioqueue mutex */ rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock); if (rc != PJ_SUCCESS) return rc; rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE); if (rc != PJ_SUCCESS) return rc; PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue)); *p_ioqueue = ioqueue; return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool, const pjmedia_vid_port_param *prm, pjmedia_vid_port **p_vid_port) { pjmedia_vid_port *vp; const pjmedia_video_format_detail *vfd; char dev_name[64]; char fmt_name[5]; pjmedia_vid_dev_cb vid_cb; pj_bool_t need_frame_buf = PJ_FALSE; pj_status_t status; unsigned ptime_usec; pjmedia_vid_dev_param vparam; pjmedia_vid_dev_info di; unsigned i; PJ_ASSERT_RETURN(pool && prm && p_vid_port, PJ_EINVAL); PJ_ASSERT_RETURN(prm->vidparam.fmt.type == PJMEDIA_TYPE_VIDEO && prm->vidparam.dir != PJMEDIA_DIR_NONE && prm->vidparam.dir != PJMEDIA_DIR_CAPTURE_RENDER, PJ_EINVAL); /* Retrieve the video format detail */ vfd = pjmedia_format_get_video_format_detail(&prm->vidparam.fmt, PJ_TRUE); if (!vfd) return PJ_EINVAL; PJ_ASSERT_RETURN(vfd->fps.num, PJ_EINVAL); /* Allocate videoport */ vp = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_port); vp->pool = pj_pool_create(pool->factory, "video port", 500, 500, NULL); vp->role = prm->active ? ROLE_ACTIVE : ROLE_PASSIVE; vp->dir = prm->vidparam.dir; // vp->cap_size = vfd->size; vparam = prm->vidparam; dev_name[0] = '\0'; /* Get device info */ if (vp->dir & PJMEDIA_DIR_CAPTURE) status = pjmedia_vid_dev_get_info(prm->vidparam.cap_id, &di); else status = pjmedia_vid_dev_get_info(prm->vidparam.rend_id, &di); if (status != PJ_SUCCESS) return status; pj_ansi_snprintf(dev_name, sizeof(dev_name), "%s [%s]", di.name, di.driver); for (i = 0; i < di.fmt_cnt; ++i) { if (prm->vidparam.fmt.id == di.fmt[i].id) break; } if (i == di.fmt_cnt) { /* The device has no no matching format. Pick one from * the supported formats, and later use converter to * convert it to the required format. */ pj_assert(di.fmt_cnt != 0); vparam.fmt.id = di.fmt[0].id; } pj_strdup2_with_null(pool, &vp->dev_name, di.name); vp->stream_role = di.has_callback ? ROLE_ACTIVE : ROLE_PASSIVE; pjmedia_fourcc_name(vparam.fmt.id, fmt_name); PJ_LOG(4,(THIS_FILE, "Opening device %s for %s: format=%s, size=%dx%d @%d:%d fps", dev_name, vid_dir_name(prm->vidparam.dir), fmt_name, vfd->size.w, vfd->size.h, vfd->fps.num, vfd->fps.denum)); ptime_usec = PJMEDIA_PTIME(&vfd->fps); pjmedia_clock_src_init(&vp->clocksrc, PJMEDIA_TYPE_VIDEO, prm->vidparam.clock_rate, ptime_usec); vp->sync_clocksrc.max_sync_ticks = PJMEDIA_CLOCK_SYNC_MAX_RESYNC_DURATION * 1000 / vp->clocksrc.ptime_usec; /* Create the video stream */ pj_bzero(&vid_cb, sizeof(vid_cb)); vid_cb.capture_cb = &vidstream_cap_cb; vid_cb.render_cb = &vidstream_render_cb; status = pjmedia_vid_dev_stream_create(&vparam, &vid_cb, vp, &vp->strm); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4,(THIS_FILE, "Device %s opened: format=%s, size=%dx%d @%d:%d fps", dev_name, fmt_name, vparam.fmt.det.vid.size.w, vparam.fmt.det.vid.size.h, vparam.fmt.det.vid.fps.num, vparam.fmt.det.vid.fps.denum)); /* Subscribe to device's events */ pjmedia_event_subscribe(NULL, &vidstream_event_cb, vp, vp->strm); if (vp->dir & PJMEDIA_DIR_CAPTURE) { pjmedia_format_copy(&vp->conv.conv_param.src, &vparam.fmt); pjmedia_format_copy(&vp->conv.conv_param.dst, &prm->vidparam.fmt); } else { pjmedia_format_copy(&vp->conv.conv_param.src, &prm->vidparam.fmt); pjmedia_format_copy(&vp->conv.conv_param.dst, &vparam.fmt); } status = create_converter(vp); if (status != PJ_SUCCESS) goto on_error; if (vp->role==ROLE_ACTIVE && ((vp->dir & PJMEDIA_DIR_ENCODING) || vp->stream_role==ROLE_PASSIVE)) { pjmedia_clock_param param; /* Active role is wanted, but our device is passive, so create * master clocks to run the media flow. For encoding direction, * we also want to create our own clock since the device's clock * may run at a different rate. */ need_frame_buf = PJ_TRUE; param.usec_interval = PJMEDIA_PTIME(&vfd->fps); param.clock_rate = prm->vidparam.clock_rate; status = pjmedia_clock_create2(pool, ¶m, PJMEDIA_CLOCK_NO_HIGHEST_PRIO, (vp->dir & PJMEDIA_DIR_ENCODING) ? &enc_clock_cb: &dec_clock_cb, vp, &vp->clock); if (status != PJ_SUCCESS) goto on_error; } else if (vp->role==ROLE_PASSIVE) { vid_pasv_port *pp; /* Always need to create media port for passive role */ vp->pasv_port = pp = PJ_POOL_ZALLOC_T(pool, vid_pasv_port); pp->vp = vp; pp->base.get_frame = &vid_pasv_port_get_frame; pp->base.put_frame = &vid_pasv_port_put_frame; pjmedia_port_info_init2(&pp->base.info, &vp->dev_name, PJMEDIA_SIG_VID_PORT, prm->vidparam.dir, &prm->vidparam.fmt); need_frame_buf = PJ_TRUE; } if (need_frame_buf) { const pjmedia_video_format_info *vfi; pjmedia_video_apply_fmt_param vafp; vfi = pjmedia_get_video_format_info(NULL, vparam.fmt.id); if (!vfi) { status = PJ_ENOTFOUND; goto on_error; } pj_bzero(&vafp, sizeof(vafp)); vafp.size = vparam.fmt.det.vid.size; status = vfi->apply_fmt(vfi, &vafp); if (status != PJ_SUCCESS) goto on_error; vp->frm_buf = PJ_POOL_ZALLOC_T(pool, pjmedia_frame); vp->frm_buf_size = vafp.framebytes; vp->frm_buf->buf = pj_pool_alloc(pool, vafp.framebytes); vp->frm_buf->size = vp->frm_buf_size; vp->frm_buf->type = PJMEDIA_FRAME_TYPE_NONE; status = pj_mutex_create_simple(pool, vp->dev_name.ptr, &vp->frm_mutex); if (status != PJ_SUCCESS) goto on_error; } *p_vid_port = vp; return PJ_SUCCESS; on_error: pjmedia_vid_port_destroy(vp); return status; }
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt) { pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (silk_factory.endpt != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Init factory */ silk_factory.base.op = &silk_factory_op; silk_factory.base.factory_data = NULL; silk_factory.endpt = endpt; /* Create pool */ silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk codecs", 4000, 4000); if (!silk_factory.pool) return PJ_ENOMEM; /* Init list */ pj_list_init(&silk_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(silk_factory.pool, "silk codecs", &silk_factory.mutex); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(5, (THIS_FILE, "Init silk")); /* Table from silk docs | fs (Hz) | BR (kbps) ----------------+---------+---------- Narrowband | 8000 | 5 - 20 Mediumband | 12000 | 7 - 25 Wideband | 16000 | 8 - 30 Super Wideband | 24000 | 20 - 40 */ // The max_bitrate is based on the maximum bitrate that can be used for the encoder. // BTW, if a remote side send us something very big, we will not get lost. // If such a remote side send us big packets it could be considered unefficient. // On our side we set for bitrate the medium value of bitrate for each clock rate based // on table above. struct silk_param *silk_param; silk_param = &silk_factory.silk_param[PARAM_NB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_NB; silk_param->clock_rate = 8000; silk_param->bitrate = 13000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_MB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_MB; silk_param->clock_rate = 12000; silk_param->bitrate = 16000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_WB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_WB; silk_param->clock_rate = 16000; silk_param->bitrate = 19000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; silk_param = &silk_factory.silk_param[PARAM_UWB]; silk_param->pt = PJMEDIA_RTP_PT_SILK_UWB; silk_param->clock_rate = 24000; silk_param->bitrate = 30000; pj_utoa(silk_param->bitrate, silk_param->bitrate_str); silk_param->max_bitrate = SILK_MAX_CODER_BITRATE; silk_param->packet_size_ms = FRAME_LENGTH_MS; silk_param->complexity = 2; silk_param->enabled = 1; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { return PJ_EINVALIDOP; } PJ_LOG(5, (THIS_FILE, "Init silk > DONE")); /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &silk_factory.base); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; on_error: if (silk_factory.mutex) { pj_mutex_destroy(silk_factory.mutex); silk_factory.mutex = NULL; } if (silk_factory.pool) { pj_pool_release(silk_factory.pool); silk_factory.pool = NULL; } return status; }
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt) { pjmedia_codec_mgr *codec_mgr; silk_param *sp; pj_status_t status; if (silk_factory.endpt != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Init factory */ pj_bzero(&silk_factory, sizeof(silk_factory)); silk_factory.base.op = &silk_factory_op; silk_factory.base.factory_data = NULL; silk_factory.endpt = endpt; /* Create pool */ silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk", 4000, 4000); if (!silk_factory.pool) return PJ_ENOMEM; /* Create mutex. */ status = pj_mutex_create_simple(silk_factory.pool, "silk", &silk_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Initialize default codec params */ /* From SILK docs: - SILK bitrate tables: +----------------+---------+-----------+ | | fs (Hz) | BR (kbps) | +----------------+---------+-----------+ | Narrowband | 8000 | 6 - 20 | | Mediumband | 12000 | 7 - 25 | | Wideband | 16000 | 8 - 30 | | Super Wideband | 24000 | 12 - 40 | +----------------+---------+-----------+ - The upper limits of the bit rate ranges in this table are recommended values. */ sp = &silk_factory.silk_param[PARAM_NB]; sp->pt = PJMEDIA_RTP_PT_SILK_NB; sp->clock_rate = 8000; sp->max_bitrate = 22000; sp->bitrate = CALC_BITRATE(sp->max_bitrate); sp->ptime = FRAME_LENGTH_MS; sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY; sp->enabled = 1; sp = &silk_factory.silk_param[PARAM_MB]; sp->pt = PJMEDIA_RTP_PT_SILK_MB; sp->clock_rate = 12000; sp->max_bitrate = 28000; sp->bitrate = CALC_BITRATE(sp->max_bitrate); sp->ptime = FRAME_LENGTH_MS; sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY; sp->enabled = 0; sp = &silk_factory.silk_param[PARAM_WB]; sp->pt = PJMEDIA_RTP_PT_SILK_WB; sp->clock_rate = 16000; sp->max_bitrate = 36000; sp->bitrate = CALC_BITRATE(sp->max_bitrate); sp->ptime = FRAME_LENGTH_MS; sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY; sp->enabled = 1; sp = &silk_factory.silk_param[PARAM_SWB]; sp->pt = PJMEDIA_RTP_PT_SILK_SWB; sp->clock_rate = 24000; sp->max_bitrate = 46000; sp->bitrate = CALC_BITRATE(sp->max_bitrate); sp->ptime = FRAME_LENGTH_MS; sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY; sp->enabled = 0; /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { return PJ_EINVALIDOP; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &silk_factory.base); if (status != PJ_SUCCESS) return status; PJ_LOG(4,(THIS_FILE, "SILK codec version %s initialized", SKP_Silk_SDK_get_version())); return PJ_SUCCESS; on_error: if (silk_factory.mutex) { pj_mutex_destroy(silk_factory.mutex); silk_factory.mutex = NULL; } if (silk_factory.pool) { pj_pool_release(silk_factory.pool); silk_factory.pool = NULL; } return status; }
/* * Perform unregistration test. * * This will create ioqueue and register a server socket. Depending * on the test method, either the callback or the main thread will * unregister and destroy the server socket after some period of time. */ static int perform_unreg_test(pj_ioqueue_t *ioqueue, pj_pool_t *test_pool, const char *title, pj_bool_t other_socket) { enum { WORKER_CNT = 1, MSEC = 500, QUIT_MSEC = 500 }; int i; pj_thread_t *thread[WORKER_CNT]; struct sock_data osd; pj_ioqueue_callback callback; pj_time_val end_time; pj_status_t status; /* Sometimes its important to have other sockets registered to * the ioqueue, because when no sockets are registered, the ioqueue * will return from the poll early. */ if (other_socket) { status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, 56127, &osd.sock); if (status != PJ_SUCCESS) { app_perror("Error creating other socket", status); return -12; } pj_bzero(&callback, sizeof(callback)); status = pj_ioqueue_register_sock(test_pool, ioqueue, osd.sock, NULL, &callback, &osd.key); if (status != PJ_SUCCESS) { app_perror("Error registering other socket", status); return -13; } } else { osd.key = NULL; osd.sock = PJ_INVALID_SOCKET; } /* Init both time duration of testing */ thread_quitting = 0; pj_gettimeofday(&time_to_unregister); time_to_unregister.msec += MSEC; pj_time_val_normalize(&time_to_unregister); end_time = time_to_unregister; end_time.msec += QUIT_MSEC; pj_time_val_normalize(&end_time); /* Create polling thread */ for (i=0; i<WORKER_CNT; ++i) { status = pj_thread_create(test_pool, "unregtest", &worker_thread, ioqueue, 0, 0, &thread[i]); if (status != PJ_SUCCESS) { app_perror("Error creating thread", status); return -20; } } /* Create pair of client/server sockets */ status = app_socketpair(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock_data.sock, &sock_data.csock); if (status != PJ_SUCCESS) { app_perror("app_socketpair error", status); return -30; } /* Initialize test data */ sock_data.pool = pj_pool_create(mem, "sd", 1000, 1000, NULL); sock_data.buffer = (char*) pj_pool_alloc(sock_data.pool, 128); sock_data.bufsize = 128; sock_data.op_key = (pj_ioqueue_op_key_t*) pj_pool_alloc(sock_data.pool, sizeof(*sock_data.op_key)); sock_data.received = 0; sock_data.unregistered = 0; pj_ioqueue_op_key_init(sock_data.op_key, sizeof(*sock_data.op_key)); status = pj_mutex_create_simple(sock_data.pool, "sd", &sock_data.mutex); if (status != PJ_SUCCESS) { app_perror("create_mutex() error", status); return -35; } /* Register socket to ioqueue */ pj_bzero(&callback, sizeof(callback)); callback.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(sock_data.pool, ioqueue, sock_data.sock, NULL, &callback, &sock_data.key); if (status != PJ_SUCCESS) { app_perror("pj_ioqueue_register error", status); return -40; } /* Bootstrap the first send/receive */ on_read_complete(sock_data.key, sock_data.op_key, 0); /* Loop until test time ends */ for (;;) { pj_time_val now, timeout; pj_gettimeofday(&now); if (test_method == UNREGISTER_IN_APP && PJ_TIME_VAL_GTE(now, time_to_unregister) && sock_data.pool) { pj_mutex_lock(sock_data.mutex); sock_data.unregistered = 1; pj_ioqueue_unregister(sock_data.key); pj_mutex_unlock(sock_data.mutex); pj_mutex_destroy(sock_data.mutex); pj_pool_release(sock_data.pool); sock_data.pool = NULL; } if (PJ_TIME_VAL_GT(now, end_time) && sock_data.unregistered) break; timeout.sec = 0; timeout.msec = 10; pj_ioqueue_poll(ioqueue, &timeout); //pj_thread_sleep(1); } thread_quitting = 1; for (i=0; i<WORKER_CNT; ++i) { pj_thread_join(thread[i]); pj_thread_destroy(thread[i]); } if (other_socket) { pj_ioqueue_unregister(osd.key); } pj_sock_close(sock_data.csock); PJ_LOG(3,(THIS_FILE, "....%s: done (%d KB/s)", title, sock_data.received * 1000 / MSEC / 1000)); return 0; }
/* * Initialize and register Speex codec factory to pjmedia endpoint. */ PJ_DEF(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt, unsigned options, int quality, int complexity ) { pjmedia_codec_mgr *codec_mgr; unsigned i; pj_status_t status; if (spx_factory.pool != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Get defaults */ if (quality < 0) quality = PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY; if (complexity < 0) complexity = PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY; /* Validate quality & complexity */ PJ_ASSERT_RETURN(quality >= 0 && quality <= 10, PJ_EINVAL); PJ_ASSERT_RETURN(complexity >= 1 && complexity <= 10, PJ_EINVAL); /* Create Speex codec factory. */ spx_factory.base.op = &spx_factory_op; spx_factory.base.factory_data = NULL; spx_factory.endpt = endpt; spx_factory.pool = pjmedia_endpt_create_pool(endpt, "speex", 4000, 4000); if (!spx_factory.pool) return PJ_ENOMEM; pj_list_init(&spx_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(spx_factory.pool, "speex", &spx_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Initialize default Speex parameter. */ spx_factory.speex_param[PARAM_NB].enabled = ((options & PJMEDIA_SPEEX_NO_NB) == 0); spx_factory.speex_param[PARAM_NB].pt = PJMEDIA_RTP_PT_SPEEX_NB; spx_factory.speex_param[PARAM_NB].mode = speex_lib_get_mode(SPEEX_MODEID_NB); spx_factory.speex_param[PARAM_NB].clock_rate = 8000; spx_factory.speex_param[PARAM_NB].quality = quality; spx_factory.speex_param[PARAM_NB].complexity = complexity; spx_factory.speex_param[PARAM_WB].enabled = ((options & PJMEDIA_SPEEX_NO_WB) == 0); spx_factory.speex_param[PARAM_WB].pt = PJMEDIA_RTP_PT_SPEEX_WB; spx_factory.speex_param[PARAM_WB].mode = speex_lib_get_mode(SPEEX_MODEID_WB); spx_factory.speex_param[PARAM_WB].clock_rate = 16000; spx_factory.speex_param[PARAM_WB].quality = quality; spx_factory.speex_param[PARAM_WB].complexity = complexity; spx_factory.speex_param[PARAM_UWB].enabled = ((options & PJMEDIA_SPEEX_NO_UWB) == 0); spx_factory.speex_param[PARAM_UWB].pt = PJMEDIA_RTP_PT_SPEEX_UWB; spx_factory.speex_param[PARAM_UWB].mode = speex_lib_get_mode(SPEEX_MODEID_UWB); spx_factory.speex_param[PARAM_UWB].clock_rate = 32000; spx_factory.speex_param[PARAM_UWB].quality = quality; spx_factory.speex_param[PARAM_UWB].complexity = complexity; /* Somehow quality <=4 is broken in linux. */ if (quality <= 4 && quality >= 0) { PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb")); spx_factory.speex_param[PARAM_UWB].quality = 5; } /* Get codec framesize and avg bitrate for each mode. */ for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) { status = get_speex_info(&spx_factory.speex_param[i]); } /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { status = PJ_EINVALIDOP; goto on_error; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &spx_factory.base); if (status != PJ_SUCCESS) goto on_error; /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(spx_factory.pool); spx_factory.pool = NULL; return status; }
/* * Initialize and register FFMPEG codec factory to pjmedia endpoint. */ PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr, pj_pool_factory *pf) { pj_pool_t *pool; AVCodec *c; pj_status_t status; unsigned i; if (ffmpeg_factory.pool != NULL) { /* Already initialized. */ return PJ_SUCCESS; } if (!mgr) mgr = pjmedia_vid_codec_mgr_instance(); PJ_ASSERT_RETURN(mgr, PJ_EINVAL); /* Create FFMPEG codec factory. */ ffmpeg_factory.base.op = &ffmpeg_factory_op; ffmpeg_factory.base.factory_data = NULL; ffmpeg_factory.mgr = mgr; ffmpeg_factory.pf = pf; pool = pj_pool_create(pf, "ffmpeg codec factory", 256, 256, NULL); if (!pool) return PJ_ENOMEM; /* Create mutex. */ status = pj_mutex_create_simple(pool, "ffmpeg codec factory", &ffmpeg_factory.mutex); if (status != PJ_SUCCESS) goto on_error; avcodec_init(); avcodec_register_all(); av_log_set_level(AV_LOG_ERROR); /* Enum FFMPEG codecs */ for (c=av_codec_next(NULL); c; c=av_codec_next(c)) { ffmpeg_codec_desc *desc; pjmedia_format_id fmt_id; int codec_info_idx; #if LIBAVCODEC_VERSION_MAJOR <= 52 # define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO #endif if (c->type != AVMEDIA_TYPE_VIDEO) continue; /* Video encoder and decoder are usually implemented in separate * AVCodec instances. While the codec attributes (e.g: raw formats, * supported fps) are in the encoder. */ //PJ_LOG(3, (THIS_FILE, "%s", c->name)); status = CodecID_to_pjmedia_format_id(c->id, &fmt_id); /* Skip if format ID is unknown */ if (status != PJ_SUCCESS) continue; codec_info_idx = find_codec_idx_by_fmt_id(fmt_id); /* Skip if codec is unwanted by this wrapper (not listed in * the codec info array) */ if (codec_info_idx < 0) continue; desc = &codec_desc[codec_info_idx]; /* Skip duplicated codec implementation */ if ((c->encode && (desc->info.dir & PJMEDIA_DIR_ENCODING)) || (c->decode && (desc->info.dir & PJMEDIA_DIR_DECODING))) { continue; } /* Get raw/decoded format ids in the encoder */ if (c->pix_fmts && c->encode) { pjmedia_format_id raw_fmt[PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT]; unsigned raw_fmt_cnt = 0; unsigned raw_fmt_cnt_should_be = 0; const enum PixelFormat *p = c->pix_fmts; for(;(p && *p != -1) && (raw_fmt_cnt < PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT); ++p) { pjmedia_format_id fmt_id; raw_fmt_cnt_should_be++; status = PixelFormat_to_pjmedia_format_id(*p, &fmt_id); if (status != PJ_SUCCESS) { PJ_LOG(6, (THIS_FILE, "Unrecognized ffmpeg pixel " "format %d", *p)); continue; } //raw_fmt[raw_fmt_cnt++] = fmt_id; /* Disable some formats due to H.264 error: * x264 [error]: baseline profile doesn't support 4:4:4 */ if (desc->info.pt != PJMEDIA_RTP_PT_H264 || fmt_id != PJMEDIA_FORMAT_RGB24) { raw_fmt[raw_fmt_cnt++] = fmt_id; } } if (raw_fmt_cnt == 0) { PJ_LOG(5, (THIS_FILE, "No recognized raw format " "for codec [%s/%s], codec ignored", c->name, c->long_name)); /* Skip this encoder */ continue; } if (raw_fmt_cnt < raw_fmt_cnt_should_be) { PJ_LOG(6, (THIS_FILE, "Codec [%s/%s] have %d raw formats, " "recognized only %d raw formats", c->name, c->long_name, raw_fmt_cnt_should_be, raw_fmt_cnt)); } desc->info.dec_fmt_id_cnt = raw_fmt_cnt; pj_memcpy(desc->info.dec_fmt_id, raw_fmt, sizeof(raw_fmt[0])*raw_fmt_cnt); } /* Get supported framerates */ if (c->supported_framerates) { const AVRational *fr = c->supported_framerates; while ((fr->num != 0 || fr->den != 0) && desc->info.fps_cnt < PJMEDIA_VID_CODEC_MAX_FPS_CNT) { desc->info.fps[desc->info.fps_cnt].num = fr->num; desc->info.fps[desc->info.fps_cnt].denum = fr->den; ++desc->info.fps_cnt; ++fr; } } /* Get ffmpeg encoder instance */ if (c->encode && !desc->enc) { desc->info.dir |= PJMEDIA_DIR_ENCODING; desc->enc = c; } /* Get ffmpeg decoder instance */ if (c->decode && !desc->dec) { desc->info.dir |= PJMEDIA_DIR_DECODING; desc->dec = c; } /* Enable this codec when any ffmpeg codec instance are recognized * and the supported raw formats info has been collected. */ if ((desc->dec || desc->enc) && desc->info.dec_fmt_id_cnt) { desc->enabled = PJ_TRUE; } /* Normalize default value of clock rate */ if (desc->info.clock_rate == 0) desc->info.clock_rate = 90000; /* Set supported packings */ desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE; if (desc->packetize && desc->unpacketize) desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS; } /* Review all codecs for applying base format, registering format match for * SDP negotiation, etc. */ for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) { ffmpeg_codec_desc *desc = &codec_desc[i]; /* Init encoder/decoder description from base format */ if (desc->base_fmt_id && (!desc->dec || !desc->enc)) { ffmpeg_codec_desc *base_desc = NULL; int base_desc_idx; pjmedia_dir copied_dir = PJMEDIA_DIR_NONE; base_desc_idx = find_codec_idx_by_fmt_id(desc->base_fmt_id); if (base_desc_idx != -1) base_desc = &codec_desc[base_desc_idx]; if (!base_desc || !base_desc->enabled) continue; /* Copy description from base codec */ if (!desc->info.dec_fmt_id_cnt) { desc->info.dec_fmt_id_cnt = base_desc->info.dec_fmt_id_cnt; pj_memcpy(desc->info.dec_fmt_id, base_desc->info.dec_fmt_id, sizeof(pjmedia_format_id)*desc->info.dec_fmt_id_cnt); } if (!desc->info.fps_cnt) { desc->info.fps_cnt = base_desc->info.fps_cnt; pj_memcpy(desc->info.fps, base_desc->info.fps, sizeof(desc->info.fps[0])*desc->info.fps_cnt); } if (!desc->info.clock_rate) { desc->info.clock_rate = base_desc->info.clock_rate; } if (!desc->dec && base_desc->dec) { copied_dir |= PJMEDIA_DIR_DECODING; desc->dec = base_desc->dec; } if (!desc->enc && base_desc->enc) { copied_dir |= PJMEDIA_DIR_ENCODING; desc->enc = base_desc->enc; } desc->info.dir |= copied_dir; desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE); /* Set supported packings */ desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE; if (desc->packetize && desc->unpacketize) desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS; if (copied_dir != PJMEDIA_DIR_NONE) { const char *dir_name[] = {NULL, "encoder", "decoder", "codec"}; PJ_LOG(5, (THIS_FILE, "The %.*s %s is using base codec (%.*s)", desc->info.encoding_name.slen, desc->info.encoding_name.ptr, dir_name[copied_dir], base_desc->info.encoding_name.slen, base_desc->info.encoding_name.ptr)); } } /* Registering format match for SDP negotiation */ if (desc->sdp_fmt_match) { status = pjmedia_sdp_neg_register_fmt_match_cb( &desc->info.encoding_name, desc->sdp_fmt_match); pj_assert(status == PJ_SUCCESS); } /* Print warning about missing encoder/decoder */ if (!desc->enc) { PJ_LOG(4, (THIS_FILE, "Cannot find %.*s encoder in ffmpeg library", desc->info.encoding_name.slen, desc->info.encoding_name.ptr)); } if (!desc->dec) { PJ_LOG(4, (THIS_FILE, "Cannot find %.*s decoder in ffmpeg library", desc->info.encoding_name.slen, desc->info.encoding_name.ptr)); } } /* Register codec factory to codec manager. */ status = pjmedia_vid_codec_mgr_register_factory(mgr, &ffmpeg_factory.base); if (status != PJ_SUCCESS) goto on_error; ffmpeg_factory.pool = pool; /* Done. */ return PJ_SUCCESS; on_error: pj_pool_release(pool); return status; }