pjsip / pjproject

PJSIP project
http://www.pjsip.org
GNU General Public License v2.0
2.02k stars 770 forks source link

pjsip for android .android audioRecord jni .may be call two count.this is bug?why in while check? #4075

Open zhuangguangkang0013 opened 2 weeks ago

zhuangguangkang0013 commented 2 weeks ago

Describe the bug

pjsip for android .android audioRecord jni .may be call two count.this is bug?why in while check?

Steps to reproduce

When the call is connected, the startrecord method may be executed twice in succession, once to startrecord and once to stop. Then execute start again. When I comment out this code in the while loop, it seems to be normal. When making an outgoing call, execute start once, and execute stop and release after hanging up. When receiving an incoming call, execute start once after answering the call, and execute stop and release after hanging up. It will no longer execute startrecord once, then stop once, and then start again when making a call.

https://github.com/pjsip/pjproject/blob/master/pjmedia/src/pjmedia-audiodev/android_jni_dev.c `static int AndroidRecorderCallback(void userData) { ........... / Start recording / pj_thread_set_prio(NULL, THREAD_PRIORITY_URGENT_AUDIO); (jni_env)->CallVoidMethod(jni_env, stream->record, record_method);

while (!stream->quit_flag) {
    pjmedia_frame frame;
    pj_status_t status;
    int shortRead;

    **//This judgment may call back once stop immediately after start
    if (!stream->running) {
        (*jni_env)->CallVoidMethod(jni_env, stream->record, stop_method);
        pj_sem_wait(stream->rec_sem);
        if (stream->quit_flag)
            break;
        (*jni_env)->CallVoidMethod(jni_env, stream->record, record_method);
    }**

    shortRead = (*jni_env)->CallIntMethod(jni_env, stream->record,
                                          read_method, inputBuffer,
                                          0, size);
    if (shortRead <= 0 || shortRead != size) {
        PJ_LOG (4, (THIS_FILE, "Record thread : error %d reading data",
                               shortRead));
        continue;
    }

    buf = (*jni_env)->GetShortArrayElements(jni_env, inputBuffer, 0);
    frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
    frame.size =  stream->rec_buf_size;
    frame.bit_info = 0;
    frame.buf = (void *)buf;
    frame.timestamp.u64 = stream->rec_timestamp.u64;

    status = (*stream->rec_cb)(stream->user_data, &frame);
    (*jni_env)->ReleaseShortArrayElements(jni_env, inputBuffer, buf,
                                          JNI_ABORT);
    if (status != PJ_SUCCESS || stream->quit_flag)
        break;

    stream->rec_timestamp.u64 += stream->param.samples_per_frame /
                                 stream->param.channel_count;
}

(*jni_env)->DeleteLocalRef(jni_env, inputBuffer);

on_return: detach_jvm(attached); PJ_LOG(5, (THIS_FILE, "Recorder thread stopped")); stream->rec_thread_exited = 1;

