PJ_DEF(Frame_Buffer *) jitter_buffer_getCompleteFrameForDecoding(Jitter_Buffer *jitter_buffer, pj_uint32_t max_wait_time_ms) {
    //running
    if(!jitter_buffer->running)
            return NULL;
    if(pj_mutex_lock(jitter_buffer->jb_mutex) != PJ_SUCCESS) { //error
        return NULL;
    }
    /*{
        char buf[1024];
        getFrameInfo(&jitter_buffer->frameList, &jitter_buffer->decode_state, buf, 1024);
        PJ_LOG(4, (THIS_FILE, "jb status:\n%s\n", buf));
    }*/
    //the first frame must be a key frame
    if(jitter_buffer->decode_state.inited == PJ_FALSE)
        jitter_buffer->waiting_for_key_frame == PJ_TRUE;
    //clean old frames
    CleanOldFrames(jitter_buffer);
    //get complete , continuous frame
    Frame_Buffer * frame = findOldestCompleteContinuousFrame(jitter_buffer);
    //if not got, try to wait a frame
    if(frame == NULL) {
        if(max_wait_time_ms == 0)
            goto ON_RET;
        pj_timestamp current ;
        pj_get_timestamp(&current);
        pj_timestamp end = current;
        pj_add_timestamp32(&end, max_wait_time_ms);
        pj_int32_t wait_time_ms = max_wait_time_ms;
        event_reset(jitter_buffer->packet_event);
        while(wait_time_ms > 0) {
            pj_mutex_unlock(jitter_buffer->jb_mutex);
            if(event_wait(jitter_buffer->packet_event, wait_time_ms) == WAIT_RET_SIGNAL) {
                //incoming a packet
                pj_mutex_lock(jitter_buffer->jb_mutex);
                if(!jitter_buffer->running) //jitter buffer stoped
                    goto ON_RET;
                CleanOldFrames(jitter_buffer);
                frame = findOldestCompleteContinuousFrame(jitter_buffer);
                if(frame != NULL)
                    break;
                pj_get_timestamp(&current);
                int elapsed_msec = pj_elapsed_msec(&current, &end);
                wait_time_ms = elapsed_msec;
            } else {
                pj_mutex_lock(jitter_buffer->jb_mutex); //error or timeout
                break;
            }
        }
    } else
        event_reset(jitter_buffer->packet_event);
    if(frame == NULL)
        goto ON_RET;
    /*if(jitter_buffer->waiting_for_key_frame && !frame->session_info.isKeyFrame) {
        frame = NULL; //not a key frame
        goto ON_RET;
    }*/
    //got one, update jitter
    if(frame->nack_count > 0) {
        jitter_estimator_frameNacked(&jitter_buffer->jitter_estimator); //nacked
    } else {
        //update jitter estimator
        UpdateJitterEstimatorForFrame(jitter_buffer, frame);
    }
    //set frame status
    frame_buffer_setStatus(frame, FRAME_STATUS_DECODING);
    //update decode state
    decode_state_updateFrame(frame, &jitter_buffer->decode_state);
    //waiting for key frame
    if(frame->session_info.isKeyFrame)
        jitter_buffer->waiting_for_key_frame = PJ_FALSE;
    //clean old frames
    CleanOldFrames(jitter_buffer);
    //return frame
    ON_RET:
        pj_mutex_unlock(jitter_buffer->jb_mutex);
        return frame;
}
Exemple #2
0
/*
 * pj_ioqueue_poll()
 *
 */
PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
{
    int i, count, processed;
    int msec;
    //struct epoll_event *events = ioqueue->events;
    //struct queue *queue = ioqueue->queue;
    struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
    struct queue queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
    pj_timestamp t1, t2;
    
    PJ_CHECK_STACK();

    msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;

    TRACE_((THIS_FILE, "start os_epoll_wait, msec=%d", msec));
    pj_get_timestamp(&t1);
 
    //count = os_epoll_wait( ioqueue->epfd, events, ioqueue->max, msec);
    count = os_epoll_wait( ioqueue->epfd, events, PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL, msec);
    if (count == 0) {
#if PJ_IOQUEUE_HAS_SAFE_UNREG
    /* Check the closing keys only when there's no activity and when there are
     * pending closing keys.
     */
    if (count == 0 && !pj_list_empty(&ioqueue->closing_list)) {
	pj_lock_acquire(ioqueue->lock);
	scan_closing_keys(ioqueue);
	pj_lock_release(ioqueue->lock);
    }
#endif
	TRACE_((THIS_FILE, "os_epoll_wait timed out"));
	return count;
    }
    else if (count < 0) {
	TRACE_((THIS_FILE, "os_epoll_wait error"));
	return -pj_get_netos_error();
    }

    pj_get_timestamp(&t2);
    TRACE_((THIS_FILE, "os_epoll_wait returns %d, time=%d usec",
		       count, pj_elapsed_usec(&t1, &t2)));

    /* Lock ioqueue. */
    pj_lock_acquire(ioqueue->lock);

    for (processed=0, i=0; i<count; ++i) {
	pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
				events[i].epoll_data;

	TRACE_((THIS_FILE, "event %d: events=%d", i, events[i].events));

	/*
	 * Check readability.
	 */
	if ((events[i].events & EPOLLIN) && 
	    (key_has_pending_read(h) || key_has_pending_accept(h)) && !IS_CLOSING(h) ) {

#if PJ_IOQUEUE_HAS_SAFE_UNREG
	    increment_counter(h);
#endif
	    queue[processed].key = h;
	    queue[processed].event_type = READABLE_EVENT;
	    ++processed;
	    continue;
	}

	/*
	 * Check for writeability.
	 */
	if ((events[i].events & EPOLLOUT) && key_has_pending_write(h) && !IS_CLOSING(h)) {

#if PJ_IOQUEUE_HAS_SAFE_UNREG
	    increment_counter(h);
#endif
	    queue[processed].key = h;
	    queue[processed].event_type = WRITEABLE_EVENT;
	    ++processed;
	    continue;
	}

#if PJ_HAS_TCP
	/*
	 * Check for completion of connect() operation.
	 */
	if ((events[i].events & EPOLLOUT) && (h->connecting) && !IS_CLOSING(h)) {

#if PJ_IOQUEUE_HAS_SAFE_UNREG
	    increment_counter(h);
#endif
	    queue[processed].key = h;
	    queue[processed].event_type = WRITEABLE_EVENT;
	    ++processed;
	    continue;
	}
#endif /* PJ_HAS_TCP */

	/*
	 * Check for error condition.
	 */
	if ((events[i].events & EPOLLERR) && !IS_CLOSING(h)) {
	    /*
	     * We need to handle this exception event.  If it's related to us
	     * connecting, report it as such.  If not, just report it as a
	     * read event and the higher layers will handle it.
	     */
	    if (h->connecting) {
#if PJ_IOQUEUE_HAS_SAFE_UNREG
		increment_counter(h);
#endif
		queue[processed].key = h;
		queue[processed].event_type = EXCEPTION_EVENT;
		++processed;
	    } else if (key_has_pending_read(h) || key_has_pending_accept(h)) {
#if PJ_IOQUEUE_HAS_SAFE_UNREG
		increment_counter(h);
#endif
		queue[processed].key = h;
		queue[processed].event_type = READABLE_EVENT;
		++processed;
	    }
	    continue;
	}
    }
    for (i=0; i<processed; ++i) {
	if (queue[i].key->grp_lock)
	    pj_grp_lock_add_ref_dbg(queue[i].key->grp_lock, "ioqueue", 0);
    }

    PJ_RACE_ME(5);

    pj_lock_release(ioqueue->lock);

    PJ_RACE_ME(5);

    /* Now process the events. */
    for (i=0; i<processed; ++i) {
	switch (queue[i].event_type) {
        case READABLE_EVENT:
            ioqueue_dispatch_read_event(ioqueue, queue[i].key);
            break;
        case WRITEABLE_EVENT:
            ioqueue_dispatch_write_event(ioqueue, queue[i].key);
            break;
        case EXCEPTION_EVENT:
            ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
            break;
        case NO_EVENT:
            pj_assert(!"Invalid event!");
            break;
        }

#if PJ_IOQUEUE_HAS_SAFE_UNREG
	decrement_counter(queue[i].key);
#endif

	if (queue[i].key->grp_lock)
	    pj_grp_lock_dec_ref_dbg(queue[i].key->grp_lock,
	                            "ioqueue", 0);
    }

    /* Special case:
     * When epoll returns > 0 but no descriptors are actually set!
     */
    if (count > 0 && !processed && msec > 0) {
	pj_thread_sleep(msec);
    }

    pj_get_timestamp(&t1);
    TRACE_((THIS_FILE, "ioqueue_poll() returns %d, time=%d usec",
		       processed, pj_elapsed_usec(&t2, &t1)));

    return processed;
}
static int test_timer_heap(void)
{
    int i, j;
    pj_timer_entry *entry;
    pj_pool_t *pool;
    pj_timer_heap_t *timer;
    pj_time_val delay;
    pj_status_t rc;    int err=0;
    unsigned size, count;

    size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);
    pool = pj_pool_create( mem, NULL, size, 4000, NULL);
    if (!pool) {
	PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",
		  size));
	return -10;
    }

    entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));
    if (!entry)
	return -20;

    for (i=0; i<MAX_COUNT; ++i) {
	entry[i].cb = &timer_callback;
    }
    rc = pj_timer_heap_create(pool, MAX_COUNT, &timer);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: unable to create timer heap", rc);
	return -30;
    }

    count = MIN_COUNT;
    for (i=0; i<LOOP; ++i) {
	int early = 0;
	int done=0;
	int cancelled=0;
	int rc;
	pj_timestamp t1, t2, t_sched, t_cancel, t_poll;
	pj_time_val now, expire;

	pj_gettimeofday(&now);
	pj_srand(now.sec);
	t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;

	// Register timers
	for (j=0; j<(int)count; ++j) {
	    delay.sec = pj_rand() % DELAY;
	    delay.msec = pj_rand() % 1000;

	    // Schedule timer
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_schedule(timer, &entry[j], &delay);
	    if (rc != 0)
		return -40;
	    pj_get_timestamp(&t2);

	    t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);

	    // Poll timers.
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_poll(timer, NULL);
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
		early += rc;
	    }
	}

	// Set the time where all timers should finish
	pj_gettimeofday(&expire);
	delay.sec = DELAY; 
	delay.msec = 0;
	PJ_TIME_VAL_ADD(expire, delay);

	// Wait unfil all timers finish, cancel some of them.
	do {
	    int index = pj_rand() % count;
	    pj_get_timestamp(&t1);
	    rc = pj_timer_heap_cancel(timer, &entry[index]);
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		cancelled += rc;
		t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);
	    }

	    pj_gettimeofday(&now);

	    pj_get_timestamp(&t1);
#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
	    /* On Symbian, we must use OS poll (Active Scheduler poll) since 
	     * timer is implemented using Active Object.
	     */
	    rc = 0;
	    while (pj_symbianos_poll(-1, 0))
		++rc;
