PJSUA2 - Recording call audio to wav file

2019-08-07 05:46发布

问题:

Using PJSUA2 I'm trying to record an incoming call directly to a wav file but can't hear any audio in the wav file.

Code below:

void SipCall::onCallMediaState(pj::OnCallMediaStateParam& /*prm*/)
{
    pj::CallInfo call_info = getInfo();
    pj::AudioMedia* audio_media = 0;

    for (unsigned int i = 0; i < call_info.media.size(); ++i) {
        if (call_info.media[i].type == PJMEDIA_TYPE_AUDIO) {
            audio_media = static_cast<pj::AudioMedia*>(getMedia(i));
            break;
        }
    }

     if (audio_media != 0) {
            try {    
                pj::AudioMediaRecorder recorder;
                recorder.createRecorder("file.wav");
                audio_media->startTransmit(recorder);   
                pj_thread_sleep(5000);
                audio_media->stopTransmit(recorder);   
            }  
            catch (pj::Error& err) {
                qWarning("[SipAccount::onIncomingCall] : Failed to record call to %s. Error = %s", "file.wav", err.info().data());    
           }        
      }
 }

There's poor documentation on PJSUA2 so does anyone have any idea what I'm doing wrong?

回答1:

There was a problem because the AudioMediaRecorder object went out of scope just after it was created. If you make it a member of the class the following will work.

void SipCall::onCallMediaState(pj::OnCallMediaStateParam& /*prm*/)
{
   pj::CallInfo call_info = getInfo();
   pj::AudioMedia* audio_media = 0;
   for (unsigned int i = 0; i < call_info.media.size(); ++i) {
      if (call_info.media[i].type == PJMEDIA_TYPE_AUDIO) {
        audio_media = static_cast<pj::AudioMedia*>(getMedia(i));
        break;
      }
   }

   if (audio_media != 0) {
        try {    
            recorder.createRecorder("file.wav");
            audio_media->startTransmit(recorder);   
        }  
        catch (pj::Error& err) {
            qWarning("[SipAccount::onIncomingCall] : Failed to record call to %s. Error = %s", "file.wav", err.info().data());    
       }        
    }
 }

Do any necessary cleanup in the onCallState() method below:

void SipCall::onCallState(pj::OnCallStateParam& prm)
{
    int i = prm.e.type;
    i = 0;

    pj::CallInfo call_info = getInfo();

    switch (call_info.state) {
       case PJSIP_INV_STATE_DISCONNECTED:
          // Add clean up code here
          delete this;        
          break;
       case PJSIP_INV_STATE_CONFIRMED:                        
          break;
       default:
          break;
   }
}


回答2:

I had the same issue while calling PJ through JNI. In my case I forgot to close the recorder. If you look close in the documentation, it says that you can't playback the wav file unless you close the recorder. So after you stop the transmission, do not forget to delete the recorder.



回答3:

The thing you're doing wrong is waiting in onCallMediaState's thread. In order to process the call further this thread has to proceed running. So, you create recorder, wait (while nothing happens, so you record nothing), close recorder, call continues. So nothing has been recorded. It has nothing to do with scope, because in your case recorder had already done his job recording nothing when got out of scope.

Main thing you needed to do is indeed not to wait in onCallMediaState's thread, let the call continue, and destroy the recorder when call is destroyed. For this to happen you need to get recorder declaration out of SipCall::onCallMediaState, of course or as you said recorder would get destroyed before it gets its job done.



标签: c++ pjsip