return 0;

}`

PJSIP version

2.12

Context

os:android os version:8.1 pjsip version:2.12

Log, call stack, etc

When the call is connected, the startrecord method may be executed twice in succession, once to startrecord and once to stop.
When I comment out this code in the while loop, it seems to be normal.
[https://github.com/pjsip/pjproject/blob/master/pjmedia/src/pjmedia-audiodev/android_jni_dev.c](url)
`static int AndroidRecorderCallback(void *userData)
{
    ...........
    /* Start recording */
    pj_thread_set_prio(NULL, THREAD_PRIORITY_URGENT_AUDIO);
    (*jni_env)->CallVoidMethod(jni_env, stream->record, record_method);

    while (!stream->quit_flag) {
        pjmedia_frame frame;
        pj_status_t status;
        int shortRead;
        // This judgment may call back once stop immediately after start
#        */if (!stream->running) {
            (*jni_env)->CallVoidMethod(jni_env, stream->record, stop_method);
            pj_sem_wait(stream->rec_sem);
            if (stream->quit_flag)
                break;
            (*jni_env)->CallVoidMethod(jni_env, stream->record, record_method);
        }/*

        shortRead = (*jni_env)->CallIntMethod(jni_env, stream->record,
                                              read_method, inputBuffer,
                                              0, size);
        if (shortRead <= 0 || shortRead != size) {
            PJ_LOG (4, (THIS_FILE, "Record thread : error %d reading data",
                                   shortRead));
            continue;
        }

        buf = (*jni_env)->GetShortArrayElements(jni_env, inputBuffer, 0);
        frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
        frame.size =  stream->rec_buf_size;
        frame.bit_info = 0;
        frame.buf = (void *)buf;
        frame.timestamp.u64 = stream->rec_timestamp.u64;

        status = (*stream->rec_cb)(stream->user_data, &frame);
        (*jni_env)->ReleaseShortArrayElements(jni_env, inputBuffer, buf,
                                              JNI_ABORT);
        if (status != PJ_SUCCESS || stream->quit_flag)
            break;

        stream->rec_timestamp.u64 += stream->param.samples_per_frame /
                                     stream->param.channel_count;
    }

    (*jni_env)->DeleteLocalRef(jni_env, inputBuffer);

on_return:
    detach_jvm(attached);
    PJ_LOG(5, (THIS_FILE, "Recorder thread stopped"));
    stream->rec_thread_exited = 1;

    return 0;
}`
zhuangguangkang0013 commented 2 weeks ago

this call android record and playtrack. c file . https://github.com/pjsip/pjproject/blob/master/pjmedia/src/pjmedia-audiodev/android_jni_dev.c

"stream->running" may be need add mutx lock ? ` / API: start stream. / static pj_status_t strm_start(pjmedia_aud_stream s) { struct extern_aud_stream stream = (struct extern_aud_stream*)s; PJ_LOG(5, (THIS_FILE, "Recorder call start method %d",stream->running)); pj_mutex_lock(stream->lock); if (!stream->running) { stream->running = PJ_TRUE; if (stream->record) pj_sem_post(stream->rec_sem); if (stream->track) pj_sem_post(stream->play_sem); } pj_mutex_unlock(stream->lock); PJ_LOG(4, (THIS_FILE, "Extern Audio JNI stream started"));

return PJ_SUCCESS;

}

/ API: stop stream. / static pj_status_t strm_stop(pjmedia_aud_stream s) { struct extern_aud_stream stream = (struct extern_aud_stream*)s; PJ_LOG(5, (THIS_FILE, "Recorder call stop2 method %d",stream->running)); pj_mutex_lock(stream->lock); if (!stream->running){ pj_mutex_unlock(stream->lock); return PJ_SUCCESS; } stream->running = PJ_FALSE; pj_mutex_unlock(stream->lock); PJ_LOG(4,(THIS_FILE, "Extern Audio JNI stream stopped"));

return PJ_SUCCESS;

}`

trengginas commented 2 weeks ago

Because stream can be started and stopped (strm_start() and strm_stop()). e.g.: On stream stop/strm_stop():

zhuangguangkang0013 commented 2 weeks ago

因为流可以启动和停止(strm_start()strm_stop())。 例如: 在流停止/上strm_stop()

  • stream->running=PJ_FALSE;
  • AndroidRecorderCallback() 将进入 (!stream->running) 块并等待直到流恢复/strm_start()被调用。

This will cause repeated callbacks when first started. It will continuously call back start, stop, start. The MIC device will be restarted and turned on and off many times. Maybe there should be a different way to control the pause of the call mic?

trengginas commented 2 weeks ago

I can only see the record_method() called once at the start of the thread. It should be no issue when the stream is started. Is there any negative impact to application with one extra call to the record_method()?

zhuangguangkang0013 commented 1 week ago

I can only see the record_method() called once at the start of the thread. It should be no issue when the stream is started. Is there any negative impact to application with one extra call to the record_method()?

If other functions use MIC and need to mutually exclude SIP calls, then turn off other occupancy when MIC is ready to be turned on. If there are multiple callbacks, other functions will be turned on and off multiple times.