#else
	    rc = pj_timer_heap_poll(timer, NULL);
#endif
	    pj_get_timestamp(&t2);
	    if (rc > 0) {
		done += rc;
		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
	    }

	} while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);

	if (pj_timer_heap_count(timer)) {
	    PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", 
		       pj_timer_heap_count(timer)));
	    ++err;
	}
	t_sched.u32.lo /= count; 
	t_cancel.u32.lo /= count;
	t_poll.u32.lo /= count;
	PJ_LOG(4, (THIS_FILE, 
	        "...ok (count:%d, early:%d, cancelled:%d, "
		"sched:%d, cancel:%d poll:%d)", 
		count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,
		t_poll.u32.lo));

	count = count * 2;
	if (count > MAX_COUNT)
	    break;
    }

    pj_pool_release(pool);
    return err;
}
Exemple #4
0
int timestamp_test(void)
{
    enum { CONSECUTIVE_LOOP = 100 };
    volatile unsigned i;
    pj_timestamp freq, t1, t2;
    pj_time_val tv1, tv2;
    unsigned elapsed;
    pj_status_t rc;

    PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)"));
    
    /* Get and display timestamp frequency. */
    if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) {
	app_perror("...ERROR: get timestamp freq", rc);
	return -1000;
    }

    PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu", 
			freq.u32.hi, freq.u32.lo));

    PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait).."));

    /*
     * Check if consecutive readings should yield timestamp value
     * that is bigger than previous value.
     * First we get the first timestamp.
     */
    rc = pj_get_timestamp(&t1);
    if (rc != PJ_SUCCESS) {
	app_perror("...ERROR: pj_get_timestamp", rc);
	return -1001;
    }
    rc = pj_gettimeofday(&tv1);
    if (rc != PJ_SUCCESS) {
	app_perror("...ERROR: pj_gettimeofday", rc);
	return -1002;
    }
    for (i=0; i<CONSECUTIVE_LOOP; ++i) {
        
        pj_thread_sleep(pj_rand() % 100);

	rc = pj_get_timestamp(&t2);
	if (rc != PJ_SUCCESS) {
	    app_perror("...ERROR: pj_get_timestamp", rc);
	    return -1003;
	}
	rc = pj_gettimeofday(&tv2);
	if (rc != PJ_SUCCESS) {
	    app_perror("...ERROR: pj_gettimeofday", rc);
	    return -1004;
	}

	/* compare t2 with t1, expecting t2 >= t1. */
	if (t2.u32.hi < t1.u32.hi ||
	    (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo))
	{
	    PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp run backwards!"));
	    return -1005;
	}

	/* compare tv2 with tv1, expecting tv2 >= tv1. */
	if (PJ_TIME_VAL_LT(tv2, tv1)) {
	    PJ_LOG(3,(THIS_FILE, "...ERROR: time run backwards!"));
	    return -1006;
	}
    }

    /* 
     * Simple test to time some loop. 
     */
    PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop"));


    /* Mark start time. */
    if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) {
	app_perror("....error: cat't get timestamp", rc);
	return -1010;
    }

    /* Loop.. */
    for (i=0; i<1000000; ++i) {
	/* Try to do something so that smart compilers wont
	 * remove this silly loop.
	 */
	null_func();
    }

    pj_thread_sleep(0);

    /* Mark end time. */
    pj_get_timestamp(&t2);

    /* Get elapsed time in usec. */
    elapsed = pj_elapsed_usec(&t1, &t2);
    PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed));

    /* See if elapsed time is "reasonable". 
     * This should be good even on 50Mhz embedded powerpc.
     */
    if (elapsed < 1 || elapsed > 1000000) {
	PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, "
			     "t1.u32.hi=%u, t1.u32.lo=%u, "
			     "t2.u32.hi=%u, t2.u32.lo=%u)",
			     elapsed, 
			     t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo));
	return -1030;
    }

    /* Testing time/timestamp accuracy */
    rc = timestamp_accuracy();
    if (rc != 0)
	return rc;

    return 0;
}
Exemple #5
0
/*
 * Get NTP time.
 */
PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
					      pjmedia_rtcp_ntp_rec *ntp)
{
/* Seconds between 1900-01-01 to 1970-01-01 */
#define JAN_1970  (2208988800UL)
    pj_timestamp ts;
    pj_status_t status;

    status = pj_get_timestamp(&ts);

    /* Fill up the high 32bit part */
    ntp->hi = (pj_uint32_t)((ts.u64 - sess->ts_base.u64) / sess->ts_freq.u64)
	      + sess->tv_base.sec + JAN_1970;

    /* Calculate seconds fractions */
    ts.u64 = (ts.u64 - sess->ts_base.u64) % sess->ts_freq.u64;
    pj_assert(ts.u64 < sess->ts_freq.u64);
    ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64;

    /* Fill up the low 32bit part */
    ntp->lo = ts.u32.lo;


#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
    (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0)

    /* On Win32, since we use QueryPerformanceCounter() as the backend
     * timestamp API, we need to protect against this bug:
     *   Performance counter value may unexpectedly leap forward
     *   http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323
     */
    {
	/*
	 * Compare elapsed time reported by timestamp with actual elapsed 
	 * time. If the difference is too excessive, then we use system
	 * time instead.
	 */

	/* MIN_DIFF needs to be large enough so that "normal" diff caused
	 * by system activity or context switch doesn't trigger the time
	 * correction.
	 */
	enum { MIN_DIFF = 400 };

	pj_time_val ts_time, elapsed, diff;

	pj_gettimeofday(&elapsed);

	ts_time.sec = ntp->hi - sess->tv_base.sec - JAN_1970;
	ts_time.msec = (long)(ntp->lo * 1000.0 / 0xFFFFFFFF);

	PJ_TIME_VAL_SUB(elapsed, sess->tv_base);

	if (PJ_TIME_VAL_LT(ts_time, elapsed)) {
	    diff = elapsed;
	    PJ_TIME_VAL_SUB(diff, ts_time);
	} else {
	    diff = ts_time;
	    PJ_TIME_VAL_SUB(diff, elapsed);
	}

	if (PJ_TIME_VAL_MSEC(diff) >= MIN_DIFF) {

	    TRACE_((sess->name, "RTCP NTP timestamp corrected by %d ms",
		    PJ_TIME_VAL_MSEC(diff)));


	    ntp->hi = elapsed.sec + sess->tv_base.sec + JAN_1970;
	    ntp->lo = (elapsed.msec * 65536 / 1000) << 16;
	}

    }
#endif

    return status;
}
static int PJ_THREAD_FUNC AndroidRecorderCallback(void* userData){
	struct android_aud_stream *stream = (struct android_aud_stream*) userData;
	JNIEnv *jni_env = 0;
	ATTACH_JVM(jni_env);

	jmethodID read_method=0, record_method=0;
	int bytesRead;
	int size =  stream->samples_per_frame * stream->bytes_per_sample;
	int nframes = stream->samples_per_frame / stream->channel_count;
	jbyte* buf;
	pj_status_t status = 0;
	jbyteArray inputBuffer;
	pj_timestamp tstamp, now, last_frame;

	int elapsed_time = 0;
	//Frame time in ms
	int frame_time = nframes * 1000 / stream->samples_per_sec;
	int missed_time = frame_time;
	int to_wait = 0;

	PJ_LOG(3,(THIS_FILE, "<< Enter recorder thread"));

	if(!stream->record){
		goto on_break;
	}


	//Get methods ids
	read_method = jni_env->GetMethodID(stream->record_class,"read", "([BII)I");
	record_method = jni_env->GetMethodID(stream->record_class,"startRecording", "()V");
	if(read_method==0 || record_method==0) {
		goto on_break;
	}

	//Create a buffer for frames read
	inputBuffer = jni_env->NewByteArray(size);
	if (inputBuffer == 0) {
		PJ_LOG(2, (THIS_FILE, "Not able to allocate a buffer for input read process"));
		goto on_break;
	}


	//start recording
	//setpriority(PRIO_PROCESS, 0, -19 /*ANDROID_PRIORITY_AUDIO*/);
	// set priority is probably not enough cause 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);

	buf = jni_env->GetByteArrayElements(inputBuffer, 0);

	//Init everything
	tstamp.u64 = 0;
	pj_bzero (buf, size);


	jni_env->CallVoidMethod(stream->record, record_method);
	pj_get_timestamp(&last_frame);

	while ( !stream->quit_flag ) {
		pj_bzero (buf, size);

#if COMPATIBLE_ALSA
		pj_get_timestamp(&now);
		// Time between now and last frame next frame (ms)
		elapsed_time = pj_elapsed_msec(&last_frame, &now);

		pj_get_timestamp(&last_frame);

		//PJ_LOG (4, (THIS_FILE, "Elapsed time is %d | missed time is %d | frame time %d", elapsed_time, missed_time, frame_time));
		//Update missed time
		// Positif if we are late
		// negatif if we are earlier
		// dividing by 2 is empiric result
		// on N1 if not we get buffer overflow I assume that it fill packets faster than the frequency
		missed_time =  missed_time/2 + elapsed_time - frame_time;

		//PJ_LOG (4, (THIS_FILE, "And now :: Elapsed time is %d | missed time is %d", elapsed_time, missed_time));

		//If we go faster than the buffer filling we have to wait no
		if( missed_time <= 0 ){
			//if(elapsed_time < frame_time){
				to_wait = - missed_time - 2;
				if(to_wait > 0){
			//		PJ_LOG (4, (THIS_FILE, "Wait for %d / %d", to_wait, frame_time));
					pj_thread_sleep(to_wait);
				}
			//}
		}
/*
		//PJ_LOG (4, (THIS_FILE, "Next frame %d", next_frame_in));
		if (next_frame_in-2 > 0) {
			//PJ_LOG (4, (THIS_FILE, "Wait for buffer %d", next_frame_in));
			pj_thread_sleep(next_frame_in-5);
			//Reset the delay we have regarding next frame
			retard = 0;
		}else{
			if(next_frame_in < 0){
				retard += next_frame_in;
			}
		}
*/
#endif

		bytesRead = jni_env->CallIntMethod(stream->record, read_method,
					inputBuffer,
					0,
					size);


		if(bytesRead<=0){
			PJ_LOG (3, (THIS_FILE, "Record thread : error while reading data... is there something we can do here? %d", bytesRead));
			continue;
		}
		if(stream->quit_flag){
			break;
		}
		if(bytesRead != size){
			PJ_LOG(3, (THIS_FILE, "Overrun..."));
			continue;
		}

	//	PJ_LOG(4,(THIS_FILE, "Valid record frame read"));
		//jni_env->GetByteArrayRegion(inputBuffer, 0, size, buf );

		pjmedia_frame frame;

		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
		frame.size =  size;
		frame.bit_info = 0;
		frame.buf = (void*) buf;
		frame.timestamp.u64 = tstamp.u64;

	//	PJ_LOG(3, (THIS_FILE, "New audio record frame to treat : %d <size : %d>", frame.type, frame.size));

		status = (*stream->rec_cb)(stream->user_data, &frame);
	//	PJ_LOG(4,(THIS_FILE, "Valid record frame sent to network stack"));

		if (status != PJ_SUCCESS){
			PJ_LOG(1, (THIS_FILE, "Error in record callback"));
			goto on_finish;
		}


		//Update for next step
		tstamp.u64 += nframes;
	};


	on_finish:
		jni_env->ReleaseByteArrayElements(inputBuffer, buf, 0);
		jni_env->DeleteLocalRef(inputBuffer);

	on_break:
		DETACH_JVM(jni_env);
		PJ_LOG(3,(THIS_FILE, ">> Record thread stopped"));
//		pj_sem_post(stream->audio_launch_sem);
		stream->rec_thread_exited = 1;
		return 0;
}
Exemple #7
0
static int test(void)
{
    pj_rbtree rb;
    node_key *key;
    pj_rbtree_node *node;
    pj_pool_t *pool;
    int err=0;
    int count = MIN_COUNT;
    int i;
    unsigned size;

    pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);
    size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) + 
			   PJ_RBTREE_SIZE + PJ_POOL_SIZE;
    pool = pj_pool_create( mem, "pool", size, 0, NULL);
    if (!pool) {
	PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));
	return -10;
    }

    key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));
    if (!key)
	return -20;

    node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));
    if (!node)
	return -30;

    for (i=0; i<LOOP; ++i) {
	int j;
	pj_rbtree_node *prev, *it;
	pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;

	pj_assert(rb.size == 0);

	t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;

	for (j=0; j<count; j++) {
	    randomize_string(key[j].str, STRSIZE);

	    pj_get_timestamp(&t1);
	    node[j].key = &key[j];
	    node[j].user_data = key[j].str;
	    key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);
	    pj_get_timestamp(&t2);
	    t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);

	    pj_get_timestamp(&t1);
	    pj_rbtree_insert(&rb, &node[j]);
	    pj_get_timestamp(&t2);
	    t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);
	}

	pj_assert(rb.size == (unsigned)count);

	// Iterate key, make sure they're sorted.
	prev = NULL;
	it = pj_rbtree_first(&rb);
	while (it) {
	    if (prev) {
		if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {
		    ++err;
		    PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", 
			       (char*)prev->user_data, (char*)it->user_data));
		}
	    }
	    prev = it;
	    it = pj_rbtree_next(&rb, it);
	}

	// Search.
	for (j=0; j<count; j++) {
	    pj_get_timestamp(&t1);
	    it = pj_rbtree_find(&rb, &key[j]);
	    pj_get_timestamp(&t2);
	    t_search.u32.lo += (t2.u32.lo - t1.u32.lo);

	    pj_assert(it != NULL);
	    if (it == NULL)
		++err;
	}

	// Erase node.
	for (j=0; j<count; j++) {
	    pj_get_timestamp(&t1);
	    it = pj_rbtree_erase(&rb, &node[j]);
	    pj_get_timestamp(&t2);
	    t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);
	}

	PJ_LOG(4, (THIS_FILE, 
		"...count:%d, setup:%d, insert:%d, search:%d, erase:%d",
		count,
		t_setup.u32.lo / count, t_insert.u32.lo / count,
		t_search.u32.lo / count, t_erase.u32.lo / count));

	count = 2 * count;
	if (count > MAX_COUNT)
	    break;
    }

    pj_pool_release(pool);
    return err;
}
Exemple #8
0
int expand(pj_pool_t *pool, const char *filein, const char *fileout,
	   int expansion_rate100, int lost_rate10, int lost_burst)
{
    enum { LOST_RATE = 10 };
    FILE *in, *out;
    short frame[SAMPLES_PER_FRAME];
    pjmedia_wsola *wsola;
    pj_timestamp elapsed, zero;
    unsigned samples;
    int last_lost = 0;

    /* Lost burst must be > 0 */
    assert(lost_rate10==0 || lost_burst > 0);

    in = fopen(filein, "rb");
    if (!in) return 1;
    out = fopen(fileout, "wb");
    if (!out) return 1;

    pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola);

    samples = 0;
    elapsed.u64 = 0;

    while (fread(frame, SAMPLES_PER_FRAME*2, 1, in) == 1) {
	pj_timestamp t1, t2;

	if (lost_rate10 == 0) {

	    /* Expansion */
	    pj_get_timestamp(&t1);
	    pjmedia_wsola_save(wsola, frame, 0);
	    pj_get_timestamp(&t2);

	    pj_sub_timestamp(&t2, &t1);
	    pj_add_timestamp(&elapsed, &t2);

	    fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);

	    samples += SAMPLES_PER_FRAME;

	    if ((rand() % 100) < expansion_rate100) {

		pj_get_timestamp(&t1);
		pjmedia_wsola_generate(wsola, frame);
		pj_get_timestamp(&t2);

		pj_sub_timestamp(&t2, &t1);
		pj_add_timestamp(&elapsed, &t2);
    
		samples += SAMPLES_PER_FRAME;

		fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
	    } 

	} else {
	    /* Lost */

	    if ((rand() % 10) < lost_rate10) {
		int burst;

		for (burst=0; burst<lost_burst; ++burst) {
		    pj_get_timestamp(&t1);
		    pjmedia_wsola_generate(wsola, frame);
		    pj_get_timestamp(&t2);

		    pj_sub_timestamp(&t2, &t1);
		    pj_add_timestamp(&elapsed, &t2);

		    samples += SAMPLES_PER_FRAME;

		    fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
		}
		last_lost = 1;
	    } else {
		pj_get_timestamp(&t1);
		pjmedia_wsola_save(wsola, frame, last_lost);
		pj_get_timestamp(&t2);

		pj_sub_timestamp(&t2, &t1);
		pj_add_timestamp(&elapsed, &t2);

		samples += SAMPLES_PER_FRAME;

		fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
		last_lost = 0;
	    }

	}

    }

    zero.u64 = 0;
    zero.u64 = pj_elapsed_usec(&zero, &elapsed);
    
    zero.u64 = samples * PJ_INT64(1000000) / zero.u64;
    assert(zero.u32.hi == 0);

    PJ_LOG(3,("test.c", "Processing: %f Msamples per second", 
	      zero.u32.lo/1000000.0));
    PJ_LOG(3,("test.c", "CPU load for current settings: %f%%",
	      CLOCK_RATE * 100.0 / zero.u32.lo));

    pjmedia_wsola_destroy(wsola);
    fclose(in);
    fclose(out);

    return 0;
}
Exemple #9
0
int CChannel::sendto(const sockaddr* addr, CPacket& packet) const
{

   // convert control information into network order
   if (packet.getFlag()) {
      for (int i = 0, n = packet.getLength() / 4; i < n; ++ i)
         *((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcData + i));
   } 

   uint32_t* p = packet.m_nHeader;
   for (int j = 0; j < 4; ++ j)
   {
      *p = htonl(*p);
      ++ p;
   }

#ifdef DEBUGP
   //dump ctrl packet
    printf("\nSend Header:\n");
    dumpHex((char *)packet.m_PacketVector[0].iov_base, packet.m_PacketVector[0].iov_len);
   char *bb = (char *)packet.m_PacketVector[0].iov_base;
   if(bb[0]&0x80) {
      printf("Data:\n");
      dumpHex((char *)packet.m_PacketVector[1].iov_base, packet.m_PacketVector[1].iov_len);
      printf("================\n");
   }
#endif

   int res = -1;
   unsigned size;
   unsigned len;
   natnl_hdr hdr = {0xff, 0x00, 0x0000};
   int is_tnl_data = 0;
   pj_thread_desc desc;
   pj_thread_t *thread = 0;

   if(m_iSocket == -1) {
      pjsua_call *call = (pjsua_call *)m_call;
	  if(call == NULL) return -1;

	  // DEAN, prevent assert fail while garbage collector remove UDT socket on multiple instance. 
	  if (!pj_thread_is_registered(call->inst_id)) {
		  int status = pj_thread_register(call->inst_id, "CChannel::sendto", desc, &thread );
		  if (status != PJ_SUCCESS)
			  return -1;
	  }

	  pj_mutex_lock(call->tnl_stream_lock2);

	  natnl_stream *stream = (natnl_stream *)call->tnl_stream;
	  if(stream == NULL) {
	     pj_mutex_unlock(call->tnl_stream_lock2);
	     return -1;
	  }

     size = CPacket::m_iPktHdrSize + packet.getLength() + sizeof(natnl_hdr);
     len = (CPacket::m_iPktHdrSize + packet.getLength());
	  hdr.length = htons(len);

      memcpy((char *)&m_pktBuffer[sizeof(natnl_hdr)], packet.m_PacketVector[0].iov_base, packet.m_PacketVector[0].iov_len);
      memcpy((char *)&m_pktBuffer[packet.m_PacketVector[0].iov_len+sizeof(natnl_hdr)], packet.m_PacketVector[1].iov_base, packet.m_PacketVector[1].iov_len);
      memcpy((char *)&m_pktBuffer[0], &hdr, sizeof(natnl_hdr));

resend:
	  // DEAN, check if this is tunnel data. If true, update last_data time.
	  is_tnl_data = pjmedia_natnl_udt_packet_is_tnl_data(&m_pktBuffer[0], size);

	  pj_assert(size < sizeof(m_pktBuffer));
		
	  ((pj_uint8_t*)m_pktBuffer)[size] = 0;  // tunnel data flag off

	  if (is_tnl_data) {
		  pj_get_timestamp(&stream->last_data);  // DEAN save current time 
		  ((pj_uint8_t*)m_pktBuffer)[size] = 1;  // tunnel data flag on
	  }

	  res = pjmedia_transport_send_rtp(stream->med_tp, m_pktBuffer, size);	// +Roger modified - stream pointer to med_tp
#if 0 // No need to resend it, because UDT will handle this.
	  if(res == 70011) { //EAGAIN
		  m_pTimer->sleepto(50000); //sleep for 50 us
	      goto resend;   
      }
#endif
      pj_mutex_unlock(call->tnl_stream_lock2);
   }
   res = (0 == res) ? size : -1;

   // convert back into local host order
   //for (int k = 0; k < 4; ++ k)
   //   packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]);
   p = packet.m_nHeader;
   for (int k = 0; k < 4; ++ k)
   {
      *p = ntohl(*p);
       ++ p;
   }

   if (packet.getFlag())
   {
      for (int l = 0, n = packet.getLength() / 4; l < n; ++ l)
         *((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcData + l));
   }

   return res;
}
Exemple #10
0
pj_status_t latency_checker::start(latency_config_t &config)
{
	pj_status_t result = PJ_EINVAL;
	if(m_pool == NULL)
	{
		m_dstate = 0;
		m_start_tone_time.u64 = 0;
		m_latency = 0;
		m_quality = 0;
		m_config = config;
		m_status_string[0] = 0;
		m_gain = new snd_agc("",30,1,32000,32000);
		m_idle_freq1_det = new tone_detector(m_config.clock_rate,IDLE_FREQ1);
		m_idle_freq2_det = new tone_detector(m_config.clock_rate,IDLE_FREQ2);
		m_active_freq1_det = new tone_detector(m_config.clock_rate,ACTIVE_FREQ1);
		m_active_freq2_det = new tone_detector(m_config.clock_rate,ACTIVE_FREQ2);

		init_generate_dual_tone(&m_idle_tone,m_config.clock_rate,IDLE_FREQ1,IDLE_FREQ2,32767);
		init_generate_dual_tone(&m_active_tone,m_config.clock_rate,ACTIVE_FREQ1,ACTIVE_FREQ2,32767);
		pj_log_set_level(0);
		pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC);
		if(pj_init()==PJ_SUCCESS)
		{
			m_caching_pool = (pj_caching_pool *)malloc(sizeof(pj_caching_pool));
			pj_caching_pool_init( m_caching_pool, NULL, 0 );
			m_pool_factory=&m_caching_pool->factory;
			m_pool = pj_pool_create(m_pool_factory, "LATENCY NATIVE", 4000, 4000, NULL);
			pj_log_set_level(m_config.logs.level);
			pj_logging_init(m_pool);
			pj_logging_setLogToConsole(1);

			pj_logging_setFilename(m_config.logs.file_name);
			pj_logging_setMaxLogFiles(m_config.logs.max_files);
			pj_logging_setMaxLogFileSize(m_config.logs.max_file_size*1024*1024);
			pj_logging_start();

			pj_get_timestamp(&m_last_get_frame_time);

			m_lock = new PPJ_SemaphoreLock(m_pool,NULL,1,1);

			pjmedia_aud_subsys_init(m_pool_factory);
#if PJMEDIA_AUDIO_DEV_HAS_ANDROID
#if PJ_ANDROID_DEVICE==1
			pjmedia_aud_register_factory(&pjmedia_android_factory);
#endif
#if PJ_ANDROID_DEVICE==2
			pjmedia_aud_register_factory(&pjmedia_opensl_factory);
#endif
#if PJ_ANDROID_DEVICE==3
			pjmedia_aud_register_factory(&pjmedia_alsa_factory);
#endif
#endif

			pjmedia_aud_param params;
			params.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
			params.rec_id = 1;
			params.play_id = 6;
			params.clock_rate = m_config.clock_rate;
			params.channel_count = 1;
			params.samples_per_frame = m_config.min_frame_length*m_config.clock_rate/1000;
			params.bits_per_sample = 16;
			params.flags = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
			params.input_latency_ms = m_config.min_frame_length;
			params.output_latency_ms = m_config.min_frame_length;
			result = pjmedia_aud_stream_create(&params,&rec_cb_s,&play_cb_s,this,&m_aud_stream);

			if(result==PJ_SUCCESS)
			{
				result = pjmedia_aud_stream_start(m_aud_stream);
				if(result==PJ_SUCCESS)
				{


				}

			}
		}
	}

	if(result!=PJ_SUCCESS)
		internal_clean();
	return result;
}
Exemple #11
0
int compress(pj_pool_t *pool, 
	     const char *filein, const char *fileout, 
	     int rate10)
{
    enum { BUF_CNT = SAMPLES_PER_FRAME * 10 };
    FILE *in, *out;
    pjmedia_wsola *wsola;
    short buf[BUF_CNT];
    pj_timestamp elapsed, zero;
    unsigned samples = 0;
    
    in = fopen(filein, "rb");
    if (!in) return 1;
    out = fopen(fileout, "wb");
    if (!out) return 1;

    pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola);

    elapsed.u64 = 0;

    for (;;) {
	unsigned size_del, count;
	pj_timestamp t1, t2;
	int i;

	if (fread(buf, sizeof(buf), 1, in) != 1)
	    break;

	count = BUF_CNT;
	size_del = 0;
	pj_get_timestamp(&t1);

	for (i=0; i<rate10; ++i) {
	    unsigned to_del = SAMPLES_PER_FRAME;
#if 0
	    /* Method 1: buf1 contiguous */
	    pjmedia_wsola_discard(wsola, buf, count, NULL, 0, &to_del);
#elif 0
	    /* Method 2: split, majority in buf1 */
	    assert(count > SAMPLES_PER_FRAME);
	    pjmedia_wsola_discard(wsola, buf, count-SAMPLES_PER_FRAME, 
				  buf+count-SAMPLES_PER_FRAME, SAMPLES_PER_FRAME, 
				  &to_del);
#elif 0
	    /* Method 3: split, majority in buf2 */
	    assert(count > SAMPLES_PER_FRAME);
	    pjmedia_wsola_discard(wsola, buf, SAMPLES_PER_FRAME, 
				  buf+SAMPLES_PER_FRAME, count-SAMPLES_PER_FRAME, 
				  &to_del);
#elif 1
	    /* Method 4: split, each with small length */
	    enum { TOT_LEN = 3 * SAMPLES_PER_FRAME };
	    unsigned buf1_len = (rand() % TOT_LEN);
	    short *ptr = buf + count - TOT_LEN;
	    assert(count > TOT_LEN);
	    if (buf1_len==0) buf1_len=SAMPLES_PER_FRAME*2;
	    pjmedia_wsola_discard(wsola, ptr, buf1_len, 
				  ptr+buf1_len, TOT_LEN-buf1_len, 
				  &to_del);
#endif
	    count -= to_del;
	    size_del += to_del;
	}
	pj_get_timestamp(&t2);
	
	samples += BUF_CNT;

	pj_sub_timestamp(&t2, &t1);
	pj_add_timestamp(&elapsed, &t2);

	assert(size_del >= SAMPLES_PER_FRAME);

	fwrite(buf, count, 2, out);
    }

    pjmedia_wsola_destroy(wsola);
    fclose(in);
    fclose(out);

    zero.u64 = 0;
    zero.u64 = pj_elapsed_usec(&zero, &elapsed);
    
    zero.u64 = samples * PJ_INT64(1000000) / zero.u64;
    assert(zero.u32.hi == 0);

    PJ_LOG(3,("test.c", "Processing: %f Msamples per second", 
	      zero.u32.lo/1000000.0));
    PJ_LOG(3,("test.c", "CPU load for current settings: %f%%",
	      CLOCK_RATE * 100.0 / zero.u32.lo));

    return 0;
}
Exemple #12
0
    pj_status_t get_timestamp()
    {
	return pj_get_timestamp(&ts_);
    }
