static pj_status_t init_stack() { pj_sockaddr addr; pjsip_inv_callback inv_cb; pj_status_t status; pj_log_set_level(5); status = pj_init(); CHECK_STATUS(); pj_log_set_level(3); status = pjlib_util_init(); CHECK_STATUS(); pj_caching_pool_init(&app.cp, NULL, 0); app.pool = pj_pool_create( &app.cp.factory, "sipecho", 512, 512, 0); status = pjsip_endpt_create(&app.cp.factory, NULL, &app.sip_endpt); CHECK_STATUS(); pj_log_set_level(4); pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT); if (AF == pj_AF_INET()) { status = pjsip_udp_transport_start( app.sip_endpt, &addr.ipv4, NULL, 1, NULL); } else if (AF == pj_AF_INET6()) { status = pjsip_udp_transport_start6(app.sip_endpt, &addr.ipv6, NULL, 1, NULL); } else { status = PJ_EAFNOTSUP; } pj_log_set_level(3); CHECK_STATUS(); status = pjsip_tsx_layer_init_module(app.sip_endpt) || pjsip_ua_init_module( app.sip_endpt, NULL ); CHECK_STATUS(); pj_bzero(&inv_cb, sizeof(inv_cb)); inv_cb.on_state_changed = &call_on_state_changed; inv_cb.on_new_session = &call_on_forked; inv_cb.on_media_update = &call_on_media_update; inv_cb.on_rx_offer = &call_on_rx_offer; status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb) || pjsip_100rel_init_module(app.sip_endpt) || pjsip_endpt_register_module( app.sip_endpt, &mod_sipecho) || pjsip_endpt_register_module( app.sip_endpt, &msg_logger) || //pjmedia_endpt_create(&app.cp.factory, // pjsip_endpt_get_ioqueue(app.sip_endpt), // 0, &app.med_endpt) || pj_thread_create(app.pool, "sipecho", &worker_proc, NULL, 0, 0, &app.worker_thread); CHECK_STATUS(); return PJ_SUCCESS; }
static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq) { unsigned i; pj_status_t status; job_queue *jq = PJ_POOL_ZALLOC_T(pool, job_queue); jq->size = MAX_JOBS; status = pj_sem_create(pool, "thread_sem", 0, jq->size + 1, &jq->sem); if (status != PJ_SUCCESS) goto on_error; for (i = 0; i < jq->size; i++) { status = pj_sem_create(pool, "job_sem", 0, 1, &jq->job_sem[i]); if (status != PJ_SUCCESS) goto on_error; } status = pj_mutex_create_recursive(pool, "job_mutex", &jq->mutex); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(pool, "job_th", job_thread, jq, 0, 0, &jq->thread); if (status != PJ_SUCCESS) goto on_error; *pjq = jq; return PJ_SUCCESS; on_error: job_queue_destroy(jq); return status; }
pjs_frame_processor::pjs_frame_processor(pjs_global& global, unsigned capacity, unsigned samples_per_frame) : m_global(global), m_samples_per_frame(samples_per_frame) { m_started = false; m_thread = NULL; m_ready = false; m_exit = false; m_pool = pj_pool_create(m_global.get_pool_factory(), "pjs_frame_processor", 128, 128, NULL); m_lock = new PPJ_SemaphoreLock(m_pool, NULL, 1, 1); pj_status_t status = pjmedia_circ_buf_create(m_pool, capacity, &m_buffer); if (status == PJ_SUCCESS) { status = pj_thread_create(m_pool, "frame processor thread", (pj_thread_proc*) &s_thread_proc, this, PJ_THREAD_DEFAULT_STACK_SIZE, PJ_THREAD_SUSPENDED, &m_thread); if (status != PJ_SUCCESS) m_thread = NULL; else m_ready = true; } else m_buffer = NULL; }
/* * Start the clock. */ PJ_DEF(pj_status_t) pjmedia_clock_start(pjmedia_clock *clock) { pj_timestamp now; pj_status_t status; PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL); if (clock->running) return PJ_SUCCESS; status = pj_get_timestamp(&now); if (status != PJ_SUCCESS) return status; clock->next_tick.u64 = now.u64 + clock->interval.u64; clock->running = PJ_TRUE; clock->quitting = PJ_FALSE; if ((clock->options & PJMEDIA_CLOCK_NO_ASYNC) == 0 && !clock->thread) { status = pj_thread_create(clock->pool, "clock", &clock_thread, clock, 0, 0, &clock->thread); if (status != PJ_SUCCESS) { pj_lock_destroy(clock->lock); return status; } } return PJ_SUCCESS; }
int udp_echo_srv_ioqueue(void) { pj_pool_t *pool; pj_sock_t sock; pj_ioqueue_t *ioqueue; pj_ioqueue_callback callback; int i; pj_thread_t *thread[ECHO_SERVER_MAX_THREADS]; pj_status_t rc; pj_bzero(&callback, sizeof(callback)); callback.on_read_complete = &on_read_complete; callback.on_write_complete = &on_write_complete; pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -10; rc = pj_ioqueue_create(pool, 2, &ioqueue); if (rc != PJ_SUCCESS) { app_perror("...pj_ioqueue_create error", rc); return -20; } rc = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, ECHO_SERVER_START_PORT, &sock); if (rc != PJ_SUCCESS) { app_perror("...app_socket error", rc); return -30; } rc = pj_ioqueue_register_sock(pool, ioqueue, sock, NULL, &callback, &key); if (rc != PJ_SUCCESS) { app_perror("...error registering socket", rc); return -40; } rc = pj_atomic_create(pool, 0, &total_bytes); if (rc != PJ_SUCCESS) { app_perror("...error creating atomic variable", rc); return -45; } for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) { rc = pj_thread_create(pool, NULL, &worker_thread, ioqueue, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread[i]); if (rc != PJ_SUCCESS) { app_perror("...create thread error", rc); return -50; } } echo_srv_common_loop(total_bytes); return 0; }
// // Create a thread. // static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread, pj_thread_proc *proc, void *arg, unsigned flags = 0, const char *name = NULL, pj_size_t stack_size = 0 ) { return pj_thread_create(pool->pool_(), name, proc, arg, stack_size, flags, thread); }
/* API: start stream. */ static pj_status_t strm_start(pjmedia_aud_stream *s) { struct android_aud_stream *stream = (struct android_aud_stream*)s; PJ_LOG(4,(THIS_FILE, "Starting %s stream..", stream->name.ptr)); stream->quit_flag = 0; JNIEnv *jni_env = 0; ATTACH_JVM(jni_env); pj_status_t status; //Start threads if(stream->record){ status = pj_thread_create(stream->pool, "android_recorder", &AndroidRecorderCallback, stream, 0, 0, &stream->rec_thread); if (status != PJ_SUCCESS) { goto on_error; } // pj_sem_wait(stream->audio_launch_sem); } if(stream->track){ status = pj_thread_create(stream->pool, "android_track", &AndroidTrackCallback, stream, 0, 0, &stream->play_thread); if (status != PJ_SUCCESS) { goto on_error; } // pj_sem_wait(stream->audio_launch_sem); } PJ_LOG(4,(THIS_FILE, "Starting done")); status = PJ_SUCCESS; on_error: DETACH_JVM(jni_env); if(status != PJ_SUCCESS){ strm_destroy(&stream->base); } return status; }
/* * Create media clock. */ PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned options, pjmedia_clock_callback *cb, void *user_data, pjmedia_clock **p_clock) { pjmedia_clock *clock; pj_status_t status; PJ_ASSERT_RETURN(pool && clock_rate && samples_per_frame && p_clock, PJ_EINVAL); clock = PJ_POOL_ALLOC_T(pool, pjmedia_clock); status = pj_get_timestamp_freq(&clock->freq); if (status != PJ_SUCCESS) return status; clock->interval.u64 = samples_per_frame * clock->freq.u64 / channel_count / clock_rate; clock->next_tick.u64 = 0; clock->timestamp.u64 = 0; clock->max_jump = MAX_JUMP_MSEC * clock->freq.u64 / 1000; clock->timestamp_inc = samples_per_frame / channel_count; clock->options = options; clock->cb = cb; clock->user_data = user_data; clock->thread = NULL; clock->running = PJ_FALSE; clock->quitting = PJ_FALSE; /* I don't think we need a mutex, so we'll use null. */ status = pj_lock_create_null_mutex(pool, "clock", &clock->lock); if (status != PJ_SUCCESS) return status; if ((clock->options & PJMEDIA_CLOCK_NO_ASYNC) == 0) { status = pj_thread_create(pool, "clock", &clock_thread, clock, 0, 0, &clock->thread); if (status != PJ_SUCCESS) { pj_lock_destroy(clock->lock); return status; } } *p_clock = clock; return PJ_SUCCESS; }
pj_status_t start_stack() { pj_status_t status = PJ_SUCCESS; quit_flag = PJ_FALSE; // Create worker threads first as they take work from the PJSIP threads so // need to be ready. for (size_t ii = 0; ii < worker_threads.size(); ++ii) { pj_thread_t* thread; status = pj_thread_create(stack_data.pool, "worker", &worker_thread, NULL, 0, 0, &thread); if (status != PJ_SUCCESS) { LOG_ERROR("Error creating worker thread, %s", PJUtils::pj_status_to_string(status).c_str()); return 1; } worker_threads[ii] = thread; } // Now create the PJSIP threads. for (size_t ii = 0; ii < pjsip_threads.size(); ++ii) { pj_thread_t* thread; status = pj_thread_create(stack_data.pool, "pjsip", &pjsip_thread, NULL, 0, 0, &thread); if (status != PJ_SUCCESS) { LOG_ERROR("Error creating PJSIP thread, %s", PJUtils::pj_status_to_string(status).c_str()); return 1; } pjsip_threads[ii] = thread; } return status; }
/* * Create media clock. */ PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool, unsigned clock_rate, unsigned samples_per_frame, unsigned options, pjmedia_clock_callback *cb, void *user_data, pjmedia_clock **p_clock) { pjmedia_clock *clock; pj_status_t status; PJ_ASSERT_RETURN(pool && clock_rate && samples_per_frame && p_clock, PJ_EINVAL); clock = pj_pool_alloc(pool, sizeof(pjmedia_clock)); status = pj_get_timestamp_freq(&clock->freq); if (status != PJ_SUCCESS) return status; clock->interval.u64 = samples_per_frame * clock->freq.u64 / clock_rate; clock->next_tick.u64 = 0; clock->timestamp.u64 = 0; clock->samples_per_frame = samples_per_frame; clock->options = options; clock->cb = cb; clock->user_data = user_data; clock->thread = NULL; clock->running = PJ_FALSE; clock->quitting = PJ_FALSE; /* I don't think we need a mutex, so we'll use null. */ status = pj_lock_create_null_mutex(pool, "clock", &clock->lock); if (status != PJ_SUCCESS) return status; status = pj_thread_create(pool, "clock", &clock_thread, clock, 0, 0, &clock->thread); if (status != PJ_SUCCESS) { pj_lock_destroy(clock->lock); return status; } *p_clock = clock; return PJ_SUCCESS; }
/* API: start stream */ static pj_status_t alsa_stream_start (pjmedia_aud_stream *s) { struct alsa_stream *stream = (struct alsa_stream*)s; pj_status_t status = PJ_SUCCESS; stream->quit = 0; if (stream->param.dir & PJMEDIA_DIR_PLAYBACK) { status = pj_thread_create (stream->pool, "alsasound_playback", pb_thread_func, stream, 0, //ZERO, 0, &stream->pb_thread); if (status != PJ_SUCCESS) return status; } if (stream->param.dir & PJMEDIA_DIR_CAPTURE) { status = pj_thread_create (stream->pool, "alsasound_playback", ca_thread_func, stream, 0, //ZERO, 0, &stream->ca_thread); if (status != PJ_SUCCESS) { stream->quit = PJ_TRUE; pj_thread_join(stream->pb_thread); pj_thread_destroy(stream->pb_thread); stream->pb_thread = NULL; } } return status; }
PJStunTurn::PJStunTurn() { if (PJ_SUCCESS != pjnath_init()) { g_warning("cannot init pjnath"); return; } pj_ice_strans_cfg_default(&ice_cfg_); pj_timer_heap_create(PJSIP::this_->pool_, 100, &ice_cfg_.stun_cfg.timer_heap); pj_ioqueue_create(PJSIP::this_->pool_, 512, &ice_cfg_.stun_cfg.ioqueue); ice_cfg_.stun_cfg.pf = PJSIP::this_->pool_->factory; if (PJ_SUCCESS != pj_thread_create(PJSIP::this_->pool_, "switcherSIP", &worker_thread, this, 0, 0, &thread_)) { g_warning("STUN TURN thread creating failed"); return; } ice_cfg_.af = pj_AF_INET(); ice_cfg_.stun.cfg.max_pkt_size = 8192; ice_cfg_.turn.cfg.max_pkt_size = 8192; ice_cfg_.opt.aggressive = PJ_FALSE; ice_cfg_.stun_cfg.rto_msec = 500; // set stun/turn config SIPPlugin::this_->install_method( "Set STUN/TURN parameters", // long name "set_stun_turn", // name "Set STUN/TURN configuration", // description "the server(s) are reachable", // return description Method::make_arg_description("STUN server address", // long name "stun", // name "string", // description "TURN server address", "turn", "string", "TURN user name", "turn_user", "string", "TURN user password", "turn_pass", "string", nullptr), (Method::method_ptr)&set_stun_turn, G_TYPE_BOOLEAN, Method::make_arg_type_description( G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, nullptr), this); }
int echo_srv_sync(void) { pj_pool_t *pool; pj_sock_t sock; pj_thread_t *thread[ECHO_SERVER_MAX_THREADS]; pj_status_t rc; int i; pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -5; rc = pj_atomic_create(pool, 0, &total_bytes); if (rc != PJ_SUCCESS) { app_perror("...unable to create atomic_var", rc); return -6; } rc = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(),0, ECHO_SERVER_START_PORT, &sock); if (rc != PJ_SUCCESS) { app_perror("...socket error", rc); return -10; } for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) { rc = pj_thread_create(pool, NULL, &worker_thread, (void*)sock, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread[i]); if (rc != PJ_SUCCESS) { app_perror("...unable to create thread", rc); return -20; } } PJ_LOG(3,("", "...UDP echo server running with %d threads at port %d", ECHO_SERVER_MAX_THREADS, ECHO_SERVER_START_PORT)); PJ_LOG(3,("", "...Press Ctrl-C to abort")); echo_srv_common_loop(total_bytes); return 0; }
PJ_DEF(pj_status_t) pjmedia_event_mgr_create(pj_pool_t *pool, unsigned options, pjmedia_event_mgr **p_mgr) { pjmedia_event_mgr *mgr; pj_status_t status; mgr = PJ_POOL_ZALLOC_T(pool, pjmedia_event_mgr); mgr->pool = pj_pool_create(pool->factory, "evt mgr", 500, 500, NULL); pj_list_init(&mgr->esub_list); pj_list_init(&mgr->free_esub_list); if (!(options & PJMEDIA_EVENT_MGR_NO_THREAD)) { status = pj_sem_create(mgr->pool, "ev_sem", 0, MAX_EVENTS + 1, &mgr->sem); if (status != PJ_SUCCESS) return status; status = pj_thread_create(mgr->pool, "ev_thread", &event_worker_thread, mgr, 0, 0, &mgr->thread); if (status != PJ_SUCCESS) { pjmedia_event_mgr_destroy(mgr); return status; } } status = pj_mutex_create_recursive(mgr->pool, "ev_mutex", &mgr->mutex); if (status != PJ_SUCCESS) { pjmedia_event_mgr_destroy(mgr); return status; } if (!event_manager_instance) event_manager_instance = mgr; if (p_mgr) *p_mgr = mgr; return PJ_SUCCESS; }
pj_status_t start_pjsip_threads() { pj_status_t status = PJ_SUCCESS; for (size_t ii = 0; ii < pjsip_threads.size(); ++ii) { pj_thread_t* thread; status = pj_thread_create(stack_data.pool, "pjsip", &pjsip_thread_func, NULL, 0, 0, &thread); if (status != PJ_SUCCESS) { LOG_ERROR("Error creating PJSIP thread, %s", PJUtils::pj_status_to_string(status).c_str()); return 1; } pjsip_threads[ii] = thread; } return PJ_SUCCESS; }
void ConnectionPool::init() { // Create an initial set of connections. for (int ii = 0; ii < _num_connections; ++ii) { create_connection(ii); } if (_recycle_period != 0) { // Spawn a thread to recycle connections pj_status_t status = pj_thread_create(_pool, "recycler", &recycle_thread, (void*)this, 0, 0, &_recycler); if (status != PJ_SUCCESS) { TRC_ERROR("Error creating recycler thread, %s", PJUtils::pj_status_to_string(status).c_str()); } } TRC_DEBUG("Started %d connections to %.*s:%d", _num_connections, _target.host.slen, _target.host.ptr, _target.port); }
int main() { pj_caching_pool cp; pj_pool_t *pool; int i; pj_thread_t *thread1; pj_log_set_level(3); CHECK(__FILE__, pj_init()); pj_srand(123765); pj_caching_pool_init(&cp, NULL, 1024); pool = pj_pool_create(&cp.factory, "objpool", 128, 128, NULL); pj_thread_create(pool, "thread1", &do_test, pool, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &thread1); pj_thread_sleep(500); do_test(pool); pj_thread_join(thread1); pj_pool_release(pool); pj_caching_pool_destroy(&cp); pj_shutdown(); return 0; }
/* Instantiate standard server */ static int create_std_server(pj_stun_auth_type auth_type, pj_bool_t responding) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_stun_auth_cred cred; pj_status_t status; /* Create server */ pool = pj_pool_create(mem, "server", 1000, 1000, NULL); server = PJ_POOL_ZALLOC_T(pool, struct server); server->pool = pool; server->auth_type = auth_type; server->responding = responding; /* Create STUN session */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_rx_request = &server_on_rx_request; sess_cb.on_send_msg = &server_send_msg; status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, NULL, &server->sess); if (status != PJ_SUCCESS) { destroy_server(); return -10; } /* Configure credential */ pj_bzero(&cred, sizeof(cred)); cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; cred.data.dyn_cred.get_auth = &server_get_auth; cred.data.dyn_cred.get_password = &server_get_password; cred.data.dyn_cred.verify_nonce = &server_verify_nonce; status = pj_stun_session_set_credential(server->sess, auth_type, &cred); if (status != PJ_SUCCESS) { destroy_server(); return -20; } /* Create socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &server->sock); if (status != PJ_SUCCESS) { destroy_server(); return -30; } /* Bind */ pj_sockaddr_in_init(&server->addr.ipv4, NULL, 0); status = pj_sock_bind(server->sock, &server->addr, pj_sockaddr_get_len(&server->addr)); if (status != PJ_SUCCESS) { destroy_server(); return -40; } else { /* Get the bound IP address */ int namelen = sizeof(server->addr); pj_sockaddr addr; status = pj_sock_getsockname(server->sock, &server->addr, &namelen); if (status != PJ_SUCCESS) { destroy_server(); return -43; } status = pj_gethostip(pj_AF_INET(), &addr); if (status != PJ_SUCCESS) { destroy_server(); return -45; } pj_sockaddr_copy_addr(&server->addr, &addr); } /* Create worker thread */ status = pj_thread_create(pool, "server", &server_thread, 0, 0, 0, &server->thread); if (status != PJ_SUCCESS) { destroy_server(); return -30; } return 0; }
/* * timeslice_test() */ static int timeslice_test(void) { enum { NUM_THREADS = 4 }; pj_pool_t *pool; pj_uint32_t counter[NUM_THREADS], lowest, highest, diff; pj_thread_t *thread[NUM_THREADS]; unsigned i; pj_status_t rc; quit_flag = 0; pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -10; PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS)); /* Create all threads in suspended mode. */ for (i=0; i<NUM_THREADS; ++i) { counter[i] = i; rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, &counter[i], PJ_THREAD_DEFAULT_STACK_SIZE, PJ_THREAD_SUSPENDED, &thread[i]); if (rc!=PJ_SUCCESS) { app_perror("...ERROR in pj_thread_create()", rc); return -20; } } /* Sleep for 1 second. * The purpose of this is to test whether all threads are suspended. */ TRACE__((THIS_FILE, " Main thread waiting..")); pj_thread_sleep(1000); TRACE__((THIS_FILE, " Main thread resuming..")); /* Check that all counters are still zero. */ for (i=0; i<NUM_THREADS; ++i) { if (counter[i] > i) { PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!", i)); return -30; } } /* Now resume all threads. */ for (i=0; i<NUM_THREADS; ++i) { TRACE__((THIS_FILE, " Resuming thread %d [%p]..", i, thread[i])); rc = pj_thread_resume(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_resume()", rc); return -40; } } /* Main thread sleeps for some time to allow threads to run. * The longer we sleep, the more accurate the calculation will be, * but it'll make user waits for longer for the test to finish. */ TRACE__((THIS_FILE, " Main thread waiting (5s)..")); pj_thread_sleep(5000); TRACE__((THIS_FILE, " Main thread resuming..")); /* Signal all threads to quit. */ quit_flag = 1; /* Wait until all threads quit, then destroy. */ for (i=0; i<NUM_THREADS; ++i) { TRACE__((THIS_FILE, " Main thread joining thread %d [%p]..", i, thread[i])); rc = pj_thread_join(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_join()", rc); return -50; } TRACE__((THIS_FILE, " Destroying thread %d [%p]..", i, thread[i])); rc = pj_thread_destroy(thread[i]); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_thread_destroy()", rc); return -60; } } TRACE__((THIS_FILE, " Main thread calculating time slices..")); /* Now examine the value of the counters. * Check that all threads had equal proportion of processing. */ lowest = 0xFFFFFFFF; highest = 0; for (i=0; i<NUM_THREADS; ++i) { if (counter[i] < lowest) lowest = counter[i]; if (counter[i] > highest) highest = counter[i]; } /* Check that all threads are running. */ if (lowest < 2) { PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!")); return -70; } /* The difference between lowest and higest should be lower than 50%. */ diff = (highest-lowest)*100 / ((highest+lowest)/2); if ( diff >= 50) { PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!")); PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%", lowest, highest, diff)); return -80; } else { PJ_LOG(3,(THIS_FILE, "...info: timeslice diff between lowest & highest=%u%%", diff)); } pj_pool_release(pool); return 0; }
/* * simple_thread() */ static int simple_thread(const char *title, unsigned flags) { pj_pool_t *pool; pj_thread_t *thread; pj_status_t rc; pj_uint32_t counter = 0; PJ_LOG(3,(THIS_FILE, "..%s", title)); pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return -1000; quit_flag = 0; TRACE__((THIS_FILE, " Creating thread 0..")); rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, &counter, PJ_THREAD_DEFAULT_STACK_SIZE, flags, &thread); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create thread", rc); return -1010; } TRACE__((THIS_FILE, " Main thread waiting..")); pj_thread_sleep(1500); TRACE__((THIS_FILE, " Main thread resuming..")); if (flags & PJ_THREAD_SUSPENDED) { /* Check that counter is still zero */ if (counter != 0) { PJ_LOG(3,(THIS_FILE, "...error: thread is not suspended")); return -1015; } rc = pj_thread_resume(thread); if (rc != PJ_SUCCESS) { app_perror("...error: resume thread error", rc); return -1020; } } PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit..")); pj_thread_sleep(1500); quit_flag = 1; pj_thread_join(thread); pj_pool_release(pool); if (counter == 0) { PJ_LOG(3,(THIS_FILE, "...error: thread is not running")); return -1025; } PJ_LOG(3,(THIS_FILE, "...%s success", title)); return PJ_SUCCESS; }
/* Calculate the bandwidth for the specific test configuration. * The test is simple: * - create sockpair_cnt number of producer-consumer socket pair. * - create thread_cnt number of worker threads. * - each producer will send buffer_size bytes data as fast and * as soon as it can. * - each consumer will read buffer_size bytes of data as fast * as it could. * - measure the total bytes received by all consumers during a * period of time. */ static int perform_test(pj_bool_t allow_concur, int sock_type, const char *type_name, unsigned thread_cnt, unsigned sockpair_cnt, pj_size_t buffer_size, pj_size_t *p_bandwidth) { enum { MSEC_DURATION = 5000 }; pj_pool_t *pool; test_item *items; pj_thread_t **thread; pj_ioqueue_t *ioqueue; pj_status_t rc; pj_ioqueue_callback ioqueue_callback; pj_uint32_t total_elapsed_usec, total_received; pj_highprec_t bandwidth; pj_timestamp start, stop; unsigned i; TRACE_((THIS_FILE, " starting test..")); ioqueue_callback.on_read_complete = &on_read_complete; ioqueue_callback.on_write_complete = &on_write_complete; thread_quit_flag = 0; pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); if (!pool) return -10; items = (test_item*) pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item)); thread = (pj_thread_t**) pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*)); TRACE_((THIS_FILE, " creating ioqueue..")); rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create ioqueue", rc); return -15; } rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_set_default_concurrency()", rc); return -16; } /* Initialize each producer-consumer pair. */ for (i=0; i<sockpair_cnt; ++i) { pj_ssize_t bytes; items[i].ioqueue = ioqueue; items[i].buffer_size = buffer_size; items[i].outgoing_buffer = (char*) pj_pool_alloc(pool, buffer_size); items[i].incoming_buffer = (char*) pj_pool_alloc(pool, buffer_size); items[i].bytes_recv = items[i].bytes_sent = 0; /* randomize outgoing buffer. */ pj_create_random_string(items[i].outgoing_buffer, buffer_size); /* Create socket pair. */ TRACE_((THIS_FILE, " calling socketpair..")); rc = app_socketpair(pj_AF_INET(), sock_type, 0, &items[i].server_fd, &items[i].client_fd); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create socket pair", rc); return -20; } /* Register server socket to ioqueue. */ TRACE_((THIS_FILE, " register(1)..")); rc = pj_ioqueue_register_sock(pool, ioqueue, items[i].server_fd, &items[i], &ioqueue_callback, &items[i].server_key); if (rc != PJ_SUCCESS) { app_perror("...error: registering server socket to ioqueue", rc); return -60; } /* Register client socket to ioqueue. */ TRACE_((THIS_FILE, " register(2)..")); rc = pj_ioqueue_register_sock(pool, ioqueue, items[i].client_fd, &items[i], &ioqueue_callback, &items[i].client_key); if (rc != PJ_SUCCESS) { app_perror("...error: registering server socket to ioqueue", rc); return -70; } /* Start reading. */ TRACE_((THIS_FILE, " pj_ioqueue_recv..")); bytes = items[i].buffer_size; rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op, items[i].incoming_buffer, &bytes, 0); if (rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_recv", rc); return -73; } /* Start writing. */ TRACE_((THIS_FILE, " pj_ioqueue_write..")); bytes = items[i].buffer_size; rc = pj_ioqueue_send(items[i].client_key, &items[i].send_op, items[i].outgoing_buffer, &bytes, 0); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_write", rc); return -76; } items[i].has_pending_send = (rc==PJ_EPENDING); } /* Create the threads. */ for (i=0; i<thread_cnt; ++i) { struct thread_arg *arg; arg = (struct thread_arg*) pj_pool_zalloc(pool, sizeof(*arg)); arg->id = i; arg->ioqueue = ioqueue; arg->counter = 0; rc = pj_thread_create( pool, NULL, &worker_thread, arg, PJ_THREAD_DEFAULT_STACK_SIZE, PJ_THREAD_SUSPENDED, &thread[i] ); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create thread", rc); return -80; } } /* Mark start time. */ rc = pj_get_timestamp(&start); if (rc != PJ_SUCCESS) return -90; /* Start the thread. */ TRACE_((THIS_FILE, " resuming all threads..")); for (i=0; i<thread_cnt; ++i) { rc = pj_thread_resume(thread[i]); if (rc != 0) return -100; } /* Wait for MSEC_DURATION seconds. * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually, * but unfortunately it doesn't work when system doesn't employ * timeslicing for threads. */ TRACE_((THIS_FILE, " wait for few seconds..")); do { pj_thread_sleep(1); /* Mark end time. */ rc = pj_get_timestamp(&stop); if (thread_quit_flag) { TRACE_((THIS_FILE, " transfer limit reached..")); break; } if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) { TRACE_((THIS_FILE, " time limit reached..")); break; } } while (1); /* Terminate all threads. */ TRACE_((THIS_FILE, " terminating all threads..")); thread_quit_flag = 1; for (i=0; i<thread_cnt; ++i) { TRACE_((THIS_FILE, " join thread %d..", i)); pj_thread_join(thread[i]); } /* Close all sockets. */ TRACE_((THIS_FILE, " closing all sockets..")); for (i=0; i<sockpair_cnt; ++i) { pj_ioqueue_unregister(items[i].server_key); pj_ioqueue_unregister(items[i].client_key); } /* Destroy threads */ for (i=0; i<thread_cnt; ++i) { pj_thread_destroy(thread[i]); } /* Destroy ioqueue. */ TRACE_((THIS_FILE, " destroying ioqueue..")); pj_ioqueue_destroy(ioqueue); /* Calculate actual time in usec. */ total_elapsed_usec = pj_elapsed_usec(&start, &stop); /* Calculate total bytes received. */ total_received = 0; for (i=0; i<sockpair_cnt; ++i) { total_received = (pj_uint32_t)items[i].bytes_recv; } /* bandwidth = total_received*1000/total_elapsed_usec */ bandwidth = total_received; pj_highprec_mul(bandwidth, 1000); pj_highprec_div(bandwidth, total_elapsed_usec); *p_bandwidth = (pj_uint32_t)bandwidth; PJ_LOG(3,(THIS_FILE, " %.4s %2d %2d %8d KB/s", type_name, thread_cnt, sockpair_cnt, *p_bandwidth)); /* Done. */ pj_pool_release(pool); TRACE_((THIS_FILE, " done..")); return 0; }
/** * Initialize and get the instance of media endpoint. */ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt) { pj_pool_t *pool; pjmedia_endpt *endpt; unsigned i; pj_status_t status; if (!error_subsys_registered) { pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE, &pjmedia_strerror); error_subsys_registered = 1; } PJ_ASSERT_RETURN(pf && p_endpt, PJ_EINVAL); PJ_ASSERT_RETURN(worker_cnt <= MAX_THREADS, PJ_EINVAL); pool = pj_pool_create(pf, "med-ept", 512, 512, NULL); if (!pool) return PJ_ENOMEM; endpt = PJ_POOL_ZALLOC_T(pool, struct pjmedia_endpt); endpt->pool = pool; endpt->pf = pf; endpt->ioqueue = ioqueue; endpt->thread_cnt = worker_cnt; /* Sound */ status = pjmedia_aud_subsys_init(pf); if (status != PJ_SUCCESS) goto on_error; /* Init codec manager. */ status = pjmedia_codec_mgr_init(&endpt->codec_mgr); if (status != PJ_SUCCESS) goto on_error; /* Create ioqueue if none is specified. */ if (endpt->ioqueue == NULL) { endpt->own_ioqueue = PJ_TRUE; status = pj_ioqueue_create( endpt->pool, PJ_IOQUEUE_MAX_HANDLES, &endpt->ioqueue); if (status != PJ_SUCCESS) goto on_error; if (worker_cnt == 0) { PJ_LOG(4,(THIS_FILE, "Warning: no worker thread is created in" "media endpoint for internal ioqueue")); } } /* Create worker threads if asked. */ for (i=0; i<worker_cnt; ++i) { status = pj_thread_create( endpt->pool, "media", &worker_proc, endpt, 0, 0, &endpt->thread[i]); if (status != PJ_SUCCESS) goto on_error; } *p_endpt = endpt; return PJ_SUCCESS; on_error: /* Destroy threads */ for (i=0; i<endpt->thread_cnt; ++i) { if (endpt->thread[i]) { pj_thread_destroy(endpt->thread[i]); } } /* Destroy internal ioqueue */ if (endpt->ioqueue && endpt->own_ioqueue) pj_ioqueue_destroy(endpt->ioqueue); pjmedia_aud_subsys_shutdown(); pj_pool_release(pool); return status; }
static int stun_destroy_test(void) { enum { LOOP = 500 }; struct stun_test_session test_sess; pj_sockaddr bind_addr; int addr_len; pj_caching_pool cp; pj_pool_t *pool; unsigned i; pj_status_t status; int rc = 0; PJ_LOG(3,(THIS_FILE, " STUN destroy concurrency test")); pj_bzero(&test_sess, sizeof(test_sess)); pj_caching_pool_init(&cp, NULL, 0); pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL); pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL); status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap); pj_assert(status == PJ_SUCCESS); status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock); pj_assert(status == PJ_SUCCESS); pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE); pj_assert(status == PJ_SUCCESS); status = pj_ioqueue_create(pool, 512, &test_sess.stun_cfg.ioqueue); pj_assert(status == PJ_SUCCESS); pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock); pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0); status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr)); pj_assert(status == PJ_SUCCESS); addr_len = sizeof(bind_addr); status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len); pj_assert(status == PJ_SUCCESS); test_sess.server_port = pj_sockaddr_get_port(&bind_addr); status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event); pj_assert(status == PJ_SUCCESS); for (i=0; i<SERVER_THREAD_CNT; ++i) { status = pj_thread_create(pool, NULL, &server_thread_proc, &test_sess, 0, 0, &test_sess.server_threads[i]); pj_assert(status == PJ_SUCCESS); } for (i=0; i<WORKER_THREAD_CNT; ++i) { status = pj_thread_create(pool, NULL, &worker_thread_proc, &test_sess, 0, 0, &test_sess.worker_threads[i]); pj_assert(status == PJ_SUCCESS); } /* Test 1: Main thread calls destroy while callback is processing response */ PJ_LOG(3,(THIS_FILE, " Destroy in main thread while callback is running")); for (i=0; i<LOOP; ++i) { int sleep = pj_rand() % 5; PJ_LOG(3,(THIS_FILE, " Try %-3d of %d", i+1, LOOP)); /* Test 1: destroy at the same time when receiving response */ pj_bzero(&test_sess.param, sizeof(test_sess.param)); test_sess.param.client_sleep_after_start = 20; test_sess.param.client_sleep_before_destroy = sleep; test_sess.param.server_wait_for_event = PJ_TRUE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test a: sleep delay:%d: clients with response: %d", sleep, test_sess.param.client_got_response)); /* Test 2: destroy at the same time with STUN retransmit timer */ test_sess.param.server_drop_request = PJ_TRUE; test_sess.param.client_sleep_after_start = 0; test_sess.param.client_sleep_before_destroy = PJ_STUN_RTO_VALUE; test_sess.param.server_wait_for_event = PJ_FALSE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test b: retransmit concurrency")); /* Test 3: destroy at the same time with receiving response * AND STUN retransmit timer */ test_sess.param.client_got_response = 0; test_sess.param.server_drop_request = PJ_FALSE; test_sess.param.client_sleep_after_start = PJ_STUN_RTO_VALUE; test_sess.param.client_sleep_before_destroy = 0; test_sess.param.server_wait_for_event = PJ_TRUE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test c: clients with response: %d", test_sess.param.client_got_response)); pj_thread_sleep(10); ice_one_conc_test(&test_sess.stun_cfg, PJ_FALSE); pj_thread_sleep(10); } /* Avoid compiler warning */ goto on_return; on_return: test_sess.thread_quit_flag = PJ_TRUE; for (i=0; i<SERVER_THREAD_CNT; ++i) { pj_thread_join(test_sess.server_threads[i]); } for (i=0; i<WORKER_THREAD_CNT; ++i) { pj_thread_join(test_sess.worker_threads[i]); } pj_event_destroy(test_sess.server_event); pj_sock_close(test_sess.server_sock); pj_ioqueue_destroy(test_sess.stun_cfg.ioqueue); pj_timer_heap_destroy(test_sess.stun_cfg.timer_heap); pj_pool_release(pool); pj_caching_pool_destroy(&cp); PJ_LOG(3,(THIS_FILE, " Done. rc=%d", rc)); return rc; }
void serial_start(serial_t *serial) { pj_thread_create(serial->pool, NULL, do_thing, serial, PJ_THREAD_DEFAULT_STACK_SIZE, 0, &serial->master_thread); }
int http_client_test_delete() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -61; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -62; #ifdef USE_LOCAL_SERVER thread_quit = PJ_FALSE; g_server.action = ACTION_REPLY; g_server.send_content_length = PJ_TRUE; g_server.data_size = 0; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d/test/test2.txt", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt"); #endif pj_http_req_param_default(¶m); pj_strset2(¶m.method, (char*)"DELETE"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -63; if (pj_http_req_start(http_req)) return -65; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* * GET request scenario 2: using on_complete() to get the * complete data. Server does not reply with content-length. * Request timed out, application sets a longer timeout, then * then restart the request. */ int http_client_test2() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; pj_time_val timeout; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; pj_http_req_param_default(¶m); /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -41; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -42; #ifdef USE_LOCAL_SERVER pj_cstr(&url, "http://127.0.0.1:380"); param.timeout.sec = 0; param.timeout.msec = 2000; thread_quit = PJ_FALSE; g_server.action = ACTION_IGNORE; g_server.send_content_length = PJ_FALSE; g_server.data_size = 4173; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://www.google.com.sg"); param.timeout.sec = 0; param.timeout.msec = 50; #endif pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept", (char*)"image/gif, image/x-xbitmap, image/jpeg, " "image/pjpeg, application/x-ms-application," " application/vnd.ms-xpsdocument, " "application/xaml+xml, " "application/x-ms-xbap, " "application/x-shockwave-flash, " "application/vnd.ms-excel, " "application/vnd.ms-powerpoint, " "application/msword, */*"); pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept-Language", (char*)"en-sg"); pj_http_headers_add_elmt2(¶m.headers, (char*)"User-Agent", (char*)"Mozilla/4.0 (compatible; MSIE 7.0; " "Windows NT 6.0; SLCC1; " ".NET CLR 2.0.50727; " ".NET CLR 3.0.04506)"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -43; if (pj_http_req_start(http_req)) return -45; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER g_server.action = ACTION_REPLY; #endif timeout.sec = 0; timeout.msec = 10000; pj_http_req_set_timeout(http_req, &timeout); if (pj_http_req_start(http_req)) return -47; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
static int init() { int i; pj_status_t status; CHECK( pj_init() ); CHECK( pjlib_util_init() ); CHECK( pjnath_init() ); /* Check that server is specified */ if (!o.srv_addr) { printf("Error: server must be specified\n"); return PJ_EINVAL; } pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0); g.pool = pj_pool_create(&g.cp.factory, "main", 1000, 1000, NULL); /* Init global STUN config */ pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, NULL); /* Create global timer heap */ CHECK( pj_timer_heap_create(g.pool, 1000, &g.stun_config.timer_heap) ); /* Create global ioqueue */ CHECK( pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue) ); /* * Create peers */ for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) { pj_stun_sock_cb stun_sock_cb; char name[] = "peer0"; pj_uint16_t port; pj_stun_sock_cfg ss_cfg; pj_str_t server; pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); stun_sock_cb.on_rx_data = &stun_sock_on_rx_data; stun_sock_cb.on_status = &stun_sock_on_status; g.peer[i].mapped_addr.addr.sa_family = pj_AF_INET(); pj_stun_sock_cfg_default(&ss_cfg); #if 1 /* make reading the log easier */ ss_cfg.ka_interval = 300; #endif name[strlen(name)-1] = '0'+i; status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(), &stun_sock_cb, &ss_cfg, &g.peer[i], &g.peer[i].stun_sock); if (status != PJ_SUCCESS) { my_perror("pj_stun_sock_create()", status); return status; } if (o.stun_server) { server = pj_str(o.stun_server); port = PJ_STUN_PORT; } else { server = pj_str(o.srv_addr); port = (pj_uint16_t)(o.srv_port?atoi(o.srv_port):PJ_STUN_PORT); } status = pj_stun_sock_start(g.peer[i].stun_sock, &server, port, NULL); if (status != PJ_SUCCESS) { my_perror("pj_stun_sock_start()", status); return status; } } /* Start the worker thread */ CHECK( pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread) ); return PJ_SUCCESS; }
static int run_client_test(const char *title, pj_bool_t server_responding, pj_stun_auth_type server_auth_type, pj_stun_auth_type client_auth_type, const char *realm, const char *username, const char *nonce, const char *password, pj_bool_t dummy_mi, pj_bool_t expected_error, pj_status_t expected_code, const char *expected_realm, const char *expected_nonce, int (*more_check)(void)) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_stun_auth_cred cred; pj_stun_tx_data *tdata; pj_status_t status; int rc = 0; PJ_LOG(3,(THIS_FILE, " %s test", title)); /* Create client */ pool = pj_pool_create(mem, "client", 1000, 1000, NULL); client = PJ_POOL_ZALLOC_T(pool, struct client); client->pool = pool; client->responding = PJ_TRUE; /* Create STUN session */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_request_complete = &client_on_request_complete; sess_cb.on_send_msg = &client_send_msg; status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, NULL, &client->sess); if (status != PJ_SUCCESS) { destroy_client_server(); return -200; } /* Create semaphore */ status = pj_sem_create(pool, "client", 0, 1, &client->test_complete); if (status != PJ_SUCCESS) { destroy_client_server(); return -205; } /* Create client socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &client->sock); if (status != PJ_SUCCESS) { destroy_client_server(); return -210; } /* Bind client socket */ status = pj_sock_bind_in(client->sock, 0, 0); if (status != PJ_SUCCESS) { destroy_client_server(); return -220; } /* Create client thread */ status = pj_thread_create(pool, "client", &client_thread, NULL, 0, 0, &client->thread); if (status != PJ_SUCCESS) { destroy_client_server(); return -230; } /* Initialize credential */ pj_bzero(&cred, sizeof(cred)); cred.type = PJ_STUN_AUTH_CRED_STATIC; if (realm) cred.data.static_cred.realm = pj_str((char*)realm); if (username) cred.data.static_cred.username = pj_str((char*)username); if (nonce) cred.data.static_cred.nonce = pj_str((char*)nonce); if (password) cred.data.static_cred.data = pj_str((char*)password); cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; status = pj_stun_session_set_credential(client->sess, client_auth_type, &cred); if (status != PJ_SUCCESS) { destroy_client_server(); return -240; } /* Create the server */ status = create_std_server(server_auth_type, server_responding); if (status != 0) { destroy_client_server(); return status; } /* Create request */ status = pj_stun_session_create_req(client->sess, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &tdata); if (status != PJ_SUCCESS) { destroy_client_server(); return -250; } /* Add our own attributes if client authentication is set to none */ if (client_auth_type == PJ_STUN_AUTH_NONE) { pj_str_t tmp; if (realm) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_REALM, pj_cstr(&tmp, realm)); if (username) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_USERNAME, pj_cstr(&tmp, username)); if (nonce) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, nonce)); if (password) { // ignored } if (dummy_mi) { pj_stun_msgint_attr *mi; pj_stun_msgint_attr_create(tdata->pool, &mi); pj_stun_msg_add_attr(tdata->msg, &mi->hdr); } } /* Send the request */ status = pj_stun_session_send_msg(client->sess, NULL, PJ_FALSE, PJ_TRUE, &server->addr, pj_sockaddr_get_len(&server->addr), tdata); if (status != PJ_SUCCESS) { destroy_client_server(); return -270; } /* Wait until test complete */ pj_sem_wait(client->test_complete); /* Verify response */ if (expected_error) { if (expected_code != client->response_status) { char e1[PJ_ERR_MSG_SIZE], e2[PJ_ERR_MSG_SIZE]; pj_strerror(expected_code, e1, sizeof(e1)); pj_strerror(client->response_status, e2, sizeof(e2)); PJ_LOG(3,(THIS_FILE, " err: expecting %d (%s) but got %d (%s) response", expected_code, e1, client->response_status, e2)); rc = -500; } } else { int res_code = 0; pj_stun_realm_attr *arealm; pj_stun_nonce_attr *anonce; if (client->response_status != 0) { PJ_LOG(3,(THIS_FILE, " err: expecting successful operation but got error %d", client->response_status)); rc = -600; goto done; } if (PJ_STUN_IS_ERROR_RESPONSE(client->response->hdr.type)) { pj_stun_errcode_attr *aerr = NULL; aerr = (pj_stun_errcode_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_ERROR_CODE, 0); if (aerr == NULL) { PJ_LOG(3,(THIS_FILE, " err: received error response without ERROR-CODE")); rc = -610; goto done; } res_code = aerr->err_code; } else { res_code = 0; } /* Check that code matches */ if (expected_code != res_code) { PJ_LOG(3,(THIS_FILE, " err: expecting response code %d but got %d", expected_code, res_code)); rc = -620; goto done; } /* Find REALM and NONCE attributes */ arealm = (pj_stun_realm_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_REALM, 0); anonce = (pj_stun_nonce_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_NONCE, 0); if (expected_realm) { if (arealm == NULL) { PJ_LOG(3,(THIS_FILE, " err: expecting REALM in esponse")); rc = -630; goto done; } if (pj_strcmp2(&arealm->value, expected_realm)!=0) { PJ_LOG(3,(THIS_FILE, " err: REALM mismatch in response")); rc = -640; goto done; } } else { if (arealm != NULL) { PJ_LOG(3,(THIS_FILE, " err: non expecting REALM in response")); rc = -650; goto done; } } if (expected_nonce) { if (anonce == NULL) { PJ_LOG(3,(THIS_FILE, " err: expecting NONCE in esponse")); rc = -660; goto done; } if (pj_strcmp2(&anonce->value, expected_nonce)!=0) { PJ_LOG(3,(THIS_FILE, " err: NONCE mismatch in response")); rc = -670; goto done; } } else { if (anonce != NULL) { PJ_LOG(3,(THIS_FILE, " err: non expecting NONCE in response")); rc = -680; goto done; } } } /* Our tests are okay so far. Let caller do some more tests if * it wants to. */ if (rc==0 && more_check) { rc = (*more_check)(); } done: destroy_client_server(); return rc; }
int transport_rt_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, char *target_url, int *lost) { enum { THREADS = 4, INTERVAL = 10 }; int i; pj_status_t status; pj_pool_t *pool; pj_bool_t logger_enabled; pj_timestamp zero_time, total_time; unsigned usec_rt; unsigned total_sent; unsigned total_recv; PJ_UNUSED_ARG(tp_type); PJ_UNUSED_ARG(ref_tp); PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", THREADS)); PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", INTERVAL)); /* Make sure msg logger is disabled. */ logger_enabled = msg_logger_set_enabled(0); /* Register module (if not yet registered) */ if (rt_module.id == -1) { status = pjsip_endpt_register_module( endpt, &rt_module ); if (status != PJ_SUCCESS) { app_perror(" error: unable to register module", status); return -600; } } /* Create pool for this test. */ pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); if (!pool) return -610; /* Initialize static test data. */ pj_ansi_strcpy(rt_target_uri, target_url); rt_call_id = pj_str("RT-Call-Id/"); rt_stop = PJ_FALSE; /* Initialize thread data. */ for (i=0; i<THREADS; ++i) { char buf[1]; pj_str_t str_id; pj_strset(&str_id, buf, 1); pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i])); /* Init timer entry */ rt_test_data[i].tx_timer.id = i; rt_test_data[i].tx_timer.cb = &rt_tx_timer; rt_test_data[i].timeout_timer.id = i; rt_test_data[i].timeout_timer.cb = &rt_timeout_timer; /* Generate Call-ID for each thread. */ rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1); pj_strcpy(&rt_test_data[i].call_id, &rt_call_id); buf[0] = '0' + (char)i; pj_strcat(&rt_test_data[i].call_id, &str_id); /* Init mutex. */ status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex); if (status != PJ_SUCCESS) { app_perror(" error: unable to create mutex", status); return -615; } /* Create thread, suspended. */ status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)i, 0, PJ_THREAD_SUSPENDED, &rt_test_data[i].thread); if (status != PJ_SUCCESS) { app_perror(" error: unable to create thread", status); return -620; } } /* Start threads! */ for (i=0; i<THREADS; ++i) { pj_time_val delay = {0,0}; pj_thread_resume(rt_test_data[i].thread); /* Schedule first message transmissions. */ rt_test_data[i].tx_timer.user_data = (void*)1; pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay); } /* Sleep for some time. */ pj_thread_sleep(INTERVAL * 1000); /* Signal thread to stop. */ rt_stop = PJ_TRUE; /* Wait threads to complete. */ for (i=0; i<THREADS; ++i) { pj_thread_join(rt_test_data[i].thread); pj_thread_destroy(rt_test_data[i].thread); } /* Destroy rt_test_data */ for (i=0; i<THREADS; ++i) { pj_mutex_destroy(rt_test_data[i].mutex); pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer); } /* Gather statistics. */ pj_bzero(&total_time, sizeof(total_time)); pj_bzero(&zero_time, sizeof(zero_time)); usec_rt = total_sent = total_recv = 0; for (i=0; i<THREADS; ++i) { total_sent += rt_test_data[i].sent_request_count; total_recv += rt_test_data[i].recv_response_count; pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time); } /* Display statistics. */ if (total_recv) total_time.u64 = total_time.u64/total_recv; else total_time.u64 = 0; usec_rt = pj_elapsed_usec(&zero_time, &total_time); PJ_LOG(3,(THIS_FILE, " done.")); PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent)); PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt)); pjsip_endpt_release_pool(endpt, pool); *lost = total_sent-total_recv; /* Flush events. */ flush_events(500); /* Restore msg logger. */ msg_logger_set_enabled(logger_enabled); return 0; }
/* API: create stream */ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param, pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_aud_strm) { struct android_aud_factory *pa = (struct android_aud_factory*)f; pj_pool_t *pool; struct android_aud_stream *stream; pj_status_t status = PJ_SUCCESS; int state = 0; int buffSize, inputBuffSizePlay, inputBuffSizeRec; int channelInCfg, channelOutCfg, sampleFormat; jmethodID constructor_method=0, bufsize_method = 0; jmethodID method_id = 0; jclass jcl; JNIEnv *jni_env = 0; pj_bool_t attached; PJ_ASSERT_RETURN(param->channel_count >= 1 && param->channel_count <= 2, PJ_EINVAL); PJ_ASSERT_RETURN(param->bits_per_sample==8 || param->bits_per_sample==16, PJ_EINVAL); PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL); pool = pj_pool_create(pa->pf, "jnistrm", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; PJ_LOG(4, (THIS_FILE, "Creating Android JNI stream")); stream = PJ_POOL_ZALLOC_T(pool, struct android_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, "JNI stream"); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; pj_memcpy(&stream->param, param, sizeof(*param)); stream->user_data = user_data; stream->rec_cb = rec_cb; stream->play_cb = play_cb; buffSize = stream->param.samples_per_frame*stream->param.bits_per_sample/8; stream->rec_buf_size = stream->play_buf_size = buffSize; channelInCfg = (param->channel_count == 1)? 16 /*CHANNEL_IN_MONO*/: 12 /*CHANNEL_IN_STEREO*/; channelOutCfg = (param->channel_count == 1)? 4 /*CHANNEL_OUT_MONO*/: 12 /*CHANNEL_OUT_STEREO*/; sampleFormat = (param->bits_per_sample == 8)? 3 /*ENCODING_PCM_8BIT*/: 2 /*ENCODING_PCM_16BIT*/; attached = attach_jvm(&jni_env); if (stream->dir & PJMEDIA_DIR_CAPTURE) { /* Find audio record class and create global ref */ jcl = (*jni_env)->FindClass(jni_env, "android/media/AudioRecord"); if (jcl == NULL) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record class")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->record_class = (jclass)(*jni_env)->NewGlobalRef(jni_env, jcl); (*jni_env)->DeleteLocalRef(jni_env, jcl); if (stream->record_class == 0) { status = PJ_ENOMEM; goto on_error; } /* Get the min buffer size function */ bufsize_method = (*jni_env)->GetStaticMethodID(jni_env, stream->record_class, "getMinBufferSize", "(III)I"); if (bufsize_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record " "getMinBufferSize() method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } inputBuffSizeRec = (*jni_env)->CallStaticIntMethod(jni_env, stream->record_class, bufsize_method, param->clock_rate, channelInCfg, sampleFormat); if (inputBuffSizeRec <= 0) { PJ_LOG(3, (THIS_FILE, "Unsupported audio record params")); status = PJMEDIA_EAUD_INIT; goto on_error; } } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { /* Find audio track class and create global ref */ jcl = (*jni_env)->FindClass(jni_env, "android/media/AudioTrack"); if (jcl == NULL) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track class")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->track_class = (jclass)(*jni_env)->NewGlobalRef(jni_env, jcl); (*jni_env)->DeleteLocalRef(jni_env, jcl); if (stream->track_class == 0) { status = PJ_ENOMEM; goto on_error; } /* Get the min buffer size function */ bufsize_method = (*jni_env)->GetStaticMethodID(jni_env, stream->track_class, "getMinBufferSize", "(III)I"); if (bufsize_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track " "getMinBufferSize() method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } inputBuffSizePlay = (*jni_env)->CallStaticIntMethod(jni_env, stream->track_class, bufsize_method, param->clock_rate, channelOutCfg, sampleFormat); if (inputBuffSizePlay <= 0) { PJ_LOG(3, (THIS_FILE, "Unsupported audio track params")); status = PJMEDIA_EAUD_INIT; goto on_error; } } if (stream->dir & PJMEDIA_DIR_CAPTURE) { jthrowable exc; int mic_source = 0; /* DEFAULT: default audio source */ /* Get pointer to the constructor */ constructor_method = (*jni_env)->GetMethodID(jni_env, stream->record_class, "<init>", "(IIIII)V"); if (constructor_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record's constructor")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } if (mic_source == 0) { /* Android-L (android-21) removes __system_property_get * from the NDK. */ /* char sdk_version[PROP_VALUE_MAX]; pj_str_t pj_sdk_version; int sdk_v; __system_property_get("ro.build.version.sdk", sdk_version); pj_sdk_version = pj_str(sdk_version); sdk_v = pj_strtoul(&pj_sdk_version); if (sdk_v > 10) */ mic_source = 7; /* VOICE_COMMUNICATION */ } PJ_LOG(4, (THIS_FILE, "Using audio input source : %d", mic_source)); do { stream->record = (*jni_env)->NewObject(jni_env, stream->record_class, constructor_method, mic_source, param->clock_rate, channelInCfg, sampleFormat, inputBuffSizeRec); if (stream->record == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio record object")); status = PJMEDIA_EAUD_INIT; goto on_error; } exc = (*jni_env)->ExceptionOccurred(jni_env); if (exc) { (*jni_env)->ExceptionDescribe(jni_env); (*jni_env)->ExceptionClear(jni_env); PJ_LOG(3, (THIS_FILE, "Failure in audio record's constructor")); if (mic_source == 0) { status = PJMEDIA_EAUD_INIT; goto on_error; } mic_source = 0; PJ_LOG(4, (THIS_FILE, "Trying the default audio source.")); continue; } /* Check state */ method_id = (*jni_env)->GetMethodID(jni_env, stream->record_class, "getState", "()I"); if (method_id == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record getState() " "method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } state = (*jni_env)->CallIntMethod(jni_env, stream->record, method_id); if (state == 0) { /* STATE_UNINITIALIZED */ PJ_LOG(3, (THIS_FILE, "Failure in initializing audio record.")); if (mic_source == 0) { status = PJMEDIA_EAUD_INIT; goto on_error; } mic_source = 0; PJ_LOG(4, (THIS_FILE, "Trying the default audio source.")); } } while (state == 0); stream->record = (*jni_env)->NewGlobalRef(jni_env, stream->record); if (stream->record == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio record global ref.")); status = PJMEDIA_EAUD_INIT; goto on_error; } status = pj_sem_create(stream->pool, NULL, 0, 1, &stream->rec_sem); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(stream->pool, "android_recorder", AndroidRecorderCallback, stream, 0, 0, &stream->rec_thread); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4, (THIS_FILE, "Audio record initialized successfully.")); } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { jthrowable exc; /* Get pointer to the constructor */ constructor_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "<init>", "(IIIIII)V"); if (constructor_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track's constructor.")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->track = (*jni_env)->NewObject(jni_env, stream->track_class, constructor_method, 0, /* STREAM_VOICE_CALL */ param->clock_rate, channelOutCfg, sampleFormat, inputBuffSizePlay, 1 /* MODE_STREAM */); if (stream->track == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio track object.")); status = PJMEDIA_EAUD_INIT; goto on_error; } exc = (*jni_env)->ExceptionOccurred(jni_env); if (exc) { (*jni_env)->ExceptionDescribe(jni_env); (*jni_env)->ExceptionClear(jni_env); PJ_LOG(3, (THIS_FILE, "Failure in audio track's constructor")); status = PJMEDIA_EAUD_INIT; goto on_error; } stream->track = (*jni_env)->NewGlobalRef(jni_env, stream->track); if (stream->track == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio track's global ref")); status = PJMEDIA_EAUD_INIT; goto on_error; } /* Check state */ method_id = (*jni_env)->GetMethodID(jni_env, stream->track_class, "getState", "()I"); if (method_id == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track getState() " "method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } state = (*jni_env)->CallIntMethod(jni_env, stream->track, method_id); if (state == 0) { /* STATE_UNINITIALIZED */ PJ_LOG(3, (THIS_FILE, "Failure in initializing audio track.")); status = PJMEDIA_EAUD_INIT; goto on_error; } status = pj_sem_create(stream->pool, NULL, 0, 1, &stream->play_sem); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(stream->pool, "android_track", AndroidTrackCallback, stream, 0, 0, &stream->play_thread); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4, (THIS_FILE, "Audio track initialized successfully.")); } if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) { strm_set_cap(&stream->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, ¶m->output_vol); } /* Done */ stream->base.op = &android_strm_op; *p_aud_strm = &stream->base; detach_jvm(attached); return PJ_SUCCESS; on_error: detach_jvm(attached); strm_destroy(&stream->base); return status; }