static int timer_thread_run(void* p) { pj_time_val tick = {0, 10}; timer_running = 1; while (timer_running) { if (pj_timer_heap_count(timer) == 0) { pj_sem_wait(timer_sem); } else { pj_thread_sleep(PJ_TIME_VAL_MSEC(tick)); pj_timer_heap_poll(timer, NULL); } } pj_timer_heap_destroy(timer); timer = NULL; pj_sem_destroy(timer_sem); timer_sem = NULL; pj_pool_release(timer_pool); timer_pool = NULL; timer_initialized = 0; return 0; }
static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func, void *data, unsigned flags, pj_status_t *retval) { job jb; int tail; if (jq->is_quitting) return PJ_EBUSY; jb.func = func; jb.data = data; jb.flags = flags; pj_mutex_lock(jq->mutex); jq->jobs[jq->tail] = &jb; tail = jq->tail; jq->tail = (jq->tail + 1) % jq->size; pj_sem_post(jq->sem); /* Wait until our posted job is completed. */ pj_sem_wait(jq->job_sem[tail]); pj_mutex_unlock(jq->mutex); if (retval) *retval = jb.retval; return PJ_SUCCESS; }
static int semaphore_test(pj_pool_t *pool) { pj_sem_t *sem; pj_status_t status; PJ_LOG(3,("", "...testing semaphore")); status = pj_sem_create(pool, NULL, 0, 1, &sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_create()", status); return -151; } status = pj_sem_post(sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_post()", status); pj_sem_destroy(sem); return -153; } status = pj_sem_trywait(sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_trywait()", status); pj_sem_destroy(sem); return -156; } status = pj_sem_post(sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_post()", status); pj_sem_destroy(sem); return -159; } status = pj_sem_wait(sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_wait()", status); pj_sem_destroy(sem); return -161; } status = pj_sem_destroy(sem); if (status != PJ_SUCCESS) { app_perror("...error: pj_sem_destroy()", status); return -163; } return 0; }
/* Event worker thread function. */ static int event_worker_thread(void *arg) { pjmedia_event_mgr *mgr = (pjmedia_event_mgr *)arg; while (1) { /* Wait until there is an event. */ pj_sem_wait(mgr->sem); if (mgr->is_quitting) break; pj_mutex_lock(mgr->mutex); event_mgr_distribute_events(mgr, &mgr->ev_queue, &mgr->th_next_sub, PJ_TRUE); pj_mutex_unlock(mgr->mutex); } return 0; }
/* * Lock the mutex for reading. * */ PJ_DEF(pj_status_t) pj_rwmutex_lock_read(pj_rwmutex_t *mutex) { pj_status_t status; PJ_ASSERT_RETURN(mutex, PJ_EINVAL); status = pj_mutex_lock(mutex->read_lock); if (status != PJ_SUCCESS) { pj_assert(!"This pretty much is unexpected"); return status; } mutex->reader_count++; pj_assert(mutex->reader_count < 0x7FFFFFF0L); if (mutex->reader_count == 1) pj_sem_wait(mutex->write_lock); status = pj_mutex_unlock(mutex->read_lock); return status; }
static int job_thread(void * data) { job_queue *jq = (job_queue *)data; while (1) { job *jb; /* Wait until there is a job. */ pj_sem_wait(jq->sem); /* Make sure there is no pending jobs before we quit. */ if (jq->is_quitting && jq->head == jq->tail) break; jb = jq->jobs[jq->head]; jb->retval = (*jb->func)(jb->data); pj_sem_post(jq->job_sem[jq->head]); jq->head = (jq->head + 1) % jq->size; } return 0; }
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; }
static int AndroidTrackCallback(void *userData) { struct android_aud_stream *stream = (struct android_aud_stream*) userData; jmethodID write_method=0, play_method=0, stop_method=0, flush_method=0; int size = stream->play_buf_size; jbyteArray outputBuffer; jbyte *buf; JNIEnv *jni_env = 0; pj_bool_t attached = attach_jvm(&jni_env); if (!stream->track) { goto on_return; } PJ_LOG(5, (THIS_FILE, "Playback thread started")); /* Get methods ids */ write_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "write", "([BII)I"); play_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "play", "()V"); stop_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "stop", "()V"); flush_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "flush", "()V"); if (write_method==0 || play_method==0 || stop_method==0 || flush_method==0) { PJ_LOG(3, (THIS_FILE, "Unable to get audio track methods")); goto on_return; } outputBuffer = (*jni_env)->NewByteArray(jni_env, size); if (outputBuffer == 0) { PJ_LOG(3, (THIS_FILE, "Unable to allocate output buffer")); goto on_return; } buf = (*jni_env)->GetByteArrayElements(jni_env, outputBuffer, 0); /* Start playing */ set_android_thread_priority(THREAD_PRIORITY_URGENT_AUDIO); (*jni_env)->CallVoidMethod(jni_env, stream->track, play_method); while (!stream->quit_flag) { pjmedia_frame frame; pj_status_t status; int bytesWritten; if (!stream->running) { (*jni_env)->CallVoidMethod(jni_env, stream->track, stop_method); (*jni_env)->CallVoidMethod(jni_env, stream->track, flush_method); pj_sem_wait(stream->play_sem); if (stream->quit_flag) break; (*jni_env)->CallVoidMethod(jni_env, stream->track, play_method); } frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.size = size; frame.buf = (void *)buf; frame.timestamp.u64 = stream->play_timestamp.u64; frame.bit_info = 0; status = (*stream->play_cb)(stream->user_data, &frame); if (status != PJ_SUCCESS) continue; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero(frame.buf, frame.size); (*jni_env)->ReleaseByteArrayElements(jni_env, outputBuffer, buf, JNI_COMMIT); /* Write to the device output. */ bytesWritten = (*jni_env)->CallIntMethod(jni_env, stream->track, write_method, outputBuffer, 0, size); if (bytesWritten <= 0 || bytesWritten != size) { PJ_LOG(4, (THIS_FILE, "Player thread: Error %d writing data", bytesWritten)); continue; } stream->play_timestamp.u64 += stream->param.samples_per_frame / stream->param.channel_count; }; (*jni_env)->ReleaseByteArrayElements(jni_env, outputBuffer, buf, 0); (*jni_env)->DeleteLocalRef(jni_env, outputBuffer); on_return: detach_jvm(attached); PJ_LOG(5, (THIS_FILE, "Player thread stopped")); stream->play_thread_exited = 1; return 0; }
static int AndroidRecorderCallback(void *userData) { struct android_aud_stream *stream = (struct android_aud_stream *)userData; jmethodID read_method=0, record_method=0, stop_method=0; int size = stream->rec_buf_size; jbyteArray inputBuffer; jbyte *buf; JNIEnv *jni_env = 0; pj_bool_t attached = attach_jvm(&jni_env); PJ_ASSERT_RETURN(jni_env, 0); if (!stream->record) { goto on_return; } PJ_LOG(5, (THIS_FILE, "Recorder thread started")); /* Get methods ids */ read_method = (*jni_env)->GetMethodID(jni_env, stream->record_class, "read", "([BII)I"); record_method = (*jni_env)->GetMethodID(jni_env, stream->record_class, "startRecording", "()V"); stop_method = (*jni_env)->GetMethodID(jni_env, stream->record_class, "stop", "()V"); if (read_method==0 || record_method==0 || stop_method==0) { PJ_LOG(3, (THIS_FILE, "Unable to get recording methods")); goto on_return; } /* Create a buffer for frames read */ inputBuffer = (*jni_env)->NewByteArray(jni_env, size); if (inputBuffer == 0) { PJ_LOG(3, (THIS_FILE, "Unable to allocate input buffer")); goto on_return; } /* Start recording * setpriority(PRIO_PROCESS, 0, -19); //ANDROID_PRIORITY_AUDIO * set priority is probably not enough because it does not change the thread * group in scheduler * Temporary solution is to call the java api to set the thread priority. * A cool solution would be to port (if possible) the code from the * android os regarding set_sched groups */ set_android_thread_priority(THREAD_PRIORITY_URGENT_AUDIO); (*jni_env)->CallVoidMethod(jni_env, stream->record, record_method); while (!stream->quit_flag) { pjmedia_frame frame; pj_status_t status; int bytesRead; if (!stream->running) { (*jni_env)->CallVoidMethod(jni_env, stream->record, stop_method); pj_sem_wait(stream->rec_sem); if (stream->quit_flag) break; (*jni_env)->CallVoidMethod(jni_env, stream->record, record_method); } bytesRead = (*jni_env)->CallIntMethod(jni_env, stream->record, read_method, inputBuffer, 0, size); if (bytesRead <= 0 || bytesRead != size) { PJ_LOG (4, (THIS_FILE, "Record thread : error %d reading data", bytesRead)); continue; } buf = (*jni_env)->GetByteArrayElements(jni_env, inputBuffer, 0); frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.size = size; frame.bit_info = 0; frame.buf = (void *)buf; frame.timestamp.u64 = stream->rec_timestamp.u64; status = (*stream->rec_cb)(stream->user_data, &frame); (*jni_env)->ReleaseByteArrayElements(jni_env, inputBuffer, buf, JNI_ABORT); stream->rec_timestamp.u64 += stream->param.samples_per_frame / stream->param.channel_count; } (*jni_env)->DeleteLocalRef(jni_env, inputBuffer); on_return: detach_jvm(attached); PJ_LOG(5, (THIS_FILE, "Recorder thread stopped")); stream->rec_thread_exited = 1; return 0; }
/* * Lock the mutex for writing. * */ PJ_DEF(pj_status_t) pj_rwmutex_lock_write(pj_rwmutex_t *mutex) { PJ_ASSERT_RETURN(mutex, PJ_EINVAL); return pj_sem_wait(mutex->write_lock); }
// // Wait semaphore. // pj_status_t wait() { return pj_sem_wait(this->pj_sem_t_()); }