Exemple #13
0
static int sleep_duration_test(void)
{
    enum { MIS = 20};
    unsigned duration[] = { 2000, 1000, 500, 200, 100 };
    unsigned i;
    pj_status_t rc;

    PJ_LOG(3,(THIS_FILE, "..running sleep duration test"));

    /* Test pj_thread_sleep() and pj_gettimeofday() */
    for (i=0; i<PJ_ARRAY_SIZE(duration); ++i) {
        pj_time_val start, stop;
	pj_uint32_t msec;

        /* Mark start of test. */
        rc = pj_gettimeofday(&start);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: pj_gettimeofday()", rc);
            return -10;
        }

        /* Sleep */
        rc = pj_thread_sleep(duration[i]);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: pj_thread_sleep()", rc);
            return -20;
        }

        /* Mark end of test. */
        rc = pj_gettimeofday(&stop);

        /* Calculate duration (store in stop). */
        PJ_TIME_VAL_SUB(stop, start);

	/* Convert to msec. */
	msec = PJ_TIME_VAL_MSEC(stop);

	/* Check if it's within range. */
	if (msec < duration[i] * (100-MIS)/100 ||
	    msec > duration[i] * (100+MIS)/100)
	{
	    PJ_LOG(3,(THIS_FILE, 
		      "...error: slept for %d ms instead of %d ms "
		      "(outside %d%% err window)",
		      msec, duration[i], MIS));
	    return -30;
	}
    }


    /* Test pj_thread_sleep() and pj_get_timestamp() and friends */
    for (i=0; i<PJ_ARRAY_SIZE(duration); ++i) {
	pj_time_val t1, t2;
        pj_timestamp start, stop;
	pj_uint32_t msec;

	pj_thread_sleep(0);

        /* Mark start of test. */
        rc = pj_get_timestamp(&start);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: pj_get_timestamp()", rc);
            return -60;
        }

	/* ..also with gettimeofday() */
	pj_gettimeofday(&t1);

        /* Sleep */
        rc = pj_thread_sleep(duration[i]);
        if (rc != PJ_SUCCESS) {
            app_perror("...error: pj_thread_sleep()", rc);
            return -70;
        }

        /* Mark end of test. */
        pj_get_timestamp(&stop);

	/* ..also with gettimeofday() */
	pj_gettimeofday(&t2);

	/* Compare t1 and t2. */
	if (PJ_TIME_VAL_LT(t2, t1)) {
	    PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!"));
	    return -75;
	}

        /* Get elapsed time in msec */
        msec = pj_elapsed_msec(&start, &stop);

	/* Check if it's within range. */
	if (msec < duration[i] * (100-MIS)/100 ||
	    msec > duration[i] * (100+MIS)/100)
	{
	    PJ_LOG(3,(THIS_FILE, 
		      "...error: slept for %d ms instead of %d ms "
		      "(outside %d%% err window)",
		      msec, duration[i], MIS));
	    PJ_TIME_VAL_SUB(t2, t1);
	    PJ_LOG(3,(THIS_FILE, 
		      "...info: gettimeofday() reported duration is "
		      "%d msec",
		      PJ_TIME_VAL_MSEC(t2)));

	    return -76;
	}
    }

    /* All done. */
    return 0;
}
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;
}
Exemple #15
0
static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed)
{
    unsigned i;
    pjsip_tx_data *request;
    pjsip_via_hdr *via;
    pjsip_rx_data rdata;
    pj_sockaddr_in remote;
    pjsip_transaction **tsx;
    pj_timestamp t1, t2, elapsed;
    char branch_buf[80] = PJSIP_RFC3261_BRANCH_ID "0000000000";
    pj_status_t status;

    /* Create the request first. */
    pj_str_t str_target = pj_str("sip:[email protected]");
    pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>");
    pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>");
    pj_str_t str_contact = str_from;

    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
					&str_target, &str_from, &str_to,
					&str_contact, NULL, -1, NULL,
					&request);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create request", status);
	return status;
    }

    /* Create  Via */
    via = pjsip_via_hdr_create(request->pool);
    via->sent_by.host = pj_str("192.168.0.7");
    via->sent_by.port = 5061;
    via->transport = pj_str("udp");
    via->rport_param = 1;
    via->recvd_param = pj_str("192.168.0.7");
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via);
    

    /* Create "dummy" rdata from the tdata */
    pj_bzero(&rdata, sizeof(pjsip_rx_data));
    rdata.tp_info.pool = request->pool;
    rdata.msg_info.msg = request->msg;
    rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL);
    rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL);
    rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.via = via;
    
    pj_sockaddr_in_init(&remote, 0, 0);
    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, 
					   &remote, sizeof(pj_sockaddr_in),
					   NULL, &rdata.tp_info.transport);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to get loop transport", status);
	return status;
    }


    /* Create transaction array */
    tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*));

    pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user));
    mod_tsx_user.id = -1;


    /* Benchmark */
    elapsed.u64 = 0;
    pj_get_timestamp(&t1);
    for (i=0; i<working_set; ++i) {
	via->branch_param.ptr = branch_buf;
	via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + 
				    pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN,
						    "-%d", i);
	status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]);
	if (status != PJ_SUCCESS)
	    goto on_error;

    }
    pj_get_timestamp(&t2);
    pj_sub_timestamp(&t2, &t1);
    pj_add_timestamp(&elapsed, &t2);

    p_elapsed->u64 = elapsed.u64;
    status = PJ_SUCCESS;
    
on_error:
    for (i=0; i<working_set; ++i) {
	if (tsx[i]) {
	    pjsip_tsx_terminate(tsx[i], 601);
	    tsx[i] = NULL;
	}
    }
    pjsip_tx_data_dec_ref(request);
    flush_events(2000);
    return status;
}
static pj_status_t check_new_decode_result(pjmedia_vid_codec *codec,
				       SBufferInfo *bufferInfo,
					   const pj_timestamp *ts,
				       pj_bool_t got_keyframe)
{
    openh264_private *ff = (openh264_private*)codec->codec_data;
    pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
    pjmedia_event event;

    /* Check for format change.
     * Decoder output format is set by libavcodec, in case it is different
     * to the configured param.
     */
    if (bufferInfo->UsrData.sSystemBuffer.iWidth != (int)vafp->size.w ||
		bufferInfo->UsrData.sSystemBuffer.iHeight != (int)vafp->size.h)
	{
		pj_status_t status;

		/* Update decoder format in param */
		ff->param.dec_fmt.id = PJMEDIA_FORMAT_I420;
		ff->param.dec_fmt.det.vid.size.w = bufferInfo->UsrData.sSystemBuffer.iWidth;
		ff->param.dec_fmt.det.vid.size.h = bufferInfo->UsrData.sSystemBuffer.iHeight;

		/* Re-init format info and apply-param of decoder */
		ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
		if (!ff->dec_vfi)
			return PJ_ENOTSUP;
		pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
		ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
		ff->dec_vafp.buffer = NULL;
		status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
		if (status != PJ_SUCCESS)
			return status;

		/* Realloc buffer if necessary */
		if (ff->dec_vafp.framebytes > ff->dec_buf_size) {
			PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u",
				   (unsigned)ff->dec_buf_size,
				   (unsigned)ff->dec_vafp.framebytes));
			ff->dec_buf_size = ff->dec_vafp.framebytes;
			ff->unaligned_dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
			ff->dec_buf = align_buffer_16(ff->unaligned_dec_buf);
		}

		/* Broadcast format changed event */
		pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
		event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
		pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param.dec_fmt,
			  sizeof(ff->param.dec_fmt));
		pjmedia_event_publish(NULL, codec, &event, 0);
    }

    /* Check for missing/found keyframe */
    if (got_keyframe) {
		pj_get_timestamp(&ff->last_dec_keyframe_ts);

	/* Broadcast keyframe event */
        pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
        pjmedia_event_publish(NULL, codec, &event, 0);
    } else if (ff->last_dec_keyframe_ts.u64 == 0) {
	/* Broadcast missing keyframe event */
// 	pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, ts, codec);
// 	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    return PJ_SUCCESS;
}
Exemple #17
0
static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed)
{
    unsigned i;
    pjsip_tx_data *request;
    pjsip_transaction **tsx;
    pj_timestamp t1, t2, elapsed;
    pjsip_via_hdr *via;
    pj_status_t status;

    /* Create the request first. */
    pj_str_t str_target = pj_str("sip:[email protected]");
    pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>");
    pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>");
    pj_str_t str_contact = str_from;

    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
					&str_target, &str_from, &str_to,
					&str_contact, NULL, -1, NULL,
					&request);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create request", status);
	return status;
    }

    via = (pjsip_via_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_VIA,
					      NULL);

    /* Create transaction array */
    tsx = (pjsip_transaction**) pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*));

    pj_bzero(&mod_tsx_user, sizeof(mod_tsx_user));
    mod_tsx_user.id = -1;

    /* Benchmark */
    elapsed.u64 = 0;
    pj_get_timestamp(&t1);
    for (i=0; i<working_set; ++i) {
	status = pjsip_tsx_create_uac(&mod_tsx_user, request, &tsx[i]);
	if (status != PJ_SUCCESS)
	    goto on_error;
	/* Reset branch param */
	via->branch_param.slen = 0;
    }
    pj_get_timestamp(&t2);
    pj_sub_timestamp(&t2, &t1);
    pj_add_timestamp(&elapsed, &t2);

    p_elapsed->u64 = elapsed.u64;
    status = PJ_SUCCESS;
    
on_error:
    for (i=0; i<working_set; ++i) {
	if (tsx[i]) {
	    pjsip_tsx_terminate(tsx[i], 601);
	    tsx[i] = NULL;
	}
    }
    pjsip_tx_data_dec_ref(request);
    flush_events(2000);
    return status;
}
Exemple #18
0
int pool_perf_test()
{
    unsigned i;
    pj_uint32_t pool_time=0, malloc_time=0, pool_time2=0;
    pj_timestamp start, end;
    pj_uint32_t best, worst;

    /* Initialize size of chunks to allocate in for the test. */
    for (i=0; i<COUNT; ++i) {
        unsigned aligned_size;
        sizes[i] = MIN_SIZE + (pj_rand() % MAX_SIZE);
        aligned_size = sizes[i];
        if (aligned_size & (PJ_POOL_ALIGNMENT-1))
            aligned_size = ((aligned_size + PJ_POOL_ALIGNMENT - 1)) & ~(PJ_POOL_ALIGNMENT - 1);
        total_size += aligned_size;
    }

    /* Add some more for pool admin area */
    total_size += 512;

    PJ_LOG(3, (THIS_FILE, "Benchmarking pool.."));

    /* Warmup */
    pool_test_pool();
    pool_test_malloc_free();

    for (i=0; i<LOOP; ++i) {
        pj_get_timestamp(&start);
        if (pool_test_pool()) {
            return 1;
        }
        pj_get_timestamp(&end);
        pool_time += (end.u32.lo - start.u32.lo);

        pj_get_timestamp(&start);
        if (pool_test_malloc_free()) {
            return 2;
        }
        pj_get_timestamp(&end);
        malloc_time += (end.u32.lo - start.u32.lo);

        pj_get_timestamp(&start);
        if (pool_test_pool()) {
            return 4;
        }
        pj_get_timestamp(&end);
        pool_time2 += (end.u32.lo - start.u32.lo);
    }

    PJ_LOG(4,(THIS_FILE,"..LOOP count:                        %u",LOOP));
    PJ_LOG(4,(THIS_FILE,"..number of alloc/dealloc per loop:  %u",COUNT));
    PJ_LOG(4,(THIS_FILE,"..pool allocation/deallocation time: %u",pool_time));
    PJ_LOG(4,(THIS_FILE,"..malloc/free time:                  %u",malloc_time));
    PJ_LOG(4,(THIS_FILE,"..pool again, second invocation:     %u",pool_time2));

    if (pool_time2==0) pool_time2=1;
    if (pool_time < pool_time2)
        best = pool_time, worst = pool_time2;
    else
        best = pool_time2, worst = pool_time;

    /* avoid division by zero */
    if (best==0) best=1;
    if (worst==0) worst=1;

    PJ_LOG(3, (THIS_FILE, "..pool speedup over malloc best=%dx, worst=%dx",
               (int)(malloc_time/best),
               (int)(malloc_time/worst)));
    return 0;
}
/* Test that we receive loopback message. */
int transport_send_recv_test( pjsip_transport_type_e tp_type,
			      pjsip_transport *ref_tp,
			      char *target_url,
			      int *p_usec_rtt)
{
    pj_bool_t msg_log_enabled;
    pj_status_t status;
    pj_str_t target, from, to, contact, call_id, body;
    pjsip_method method;
    pjsip_tx_data *tdata;
    pj_time_val timeout;

    PJ_UNUSED_ARG(tp_type);
    PJ_UNUSED_ARG(ref_tp);

    PJ_LOG(3,(THIS_FILE, "  single message round-trip test..."));

    /* Register out test module to receive the message (if necessary). */
    if (my_module.id == -1) {
	status = pjsip_endpt_register_module( endpt, &my_module );
	if (status != PJ_SUCCESS) {
	    app_perror("   error: unable to register module", status);
	    return -500;
	}
    }

    /* Disable message logging. */
    msg_log_enabled = msg_logger_set_enabled(0);

    /* Create a request message. */
    target = pj_str(target_url);
    from = pj_str(FROM_HDR);
    to = pj_str(target_url);
    contact = pj_str(CONTACT_HDR);
    call_id = pj_str(CALL_ID_HDR);
    body = pj_str(BODY);

    pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);
    status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to,
					 &contact, &call_id, CSEQ_VALUE, 
					 &body, &tdata );
    if (status != PJ_SUCCESS) {
	app_perror("   error: unable to create request", status);
	return -510;
    }

    /* Reset statuses */
    send_status = recv_status = NO_STATUS;

    /* Start time. */
    pj_get_timestamp(&my_send_time);

    /* Send the message (statelessly). */
    PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", 
			 (int)target.slen, target.ptr));
    status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL,
					         &send_msg_callback);
    if (status != PJ_SUCCESS) {
	/* Immediate error! */
	pjsip_tx_data_dec_ref(tdata);
	send_status = status;
    }

    /* Set the timeout (2 seconds from now) */
    pj_gettimeofday(&timeout);
    timeout.sec += 2;

    /* Loop handling events until we get status */
    do {
	pj_time_val now;
	pj_time_val poll_interval = { 0, 10 };

	pj_gettimeofday(&now);
	if (PJ_TIME_VAL_GTE(now, timeout)) {
	    PJ_LOG(3,(THIS_FILE, "   error: timeout in send/recv test"));
	    status = -540;
	    goto on_return;
	}

	if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) {
	    app_perror("   error sending message", send_status);
	    status = -550;
	    goto on_return;
	}

	if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) {
	    app_perror("   error receiving message", recv_status);
	    status = -560;
	    goto on_return;
	}

	if (send_status!=NO_STATUS && recv_status!=NO_STATUS) {
	    /* Success! */
	    break;
	}

	pjsip_endpt_handle_events(endpt, &poll_interval);

    } while (1);

    if (status == PJ_SUCCESS) {
	unsigned usec_rt;
	usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time);

	PJ_LOG(3,(THIS_FILE, "    round-trip = %d usec", usec_rt));

	*p_usec_rtt = usec_rt;
    }

    /* Restore message logging. */
    msg_logger_set_enabled(msg_log_enabled);

    status = PJ_SUCCESS;

on_return:
    return status;
}
Exemple #20
0
/*
 * sock_producer_consumer()
 *
 * Simple producer-consumer benchmarking. Send loop number of
 * buf_size size packets as fast as possible.
 */
static int sock_producer_consumer(int sock_type,
                                  unsigned buf_size,
                                  unsigned loop, 
                                  unsigned *p_bandwidth)
{
    pj_sock_t consumer, producer;
    pj_pool_t *pool;
    char *outgoing_buffer, *incoming_buffer;
    pj_timestamp start, stop;
    unsigned i;
    pj_highprec_t elapsed, bandwidth;
    pj_size_t total_received;
    pj_status_t rc;

    /* Create pool. */
    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
    if (!pool)
        return -10;

    /* Create producer-consumer pair. */
    rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
    if (rc != PJ_SUCCESS) {
        app_perror("...error: create socket pair", rc);
        return -20;
    }

    /* Create buffers. */
    outgoing_buffer = pj_pool_alloc(pool, buf_size);
    incoming_buffer = pj_pool_alloc(pool, buf_size);

    /* Start loop. */
    pj_get_timestamp(&start);
    total_received = 0;
    for (i=0; i<loop; ++i) {
        pj_ssize_t sent, part_received, received;
	pj_time_val delay;

        sent = buf_size;
        rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
        if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
            app_perror("...error: send()", rc);
            return -61;
        }

        /* Repeat recv() until all data is part_received.
         * This applies only for non-UDP of course, since for UDP
         * we would expect all data to be part_received in one packet.
         */
        received = 0;
        do {
            part_received = buf_size-received;
	    rc = pj_sock_recv(consumer, incoming_buffer+received, 
			      &part_received, 0);
	    if (rc != PJ_SUCCESS) {
	        app_perror("...recv error", rc);
	        return -70;
	    }
            if (part_received <= 0) {
                PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
                          part_received));
                return -73;
            }
	    if ((pj_size_t)part_received != buf_size-received) {
                if (sock_type != PJ_SOCK_STREAM) {
	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
                              buf_size-received, part_received));
	            return -76;
                }
	    }
            received += part_received;
        } while ((pj_size_t)received < buf_size);

	total_received += received;

	/* Stop test if it's been runnign for more than 10 secs. */
	pj_get_timestamp(&stop);
	delay = pj_elapsed_time(&start, &stop);
	if (delay.sec > 10)
	    break;
    }

    /* Stop timer. */
    pj_get_timestamp(&stop);

    elapsed = pj_elapsed_usec(&start, &stop);

    /* bandwidth = total_received * 1000 / elapsed */
    bandwidth = total_received;
    pj_highprec_mul(bandwidth, 1000);
    pj_highprec_div(bandwidth, elapsed);
    
    *p_bandwidth = (pj_uint32_t)bandwidth;

    /* Close sockets. */
    pj_sock_close(consumer);
    pj_sock_close(producer);

    /* Done */
    pj_pool_release(pool);

    return 0;
}
/*
 * create response benchmark
 */
static int create_response_bench(pj_timestamp *p_elapsed)
{
    enum { COUNT = 100 };
    unsigned i, j;
    pjsip_via_hdr *via;
    pjsip_rx_data rdata;
    pjsip_tx_data *request;
    pjsip_tx_data *tdata[COUNT];
    pj_timestamp t1, t2, elapsed;
    pj_status_t status;

    /* Create the request first. */
    pj_str_t str_target = pj_str("sip:[email protected]");
    pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>");
    pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>");
    pj_str_t str_contact = str_from;

    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
					&str_target, &str_from, &str_to,
					&str_contact, NULL, -1, NULL,
					&request);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create request", status);
	return status;
    }

    /* Create several Via headers */
    via = pjsip_via_hdr_create(request->pool);
    via->sent_by.host = pj_str("192.168.0.7");
    via->sent_by.port = 5061;
    via->transport = pj_str("udp");
    via->rport_param = 0;
    via->branch_param = pj_str("012345678901234567890123456789");
    via->recvd_param = pj_str("192.168.0.7");
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via));
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via));
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via);
    

    /* Create "dummy" rdata from the tdata */
    pj_bzero(&rdata, sizeof(pjsip_rx_data));
    rdata.tp_info.pool = request->pool;
    rdata.msg_info.msg = request->msg;
    rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL);
    rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL);
    rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.via = via;

    /*
     * Now benchmark create_response
     */
    elapsed.u64 = 0;

    for (i=0; i<LOOP; i+=COUNT) {
	pj_bzero(tdata, sizeof(tdata));

	pj_get_timestamp(&t1);

	for (j=0; j<COUNT; ++j) {
	    status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]);
	    if (status != PJ_SUCCESS) {
		app_perror("    error: unable to create request", status);
		goto on_error;
	    }
	}

	pj_get_timestamp(&t2);
	pj_sub_timestamp(&t2, &t1);
	pj_add_timestamp(&elapsed, &t2);
	
	for (j=0; j<COUNT; ++j)
	    pjsip_tx_data_dec_ref(tdata[j]);
    }

    p_elapsed->u64 = elapsed.u64;
    pjsip_tx_data_dec_ref(request);
    return PJ_SUCCESS;

on_error:
    for (i=0; i<COUNT; ++i) {
	if (tdata[i])
	    pjsip_tx_data_dec_ref(tdata[i]);
    }
    return -400;
}
Exemple #22
0
/*
 * pj_init(void).
 * Init PJLIB!
 */
PJ_DEF(pj_status_t) pj_init(void)
{
    char dummy_guid[PJ_GUID_MAX_LENGTH];
    pj_str_t guid;
    pj_status_t rc;

    /* Check if PJLIB have been initialized */
    if (initialized) {
	++initialized;
	return PJ_SUCCESS;
    }

#if PJ_HAS_THREADS
    /* Init this thread's TLS. */
    if ((rc=pj_thread_init()) != 0) {
	return rc;
    }

    /* Critical section. */
    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_RECURSE)) != 0)
	return rc;

#endif

    /* Init logging */
    pj_log_init();

    /* Initialize exception ID for the pool. 
     * Must do so after critical section is configured.
     */
    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
    if (rc != PJ_SUCCESS)
        return rc;
    
    /* Init random seed. */
    /* Or probably not. Let application in charge of this */
    /* pj_srand( clock() ); */

    /* Startup GUID. */
    guid.ptr = dummy_guid;
    pj_generate_unique_string( &guid );

    /* Startup timestamp */
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
    {
	pj_timestamp dummy_ts;
	if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
	    return rc;
	}
    }
#endif   

    /* Flag PJLIB as initialized */
    ++initialized;
    pj_assert(initialized == 1);

    PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
	      PJ_VERSION));

    return PJ_SUCCESS;
}
Exemple #23
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t	  *pool;
    pjmedia_port  *wav_play;
    pjmedia_port  *wav_rec;
    pjmedia_port  *wav_out;
    pj_status_t status;
    pjmedia_echo_state *ec;
    pjmedia_frame play_frame, rec_frame;
    unsigned opt = 0;
    unsigned latency_ms = 25;
    unsigned tail_ms = TAIL_LENGTH;
    pj_timestamp t0, t1;
    int i, repeat=1, interactive=0, c;

    pj_optind = 0;
    while ((c=pj_getopt(argc, argv, "d:l:a:r:i")) !=-1) {
	switch (c) {
	case 'd':
	    latency_ms = atoi(pj_optarg);
	    if (latency_ms < 25) {
		puts("Invalid delay");
		puts(desc);
	    }
	    break;
	case 'l':
	    tail_ms = atoi(pj_optarg);
	    break;
	case 'a':
	    {
		int alg = atoi(pj_optarg);
		switch (alg) {
		case 0:
		    opt = 0;
		case 1:
		    opt = PJMEDIA_ECHO_SPEEX;
		    break;
		case 3:
		    opt = PJMEDIA_ECHO_SIMPLE;
		    break;
		default:
		    puts("Invalid algorithm");
		    puts(desc);
		    return 1;
		}
	    }
	    break;
	case 'r':
	    repeat = atoi(pj_optarg);
	    if (repeat < 1) {
		puts("Invalid repeat count");
		puts(desc);
		return 1;
	    }
	    break;
	case 'i':
	    interactive = 1;
	    break;
	}
    }

    if (argc - pj_optind != 3) {
	puts("Error: missing argument(s)");
	puts(desc);
	return 1;
    }

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Create memory pool for our file player */
    pool = pj_pool_create( &cp.factory,	    /* pool factory	    */
			   "wav",	    /* pool name.	    */
			   4000,	    /* init size	    */
			   4000,	    /* increment size	    */
			   NULL		    /* callback on error    */
			   );

    /* Open wav_play */
    status = pjmedia_wav_player_port_create(pool, argv[pj_optind], PTIME, 
					    PJMEDIA_FILE_NO_LOOP, 0, 
					    &wav_play);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error opening playback WAV file", status);
	return 1;
    }
    
    /* Open recorded wav */
    status = pjmedia_wav_player_port_create(pool, argv[pj_optind+1], PTIME, 
					    PJMEDIA_FILE_NO_LOOP, 0, 
					    &wav_rec);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error opening recorded WAV file", status);
	return 1;
    }

    /* play and rec WAVs must have the same clock rate */
    if (wav_play->info.clock_rate != wav_rec->info.clock_rate) {
	puts("Error: clock rate mismatch in the WAV files");
	return 1;
    }

    /* .. and channel count */
    if (wav_play->info.channel_count != wav_rec->info.channel_count) {
	puts("Error: clock rate mismatch in the WAV files");
	return 1;
    }

    /* Create output wav */
    status = pjmedia_wav_writer_port_create(pool, argv[pj_optind+2],
					    wav_play->info.clock_rate,
					    wav_play->info.channel_count,
					    wav_play->info.samples_per_frame,
					    wav_play->info.bits_per_sample,
					    0, 0, &wav_out);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error opening output WAV file", status);
	return 1;
    }

    /* Create echo canceller */
    status = pjmedia_echo_create2(pool, wav_play->info.clock_rate,
				  wav_play->info.channel_count,
				  wav_play->info.samples_per_frame,
				  tail_ms, latency_ms,
				  opt, &ec);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error creating EC", status);
	return 1;
    }


    /* Processing loop */
    play_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1);
    rec_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1);
    pj_get_timestamp(&t0);
    for (i=0; i < repeat; ++i) {
	for (;;) {
	    play_frame.size = wav_play->info.samples_per_frame << 1;
	    status = pjmedia_port_get_frame(wav_play, &play_frame);
	    if (status != PJ_SUCCESS)
		break;

	    status = pjmedia_echo_playback(ec, (short*)play_frame.buf);

	    rec_frame.size = wav_play->info.samples_per_frame << 1;
	    status = pjmedia_port_get_frame(wav_rec, &rec_frame);
	    if (status != PJ_SUCCESS)
		break;

	    status = pjmedia_echo_capture(ec, (short*)rec_frame.buf, 0);

	    //status = pjmedia_echo_cancel(ec, (short*)rec_frame.buf, 
	    //			     (short*)play_frame.buf, 0, NULL);

	    pjmedia_port_put_frame(wav_out, &rec_frame);
	}

	pjmedia_wav_player_port_set_pos(wav_play, 0);
	pjmedia_wav_player_port_set_pos(wav_rec, 0);
    }
    pj_get_timestamp(&t1);

    i = pjmedia_wav_writer_port_get_pos(wav_out) / sizeof(pj_int16_t) * 1000 / 
	(wav_out->info.clock_rate * wav_out->info.channel_count);
    PJ_LOG(3,(THIS_FILE, "Processed %3d.%03ds audio",
	      i / 1000, i % 1000));
    PJ_LOG(3,(THIS_FILE, "Completed in %u msec\n", pj_elapsed_msec(&t0, &t1)));

    /* Destroy file port(s) */
    status = pjmedia_port_destroy( wav_play );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_port_destroy( wav_rec );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_port_destroy( wav_out );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Destroy ec */
    pjmedia_echo_destroy(ec);

    /* Release application pool */
    pj_pool_release( pool );

    /* Destroy media endpoint. */
    pjmedia_endpt_destroy( med_endpt );

    /* Destroy pool factory */
    pj_caching_pool_destroy( &cp );

    /* Shutdown PJLIB */
    pj_shutdown();

    if (interactive) {
	char s[10], *dummy;
	puts("ENTER to quit");
	dummy = fgets(s, sizeof(s), stdin);
    }

    /* Done. */
    return 0;
}
Exemple #24
0
/* 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;
}
Exemple #25
0
static int send_recv_test(pj_ioqueue_t *ioque,
			  pj_ioqueue_key_t *skey,
			  pj_ioqueue_key_t *ckey,
			  void *send_buf,
			  void *recv_buf,
			  pj_ssize_t bufsize,
			  pj_timestamp *t_elapsed)
{
    pj_status_t status;
    pj_ssize_t bytes;
    pj_time_val timeout;
    pj_timestamp t1, t2;
    int pending_op = 0;
    pj_ioqueue_op_key_t read_op, write_op;

    // Start reading on the server side.
    bytes = bufsize;
    status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
        app_perror("...pj_ioqueue_recv error", status);
	return -100;
    }
    
    if (status == PJ_EPENDING)
        ++pending_op;
    else {
        /* Does not expect to return error or immediate data. */
        return -115;
    }

    // Randomize send buffer.
    pj_create_random_string((char*)send_buf, bufsize);

    // Starts send on the client side.
    bytes = bufsize;
    status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
    if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
	return -120;
    }
    if (status == PJ_EPENDING) {
	++pending_op;
    }

    // Begin time.
    pj_get_timestamp(&t1);

    // Reset indicators
    callback_read_size = callback_write_size = 0;
    callback_read_key = callback_write_key = NULL;
    callback_read_op = callback_write_op = NULL;

    // Poll the queue until we've got completion event in the server side.
    status = 0;
    while (pending_op > 0) {
        timeout.sec = 1; timeout.msec = 0;
#ifdef PJ_SYMBIAN
	PJ_UNUSED_ARG(ioque);
	status = pj_symbianos_poll(-1, 1000);
#else
	status = pj_ioqueue_poll(ioque, &timeout);
#endif
	if (status > 0) {
            if (callback_read_size) {
                if (callback_read_size != bufsize)
                    return -160;
                if (callback_read_key != skey)
                    return -161;
                if (callback_read_op != &read_op)
                    return -162;
            }
            if (callback_write_size) {
                if (callback_write_key != ckey)
                    return -163;
                if (callback_write_op != &write_op)
                    return -164;
            }
	    pending_op -= status;
	}
        if (status == 0) {
            PJ_LOG(3,("", "...error: timed out"));
        }
	if (status < 0) {
	    return -170;
	}
    }

    // Pending op is zero.
    // Subsequent poll should yield zero too.
    timeout.sec = timeout.msec = 0;
#ifdef PJ_SYMBIAN
    status = pj_symbianos_poll(-1, 1);
#else
    status = pj_ioqueue_poll(ioque, &timeout);
#endif
    if (status != 0)
        return -173;

    // End time.
    pj_get_timestamp(&t2);
    t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);

    // Compare recv buffer with send buffer.
    if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
	return -180;
    }

    // Success
    return 0;
}
Exemple #26
0
/*
 * pj_init(void).
 * Init PJLIB!
 */
PJ_DEF(pj_status_t) pj_init(void)
{
    WSADATA wsa;
    char dummy_guid[32]; /* use maximum GUID length */
    pj_str_t guid;
    pj_status_t rc;

    /* Check if PJLIB have been initialized */
    if (initialized) {
	++initialized;
	return PJ_SUCCESS;
    }

    /* Init Winsock.. */
    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
	return PJ_RETURN_OS_ERROR(WSAGetLastError());
    }

    /* Init this thread's TLS. */
    if ((rc=pj_thread_init()) != PJ_SUCCESS) {
	return rc;
    }
    
    /* Init logging */
    pj_log_init();

    /* Init random seed. */
    /* Or probably not. Let application in charge of this */
    /* pj_srand( GetCurrentProcessId() ); */

    /* Initialize critical section. */
    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
	return rc;

    /* Startup GUID. */
    guid.ptr = dummy_guid;
    pj_generate_unique_string( &guid );

    /* Initialize exception ID for the pool. 
     * Must do so after critical section is configured.
     */
    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
    if (rc != PJ_SUCCESS)
        return rc;

    /* Startup timestamp */
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
    {
	pj_timestamp dummy_ts;
	if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) {
	    return rc;
	}
	if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
	    return rc;
	}
    }
#endif   

    /* Flag PJLIB as initialized */
    ++initialized;
    pj_assert(initialized == 1);

    PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
	      PJ_VERSION));

    return PJ_SUCCESS;
}
Exemple #27
0
/*
 * Benchmarking IOQueue
 */
static int bench_test(pj_bool_t allow_concur, int bufsize, 
		      int inactive_sock_count)
{
    pj_sock_t ssock=-1, csock=-1;
    pj_sockaddr_in addr;
    pj_pool_t *pool = NULL;
    pj_sock_t *inactive_sock=NULL;
    pj_ioqueue_op_key_t *inactive_read_op;
    char *send_buf, *recv_buf;
    pj_ioqueue_t *ioque = NULL;
    pj_ioqueue_key_t *skey, *ckey, *keys[SOCK_INACTIVE_MAX+2];
    pj_timestamp t1, t2, t_elapsed;
    int rc=0, i;    /* i must be signed */
    pj_str_t temp;
    char errbuf[PJ_ERR_MSG_SIZE];

    TRACE__((THIS_FILE, "   bench test %d", inactive_sock_count));

    // Create pool.
    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

    // Allocate buffers for send and receive.
    send_buf = (char*)pj_pool_alloc(pool, bufsize);
    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

    // Allocate sockets for sending and receiving.
    rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock);
    if (rc == PJ_SUCCESS) {
        rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock);
    } else
        csock = PJ_INVALID_SOCKET;
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_sock_socket()", rc);
	goto on_error;
    }

    // Bind server socket.
    pj_bzero(&addr, sizeof(addr));
    addr.sin_family = pj_AF_INET();
    addr.sin_port = pj_htons(PORT);
    if (pj_sock_bind(ssock, &addr, sizeof(addr)))
	goto on_error;

    pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);

    // Create I/O Queue.
    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_ioqueue_create()", rc);
	goto on_error;
    }

    // Set concurrency
    rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_ioqueue_set_default_concurrency()", rc);
	goto on_error;
    }

    // Allocate inactive sockets, and bind them to some arbitrary address.
    // Then register them to the I/O queue, and start a read operation.
    inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, 
				    inactive_sock_count*sizeof(pj_sock_t));
    inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
                              inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
    pj_bzero(&addr, sizeof(addr));
    addr.sin_family = pj_AF_INET();
    for (i=0; i<inactive_sock_count; ++i) {
        pj_ssize_t bytes;

	rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &inactive_sock[i]);
	if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
	    app_perror("...error: pj_sock_socket()", rc);
	    goto on_error;
	}
	if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error: pj_sock_bind()", rc);
	    goto on_error;
	}
	rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], 
			              NULL, &test_cb, &keys[i]);
	if (rc != PJ_SUCCESS) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error(1): pj_ioqueue_register_sock()", rc);
	    PJ_LOG(3,(THIS_FILE, "....i=%d", i));
	    goto on_error;
	}
        bytes = bufsize;
	rc = pj_ioqueue_recv(keys[i], &inactive_read_op[i], recv_buf, &bytes, 0);
	if (rc != PJ_EPENDING) {
	    pj_sock_close(inactive_sock[i]);
	    inactive_sock[i] = PJ_INVALID_SOCKET;
	    app_perror("...error: pj_ioqueue_read()", rc);
	    goto on_error;
	}
    }

    // Register server and client socket.
    // We put this after inactivity socket, hopefully this can represent the
    // worst waiting time.
    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 
			          &test_cb, &skey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(2): pj_ioqueue_register_sock()", rc);
	goto on_error;
    }

    rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, 
			          &test_cb, &ckey);
    if (rc != PJ_SUCCESS) {
	app_perror("...error(3): pj_ioqueue_register_sock()", rc);
	goto on_error;
    }

    // Set destination address to send the packet.
    pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);

    // Test loop.
    t_elapsed.u64 = 0;
    for (i=0; i<LOOP; ++i) {
	pj_ssize_t bytes;
        pj_ioqueue_op_key_t read_op, write_op;

	// Randomize send buffer.
	pj_create_random_string(send_buf, bufsize);

	// Start reading on the server side.
        bytes = bufsize;
	rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
	if (rc != PJ_EPENDING) {
	    app_perror("...error: pj_ioqueue_read()", rc);
	    break;
	}

	// Starts send on the client side.
        bytes = bufsize;
	rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
			       &addr, sizeof(addr));
	if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
	    app_perror("...error: pj_ioqueue_write()", rc);
	    break;
	}
	if (rc == PJ_SUCCESS) {
	    if (bytes < 0) {
		app_perror("...error: pj_ioqueue_sendto()",(pj_status_t)-bytes);
		break;
	    }
	}

	// Begin time.
	pj_get_timestamp(&t1);

	// Poll the queue until we've got completion event in the server side.
        callback_read_key = NULL;
        callback_read_size = 0;
	TRACE__((THIS_FILE, "     waiting for key = %p", skey));
	do {
	    pj_time_val timeout = { 1, 0 };
#ifdef PJ_SYMBIAN
	    rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
#else
	    rc = pj_ioqueue_poll(ioque, &timeout);
#endif
	    TRACE__((THIS_FILE, "     poll rc=%d", rc));
	} while (rc >= 0 && callback_read_key != skey);

	// End time.
	pj_get_timestamp(&t2);
	t_elapsed.u64 += (t2.u64 - t1.u64);

	if (rc < 0) {
	    app_perror("   error: pj_ioqueue_poll", -rc);
	    break;
	}

	// Compare recv buffer with send buffer.
	if (callback_read_size != bufsize || 
	    pj_memcmp(send_buf, recv_buf, bufsize)) 
	{
	    rc = -10;
	    PJ_LOG(3,(THIS_FILE, "   error: size/buffer mismatch"));
	    break;
	}

	// Poll until all events are exhausted, before we start the next loop.
	do {
	    pj_time_val timeout = { 0, 10 };
#ifdef PJ_SYMBIAN
	    PJ_UNUSED_ARG(timeout);
	    rc = pj_symbianos_poll(-1, 100);
#else	    
	    rc = pj_ioqueue_poll(ioque, &timeout);
#endif
	} while (rc>0);

	rc = 0;
    }

    // Print results
    if (rc == 0) {
	pj_timestamp tzero;
	pj_uint32_t usec_delay;

	tzero.u32.hi = tzero.u32.lo = 0;
	usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);

	PJ_LOG(3, (THIS_FILE, "...%10d %15d  % 9d", 
	           bufsize, inactive_sock_count, usec_delay));

    } else {
	PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)", 
			      rc, bufsize, inactive_sock_count+2));
    }

    // Cleaning up.
    for (i=inactive_sock_count-1; i>=0; --i) {
	pj_ioqueue_unregister(keys[i]);
    }

    pj_ioqueue_unregister(skey);
    pj_ioqueue_unregister(ckey);


    pj_ioqueue_destroy(ioque);
    pj_pool_release( pool);
    return rc;

on_error:
    PJ_LOG(1,(THIS_FILE, "...ERROR: %s", 
	      pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
    if (ssock)
	pj_sock_close(ssock);
    if (csock)
	pj_sock_close(csock);
    for (i=0; i<inactive_sock_count && inactive_sock && 
	      inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) 
    {
	pj_sock_close(inactive_sock[i]);
    }
    if (ioque != NULL)
	pj_ioqueue_destroy(ioque);
    pj_pool_release( pool);
    return -1;
}
Exemple #28
0
/*
 * Test one test entry.
 */
static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry)
{
    pj_status_t status;
    int len;
    char *input;
    pjsip_uri *parsed_uri, *ref_uri;
    pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0};
    pj_timestamp t1, t2;

    if (entry->len == 0)
	entry->len = pj_ansi_strlen(entry->str);

#if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0
    input = pj_pool_alloc(pool, entry->len + 1);
    pj_memcpy(input, entry->str, entry->len);
    input[entry->len] = '\0';
#else
    input = entry->str;
#endif

    /* Parse URI text. */
    pj_get_timestamp(&t1);
    var.parse_len = var.parse_len + entry->len;
    parsed_uri = pjsip_parse_uri(pool, input, entry->len, 0);
    if (!parsed_uri) {
	/* Parsing failed. If the entry says that this is expected, then
	 * return OK.
	 */
	status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : -10;
	if (status != 0) {
	    PJ_LOG(3,(THIS_FILE, "   uri parse error!\n"
				 "   uri='%s'\n",
				 input));
	}
	goto on_return;
    }
    pj_get_timestamp(&t2);
    pj_sub_timestamp(&t2, &t1);
    pj_add_timestamp(&var.parse_time, &t2);

    /* Create the reference URI. */
    ref_uri = entry->creator(pool);

    /* Print both URI. */
    s1.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
    s2.ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);

    pj_get_timestamp(&t1);
    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE);
    if (len < 1) {
	status = -20;
	goto on_return;
    }
    s1.ptr[len] = '\0';
    s1.slen = len;

    var.print_len = var.print_len + len;
    pj_get_timestamp(&t2);
    pj_sub_timestamp(&t2, &t1);
    pj_add_timestamp(&var.print_time, &t2);

    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE);
    if (len < 1) {
	status = -30;
	goto on_return;
    }
    s2.ptr[len] = '\0';
    s2.slen = len;

    /* Full comparison of parsed URI with reference URI. */
    pj_get_timestamp(&t1);
    status = pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri);
    if (status != 0) {
	/* Not equal. See if this is the expected status. */
	status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : -40;
	if (status != 0) {
	    PJ_LOG(3,(THIS_FILE, "   uri comparison mismatch, status=%d:\n"
				 "    uri1='%s'\n"
				 "    uri2='%s'",
				 status, s1.ptr, s2.ptr));
	}
	goto on_return;

    } else {
	/* Equal. See if this is the expected status. */
	status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -50;
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}
    }

    var.cmp_len = var.cmp_len + len;
    pj_get_timestamp(&t2);
    pj_sub_timestamp(&t2, &t1);
    pj_add_timestamp(&var.cmp_time, &t2);

    /* Compare text. */
    if (entry->printed) {
	if (pj_strcmp2(&s1, entry->printed) != 0) {
	    /* Not equal. */
	    PJ_LOG(3,(THIS_FILE, "   uri print mismatch:\n"
				 "    printed='%s'\n"
				 "    expectd='%s'",
				 s1.ptr, entry->printed));
	    status = -60;
	}
    } else {
	if (pj_strcmp(&s1, &s2) != 0) {
	    /* Not equal. */
	    PJ_LOG(3,(THIS_FILE, "   uri print mismatch:\n"
				 "    uri1='%s'\n"
				 "    uri2='%s'",
				 s1.ptr, s2.ptr));
	    status = -70;
	}
    }

on_return:
    return status;
}
Exemple #29
0
PJ_DEF(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *sess, 
				  unsigned seq, 
				  unsigned rtp_ts,
				  unsigned payload,
				  pj_bool_t discarded)
{   
    pj_timestamp ts;
    pj_uint32_t arrival;
    pj_int32_t transit;
    pjmedia_rtp_status seq_st;
    unsigned last_seq;

#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
    PJ_UNUSED_ARG(discarded);
#endif

    if (sess->stat.rx.pkt == 0) {
	/* Init sequence for the first time. */
	pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq);
    } 

    sess->stat.rx.pkt++;
    sess->stat.rx.bytes += payload;

    /* Process the RTP packet. */
    last_seq = sess->seq_ctrl.max_seq;
    pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st);

    if (seq_st.status.flag.restart) {
	rtcp_init_seq(sess);
    }
    
    if (seq_st.status.flag.dup) {
	sess->stat.rx.dup++;
	TRACE_((sess->name, "Duplicate packet detected"));
    }

    if (seq_st.status.flag.outorder && !seq_st.status.flag.probation) {
	sess->stat.rx.reorder++;
	TRACE_((sess->name, "Out-of-order packet detected"));
    }

    if (seq_st.status.flag.bad) {
	sess->stat.rx.discard++;

#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
	pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
			       -1,				 /* lost    */
			       (seq_st.status.flag.dup? 1:0),	 /* dup     */
			       (!seq_st.status.flag.dup? 1:-1),  /* discard */
			       -1,				 /* jitter  */
			       -1, 0);				 /* toh	    */
#endif

	TRACE_((sess->name, "Bad packet discarded"));
	return;
    }

    /* Only mark "good" packets */
    ++sess->received;

    /* Calculate loss periods. */
    if (seq_st.diff > 1) {
	unsigned count = seq_st.diff - 1;
	unsigned period;

	period = count * sess->pkt_size * 1000 / sess->clock_rate;
	period *= 1000;

	/* Update packet lost. 
	 * The packet lost number will also be updated when we're sending
	 * outbound RTCP RR.
	 */
	sess->stat.rx.loss += (seq_st.diff - 1);
	TRACE_((sess->name, "%d packet(s) lost", seq_st.diff - 1));

	/* Update loss period stat */
	pj_math_stat_update(&sess->stat.rx.loss_period, period);
    }


    /*
     * Calculate jitter only when sequence is good (see RFC 3550 section A.8),
     * AND only when the timestamp is different than the last packet
     * (see RTP FAQ).
     */
    if (seq_st.diff == 1 && rtp_ts != sess->rtp_last_ts) {
	/* Get arrival time and convert timestamp to samples */
	pj_get_timestamp(&ts);
	ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64;
	arrival = ts.u32.lo;

	transit = arrival - rtp_ts;
    
	/* Ignore the first N packets as they normally have bad jitter
	 * due to other threads working to establish the call
	 */
	if (sess->transit == 0 || 
	    sess->received < PJMEDIA_RTCP_IGNORE_FIRST_PACKETS) 
	{
	    sess->transit = transit;
	    sess->stat.rx.jitter.min = (unsigned)-1;
	} else {
	    pj_int32_t d;
	    pj_uint32_t jitter;
	    
	    d = transit - sess->transit;
	    sess->transit = transit;
	    if (d < 0) 
		d = -d;
	    
	    sess->jitter += d - ((sess->jitter + 8) >> 4);

	    /* Get jitter in usec */
	    if (d < 4294)
		jitter = d * 1000000 / sess->clock_rate;
	    else {
		jitter = d * 1000 / sess->clock_rate;
		jitter *= 1000;
	    }

	    /* Update jitter stat */
	    pj_math_stat_update(&sess->stat.rx.jitter, jitter);

#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
	    pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
				   0,			    /* lost    */
				   0,			    /* dup     */
				   discarded,		    /* discard */
				   (sess->jitter >> 4),	    /* jitter  */
				   -1, 0);		    /* toh     */
#endif
	}
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
    } else if (seq_st.diff > 1) {
Exemple #30
0
static pj_status_t check_decode_result(pjmedia_vid_codec *codec,
				       const pj_timestamp *ts,
				       pj_bool_t got_keyframe)
{
    ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
    pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
    pjmedia_event event;

    /* Check for format change.
     * Decoder output format is set by libavcodec, in case it is different
     * to the configured param.
     */
    if (ff->dec_ctx->pix_fmt != ff->expected_dec_fmt ||
	ff->dec_ctx->width != (int)vafp->size.w ||
	ff->dec_ctx->height != (int)vafp->size.h)
    {
	pjmedia_format_id new_fmt_id;
	pj_status_t status;

	/* Get current raw format id from ffmpeg decoder context */
	status = PixelFormat_to_pjmedia_format_id(ff->dec_ctx->pix_fmt, 
						  &new_fmt_id);
	if (status != PJ_SUCCESS)
	    return status;

	/* Update decoder format in param */
		ff->param.dec_fmt.id = new_fmt_id;
	ff->param.dec_fmt.det.vid.size.w = ff->dec_ctx->width;
	ff->param.dec_fmt.det.vid.size.h = ff->dec_ctx->height;
	ff->expected_dec_fmt = ff->dec_ctx->pix_fmt;

	/* Re-init format info and apply-param of decoder */
	ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
	if (!ff->dec_vfi)
	    return PJ_ENOTSUP;
	pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
	ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
	ff->dec_vafp.buffer = NULL;
	status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
	if (status != PJ_SUCCESS)
	    return status;

	/* Realloc buffer if necessary */
	if (ff->dec_vafp.framebytes > ff->dec_buf_size) {
	    PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u",
		       (unsigned)ff->dec_buf_size,
		       (unsigned)ff->dec_vafp.framebytes));
	    ff->dec_buf_size = ff->dec_vafp.framebytes;
	    ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
	}

	/* Broadcast format changed event */
	pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
	event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
	pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param.dec_fmt,
		  sizeof(ff->param.dec_fmt));
	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    /* Check for missing/found keyframe */
    if (got_keyframe) {
	pj_get_timestamp(&ff->last_dec_keyframe_ts);

	/* Broadcast keyframe event */
        pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
        pjmedia_event_publish(NULL, codec, &event, 0);
    } else if (ff->last_dec_keyframe_ts.u64 == 0) {
	/* Broadcast missing keyframe event */
	pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, ts, codec);
	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    return PJ_SUCCESS;
}