struct my_call_data *call_init_tonegen(pjsua_call_id call_id) { pj_pool_t *pool; struct my_call_data *cd; pjsua_call_info ci; if (call_id !=-1 ) { pjsua_call_get_info(call_id, &ci); if (ci.media_status != PJSUA_CALL_MEDIA_ACTIVE) return NULL; } pool = pjsua_pool_create("mycall", 512, 512); cd = PJ_POOL_ZALLOC_T(pool, struct my_call_data); cd->pool = pool; pjmedia_tonegen_create(cd->pool, 8000, 1, 160, 16, 0, &cd->tonegen); pjsua_conf_add_port(cd->pool, cd->tonegen, &cd->toneslot); if (call_id !=-1 ) { pjsua_conf_connect(cd->toneslot, ci.conf_slot); } if (accountSettings.localDTMF) { pjsua_conf_connect(cd->toneslot, 0); } if (call_id !=-1 ) { pjsua_call_set_user_data(call_id, (void*) cd); } return cd; }
struct my_call_data *call_init_tonegen(pjsua_call_id call_id) { pj_pool_t *pool; struct my_call_data *cd; pjsua_call_info ci; if (call_id !=-1 ) { pjsua_call_get_info(call_id, &ci); } pool = pjsua_pool_create("mycall", 512, 512); cd = PJ_POOL_ZALLOC_T(pool, struct my_call_data); cd->pool = pool; pjmedia_tonegen_create(cd->pool, 8000, 1, 160, 16, 0, &cd->tonegen); pjsua_conf_add_port(cd->pool, cd->tonegen, &cd->toneslot); if (call_id !=-1 ) { pjsua_conf_connect(cd->toneslot, ci.conf_slot); } pjsua_conf_connect(cd->toneslot, 0); if(call_id !=-1) { pjsua_call_set_user_data(call_id, (void*) cd); } return cd; }
/* Callback called by PJSUA when call's media state has changed */ static void on_call_media_state(pjsua_call_id call_id) { qDebug() << "Call media state"; pjsua_call_info ci; if (pjsua_call_get_info(call_id, &ci) != PJ_SUCCESS) { return; } pjsua_conf_connect(ci.conf_slot, 0); pjsua_conf_connect(0, ci.conf_slot); }
/* Callback called by the library when call's media state has changed */ static void on_call_media_state(pjsua_call_id call_id) { pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { // When media is active, connect call to sound device. pjsua_conf_connect(ci.conf_slot, 0); pjsua_conf_connect(0, ci.conf_slot); } }
/* * Callback on media state changed event. * The action may connect the call to sound device, to file, or * to loop the call. */ static void on_call_media_state (pjsua_call_id call_id) { pjsua_call_info call_info; pjsua_call_get_info (call_id, &call_info); if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { pjsua_conf_connect (call_info.conf_slot, 0); pjsua_conf_connect (0, call_info.conf_slot); } }
void QPhoneHandler::onCallMediaState(qpjsua::CallInfo aCallInfo) { callInfoOut(aCallInfo); if(aCallInfo.getMediaStatus() == PJSUA_CALL_MEDIA_ACTIVE) { pjsua_conf_connect(0, aCallInfo.getConferenceSlot()); pjsua_conf_connect(aCallInfo.getConferenceSlot(), 0); // view->setButtonText("Auflegen"); // connect(view, SIGNAL(accept()), SLOT(onHangup())); } }
//---------------------------------------------------------------------- void SipPhone::callMediaStateCb(pjsua_call_id call_id) { pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { // When media is active, connect call to sound device. pjsua_conf_connect(ci.conf_slot, 0); pjsua_conf_connect(0, ci.conf_slot); } LogInfo info(LogInfo::STATUS_DEBUG, "pjsip", 0, "Call-media-state changed to "+QString::number(ci.state)); self_->signalLogData(info); }
static void ui_conf_connect(char menuin[]) { char tmp[10], src_port[10], dst_port[10]; pj_status_t status; int cnt; const char *src_title, *dst_title; cnt = sscanf(menuin, "%s %s %s", tmp, src_port, dst_port); if (cnt != 3) { ui_conf_list(); src_title = (menuin[1]=='c'? "Connect src port #": "Disconnect src port #"); dst_title = (menuin[1]=='c'? "To dst port #":"From dst port #"); if (!simple_input(src_title, src_port, sizeof(src_port))) return; if (!simple_input(dst_title, dst_port, sizeof(dst_port))) return; } if (menuin[1]=='c') { status = pjsua_conf_connect(my_atoi(src_port), my_atoi(dst_port)); } else { status = pjsua_conf_disconnect(my_atoi(src_port), my_atoi(dst_port)); } if (status == PJ_SUCCESS) { puts("Success"); } else { puts("ERROR!!"); } }
// helper for creating call-media-player static void create_player(pjsua_call_id call_id) { // get call infos pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); pj_str_t name; pj_status_t status = PJ_ENOTFOUND; log_message("Creating player ... "); // create player for playback media if (app_cfg.wav_file) { status = pjsua_player_create(pj_cstr(&name, app_cfg.wav_file), 0, &play_id); } else { status = pjsua_player_create(pj_cstr(&name, app_cfg.tts_file), 0, &play_id); } if (status != PJ_SUCCESS) error_exit("Error playing sound-playback", status); // connect active call to media player pjsua_conf_connect(pjsua_player_get_conf_port(play_id), ci.conf_slot); // get media port (play_port) from play_id status = pjsua_player_get_port(play_id, &play_port); if (status != PJ_SUCCESS) error_exit("Error getting sound player port", status); // register media finished callback status = pjmedia_wav_player_set_eof_cb(play_port, NULL, &on_media_finished); if (status != PJ_SUCCESS) error_exit("Error adding sound-playback callback", status); log_message("Done.\n"); }
//---------------------------------------------------------------------- bool SipPhone::addCallToConference(const int &call_src, const int &call_dest) { int src = call_src; int dest = call_dest; if (src == -1 || dest == -1) { LogInfo info(LogInfo::STATUS_ERROR, "pjsip", 0, "Error: one of the selected calls does NOT exist!"); signalLogData(info); return false; } pjsua_call_info src_ci, dest_ci; pjsua_call_get_info(src,&src_ci); pjsua_call_get_info(dest,&dest_ci); pj_status_t status = pjsua_conf_connect(src_ci.conf_slot,dest_ci.conf_slot); if (status != PJ_SUCCESS) { LogInfo info(LogInfo::STATUS_ERROR, "pjsip", status, "Error connecting conference!"); signalLogData(info); return false; } return true; }
/***************************************************************************** * test: play WAV file */ static void systest_play_wav(unsigned path_cnt, const char *paths[]) { pjsua_player_id play_id = PJSUA_INVALID_ID; enum gui_key key; test_item_t *ti; const char *title = "WAV File Playback Test"; pj_status_t status; ti = systest_alloc_test_item(title); if (!ti) return; pj_ansi_snprintf(textbuf, sizeof(textbuf), "This test will play %s file to " "the speaker. Please listen carefully for audio " "impairments such as stutter. Let this test run " "for a while to make sure that everything is okay." " Press OK to start, CANCEL to skip", paths[0]); key = gui_msgbox(title, textbuf, WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } PJ_LOG(3,(THIS_FILE, "Running %s", title)); /* WAV port */ status = create_player(path_cnt, paths, &play_id); if (status != PJ_SUCCESS) goto on_return; status = pjsua_conf_connect(pjsua_player_get_conf_port(play_id), 0); if (status != PJ_SUCCESS) goto on_return; key = gui_msgbox(title, "WAV file should be playing now in the " "speaker. Press OK to stop. ", WITH_OK); status = PJ_SUCCESS; on_return: if (play_id != -1) pjsua_player_destroy(play_id); if (status != PJ_SUCCESS) { systest_perror("Sorry we've encountered error", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); } else { key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO); ti->success = (key == KEY_YES); if (!ti->success) pj_ansi_strcpy(ti->reason, USER_ERROR); } return; }
void ringback_start(){ if (app_config.ringback_on) { //Already ringing back return; } app_config.ringback_on = PJ_TRUE; if (++app_config.ringback_cnt==1 && app_config.ringback_slot!=PJSUA_INVALID_ID){ pjsua_conf_connect(app_config.ringback_slot, 0); } }
void ringback_start() { if (css_var.ringback_on) { //Already ringing back return; } css_var.ringback_on = PJ_TRUE; if (++css_var.ringback_cnt == 1 && css_var.ringback_slot != PJSUA_INVALID_ID) { pjsua_conf_connect(css_var.ringback_slot, 0); } }
void SipAccount::onCallMediaState(pjsua_call_id call_id) { Logger::debug("SipAccount::onCallMediaState(call_id=%d)...", call_id); pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { // connect active call to silence pjsua_conf_connect(m_pPhone->getMediaConfSilenceId(), ci.conf_slot); } }
void QVDoorcom::onIncomingCall(int call_id) { pj_status_t status; if (active_call >= 0) { return; } qDebug() << "incoming call" << call_id; active_call = call_id; w_dooropen->hide(); popup->show(); #ifdef DOORBELL_WAV status = pjmedia_wav_player_port_set_pos(bell_file_port,0); qDebug() << "Rewind status" << status; if (status == PJ_SUCCESS) { pjsua_conf_connect(bell_port_id,0); // pjsua_conf_adjust_tx_level(0,1.0); } #else pjsua_conf_connect(bell_port_id,0); #endif }
void MainWin::on_call_media_state(pjsua_call_id call_id) { pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); for (unsigned i=0; i<ci.media_cnt; ++i) { if (ci.media[i].type == PJMEDIA_TYPE_AUDIO) { switch (ci.media[i].status) { case PJSUA_CALL_MEDIA_ACTIVE: pjsua_conf_connect(ci.media[i].stream.aud.conf_slot, 0); pjsua_conf_connect(0, ci.media[i].stream.aud.conf_slot); break; default: break; } } else if (ci.media[i].type == PJMEDIA_TYPE_VIDEO) { emit signalInitVideoWindow(); } } }
void BlabbleCall::OnCallMediaState() { if (call_id_ == INVALID_CALL) return; pjsua_call_info info; pj_status_t status; if ((status = pjsua_call_get_info(call_id_, &info)) != PJ_SUCCESS) { BLABBLE_LOG_ERROR("Unable to get call info. PJSIP call id: " << call_id_ << ", global id: " << id_ << ", pjsua_call_get_info returned " << status); StopRinging(); return; } if (info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { StopRinging(); // When media is active, connect call to sound device. pjsua_conf_connect(info.conf_slot, 0); pjsua_conf_connect(0, info.conf_slot); } }
static void on_call_media_state(pjsua_call_id call_id) { ics_t *data; pjsua_call_info ci; pjsua_call_get_info(call_id, &ci); //! Khoi tao mot connect media flow tu app nay sang app khac if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { pjsua_conf_connect(ci.conf_slot, 0); // ntt1->quy pjsua_conf_connect(0, ci.conf_slot); // quy->ntt1 } pjsua_call_get_info(call_id, &ci); data = (ics_t *)pjsua_acc_get_user_data(ci.acc_id); opool_item_t *p_item = opool_get(&data->opool); build_call_media_state_event((ics_event_t *)p_item->data, call_id, ci.media_status); ics_event_t *event = (ics_event_t *)p_item->data; // queue_enqueue(&data->queue, (void *)p_item); process_event(event); }
static void _ics_conference_call(ics_t *data, int call_id) { int i, max; PJ_UNUSED_ARG(data); max = pjsua_call_get_count(); SHOW_LOG(3, "Let's conference call!\n"); pjsua_call_info ci; #if 1 if ( (call_id != current_call) && pjsua_call_is_active(call_id) ) { pjsua_call_reinvite(call_id, PJ_TRUE, NULL); for (i = 0; i < max; i++) { if (pjsua_call_has_media(i) != 0) { pjsua_conf_connect(pjsua_call_get_conf_port(call_id), pjsua_call_get_conf_port(i)); pjsua_conf_connect(pjsua_call_get_conf_port(i), pjsua_call_get_conf_port(call_id)); } } } else SHOW_LOG(3, "Cannot transfer call!\n"); #endif //For test only: #if 1 for (i = 0; i < max; i++){ if (pjsua_call_is_active(i) && (i != current_call)) { pjsua_call_reinvite(i, PJ_TRUE, NULL); pjsua_call_get_info(i, &ci); pjsua_conf_connect(pjsua_call_get_conf_port(ci.id), pjsua_call_get_conf_port(current_call)); pjsua_conf_connect(pjsua_call_get_conf_port(current_call), pjsua_call_get_conf_port(ci.id)); } break; } #endif }
void QVDoorcom::onCallState(int call_id, QString state) { if (call_id != active_call) { return; } qDebug() << "new state" << state; if (state == "DISCONNCTD") { popup->hide(); active_call = -1; // pjsua_conf_adjust_tx_level(0,0.0); } if (state == "CONFIRMED") { w_dooropen->show(); /* Create DTMF generator */ pjsua_call_info ci; qDebug() << "2" << pjmedia_tonegen_create(pj_pool, 16000, 1, 160, 16, 0, &pj_tonegen); qDebug() << "3" << pjsua_conf_add_port(pj_pool, pj_tonegen, &pj_toneslot); pjsua_call_get_info(call_id, &ci); qDebug() << "4" << pjsua_conf_connect(pj_toneslot, ci.conf_slot); /* Send DTMF code */ if (!code_accept.isEmpty()) { qDebug() << "accept code" << code_accept; pjmedia_tone_digit d[16]; unsigned i, count = code_accept.length(); if (count > PJ_ARRAY_SIZE(d)) { count = PJ_ARRAY_SIZE(d); } pj_bzero(d, sizeof(d)); for (i=0; i<count; i++) { d[i].digit = code_accept.at(i).toLatin1(); d[i].on_msec = 80; d[i].off_msec = 80; d[i].volume = 32767; } qDebug() << "before tonegen"; qDebug() << "tonegen result " << pjmedia_tonegen_play_digits(pj_tonegen, count, d, 0); dtmf_timer.start(); } } }
// helper for creating call-recorder static void create_recorder(pjsua_call_info ci) { // specify target file pj_str_t rec_file = pj_str(app_cfg.record_file); pj_status_t status = PJ_ENOTFOUND; log_message("Creating recorder ... "); // Create recorder for call status = pjsua_recorder_create(&rec_file, 0, NULL, 0, 0, &rec_id); if (status != PJ_SUCCESS) error_exit("Error recording answer", status); // connect active call to call recorder pjsua_conf_port_id rec_port = pjsua_recorder_get_conf_port(rec_id); pjsua_conf_connect(ci.conf_slot, rec_port); log_message("Done.\n"); }
/***************************************************************************** * test: play simple ringback tone and hear it */ static void systest_play_tone(void) { /* Ringtones */ #define RINGBACK_FREQ1 440 /* 400 */ #define RINGBACK_FREQ2 480 /* 450 */ #define RINGBACK_ON 3000 /* 400 */ #define RINGBACK_OFF 4000 /* 200 */ #define RINGBACK_CNT 1 /* 2 */ #define RINGBACK_INTERVAL 4000 /* 2000 */ unsigned i, samples_per_frame; pjmedia_tone_desc tone[RINGBACK_CNT]; pj_pool_t *pool = NULL; pjmedia_port *ringback_port = NULL; enum gui_key key; int ringback_slot = -1; test_item_t *ti; pj_str_t name; const char *title = "Audio Tone Playback Test"; pj_status_t status; ti = systest_alloc_test_item(title); if (!ti) return; key = gui_msgbox(title, "This test will play simple ringback tone to " "the speaker. Please listen carefully for audio " "impairments such as stutter. You may need " "to let this test running for a while to " "make sure that everything is okay. Press " "OK to start, CANCEL to skip", WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } PJ_LOG(3,(THIS_FILE, "Running %s", title)); pool = pjsua_pool_create("ringback", 512, 512); samples_per_frame = systest.media_cfg.audio_frame_ptime * systest.media_cfg.clock_rate * systest.media_cfg.channel_count / 1000; /* Ringback tone (call is ringing) */ name = pj_str("ringback"); status = pjmedia_tonegen_create2(pool, &name, systest.media_cfg.clock_rate, systest.media_cfg.channel_count, samples_per_frame, 16, PJMEDIA_TONEGEN_LOOP, &ringback_port); if (status != PJ_SUCCESS) goto on_return; pj_bzero(&tone, sizeof(tone)); for (i=0; i<RINGBACK_CNT; ++i) { tone[i].freq1 = RINGBACK_FREQ1; tone[i].freq2 = RINGBACK_FREQ2; tone[i].on_msec = RINGBACK_ON; tone[i].off_msec = RINGBACK_OFF; } tone[RINGBACK_CNT-1].off_msec = RINGBACK_INTERVAL; status = pjmedia_tonegen_play(ringback_port, RINGBACK_CNT, tone, PJMEDIA_TONEGEN_LOOP); if (status != PJ_SUCCESS) goto on_return; status = pjsua_conf_add_port(pool, ringback_port, &ringback_slot); if (status != PJ_SUCCESS) goto on_return; status = pjsua_conf_connect(ringback_slot, 0); if (status != PJ_SUCCESS) goto on_return; key = gui_msgbox(title, "Ringback tone should be playing now in the " "speaker. Press OK to stop. ", WITH_OK); status = PJ_SUCCESS; on_return: if (ringback_slot != -1) pjsua_conf_remove_port(ringback_slot); if (ringback_port) pjmedia_port_destroy(ringback_port); if (pool) pj_pool_release(pool); if (status != PJ_SUCCESS) { systest_perror("Sorry we encounter error when initializing " "the tone generator: ", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); } else { key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO); ti->success = (key == KEY_YES); if (!ti->success) pj_ansi_strcpy(ti->reason, USER_ERROR); } return; }
int dll_playWav(char* wavFile, int callId) { pj_status_t status; /* Infos Player */ pjsua_player_id player_id; // Ident. for the player pjmedia_port *media_port; // Struct. media_port pjsua_conf_port_id conf_port; // Conference port for the player /* Infos Call Session */ pjsua_call_info call_info; /******************************************** / 1- Check if Call exists and is active ********************************************/ // Get call_info from callId pjsua_call_get_info(callId, &call_info); if (call_info.media_status != PJSUA_CALL_MEDIA_ACTIVE) return -1; /******************************************** / 2- Load the WAV File - Create the player ********************************************/ status = pjsua_player_create(&pj_str(wavFile), PJMEDIA_FILE_NO_LOOP, &player_id); /******************************************** / 3- Register the Callback C++ Function "on_wavplayerEof_callback" ********************************************/ if (status == PJ_SUCCESS) { // Get media_port from player_id status = pjsua_player_get_port(player_id, &media_port); } if (status == PJ_SUCCESS) { // Prepare argument for Callback wavplayerEof_Data* args = (wavplayerEof_Data*)malloc(sizeof(wavplayerEof_Data)); args->playerId = player_id; args->callId = callId; // Register the Callback, launched when the End of the Wave File is reached status = pjmedia_wav_player_set_eof_cb(media_port, args, &on_wavplayerEof_callback); } /******************************************** / 4- Stream the file to the Call Session ********************************************/ // Get conf_port from player_id if (status == PJ_SUCCESS) conf_port = pjsua_player_get_conf_port(player_id); // one way connect conf_port (wav player) to call_info.conf_slot (call) if ((status == PJ_SUCCESS)&&(conf_port != PJSUA_INVALID_ID)&&(call_info.conf_slot != 0)) // test if conf_port valid, and if conf_slot != soundcard { status = pjsua_conf_connect(conf_port, call_info.conf_slot); } PJ_LOG(3,(THIS_FILE,"Wav Play, status %d",status)); if (status != PJ_SUCCESS) return -1; return player_id; }
/* * Callback on media state changed event. * The action may connect the call to sound device, to file, or * to loop the call. */ static void on_call_media_state(pjsua_call_id call_id) { pjsua_call_info call_info; pjsua_call_get_info(call_id, &call_info); /* Connect ports appropriately when media status is ACTIVE or REMOTE HOLD, * otherwise we should NOT connect the ports. */ if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE || call_info.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) { pj_bool_t connect_sound = PJ_TRUE; /* Loopback sound, if desired */ if (app_config.auto_loop) { pjsua_conf_connect(call_info.conf_slot, call_info.conf_slot); connect_sound = PJ_FALSE; } /* Automatically record conversation, if desired */ if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { pjsua_conf_connect(call_info.conf_slot, app_config.rec_port); } /* Stream a file, if desired */ if ((app_config.auto_play || app_config.auto_play_hangup) && app_config.wav_port != PJSUA_INVALID_ID) { pjsua_conf_connect(app_config.wav_port, call_info.conf_slot); connect_sound = PJ_FALSE; } /* Put call in conference with other calls, if desired */ if (app_config.auto_conf) { pjsua_call_id call_ids[PJSUA_MAX_CALLS]; unsigned call_cnt=PJ_ARRAY_SIZE(call_ids); unsigned i; /* Get all calls, and establish media connection between * this call and other calls. */ pjsua_enum_calls(call_ids, &call_cnt); for (i=0; i<call_cnt; ++i) { if (call_ids[i] == call_id) continue; if (!pjsua_call_has_media(call_ids[i])) continue; pjsua_conf_connect(call_info.conf_slot, pjsua_call_get_conf_port(call_ids[i])); pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]), call_info.conf_slot); /* Automatically record conversation, if desired */ if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]), app_config.rec_port); } } /* Also connect call to local sound device */ connect_sound = PJ_TRUE; } /* Otherwise connect to sound device */ if (connect_sound) { pjsua_conf_connect(call_info.conf_slot, 0); pjsua_conf_connect(0, call_info.conf_slot); /* Automatically record conversation, if desired */ if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) { pjsua_conf_connect(call_info.conf_slot, app_config.rec_port); pjsua_conf_connect(0, app_config.rec_port); } } } PJ_LOG(3,(THIS_FILE, "Media for call %d is active", call_id)); /* Handle media status */ switch (call_info.media_status) { case PJSUA_CALL_MEDIA_ACTIVE: PJ_LOG(3,(THIS_FILE, "Media for call %d is active", call_id)); break; case PJSUA_CALL_MEDIA_LOCAL_HOLD: PJ_LOG(3,(THIS_FILE, "Media for call %d is suspended (hold) by local", call_id)); // call on call hold handler cb_callholdconf(call_id); break; case PJSUA_CALL_MEDIA_REMOTE_HOLD: PJ_LOG(3,(THIS_FILE, "Media for call %d is suspended (hold) by remote", call_id)); break; case PJSUA_CALL_MEDIA_ERROR: PJ_LOG(3,(THIS_FILE, "Media has reported error, disconnecting call")); { pj_str_t reason = pj_str("ICE negotiation failed"); pjsua_call_hangup(call_id, 500, &reason, NULL); } break; case PJSUA_CALL_MEDIA_NONE: PJ_LOG(3,(THIS_FILE, "Media for call %d is inactive", call_id)); break; default: pj_assert(!"Unhandled media status"); break; } }
static void systest_aec_test(void) { const char *ref_wav_paths[] = { add_path(res_path, WAV_PLAYBACK_PATH), ALT_PATH1 WAV_PLAYBACK_PATH }; pjsua_player_id player_id = PJSUA_INVALID_ID; pjsua_recorder_id writer_id = PJSUA_INVALID_ID; enum gui_key key; test_item_t *ti; const char *title = "AEC/AES Test"; unsigned last_ec_tail = 0; pj_status_t status; pj_str_t tmp; ti = systest_alloc_test_item(title); if (!ti) return; key = gui_msgbox(title, "This test will try to find whether the AEC/AES " "works good on this system. Test will play a file " "while recording from mic. The recording will be " "played back later so you can check if echo is there. " "Press OK to start.", WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } /* Save current EC tail */ status = pjsua_get_ec_tail(&last_ec_tail); if (status != PJ_SUCCESS) goto on_return; /* Set EC tail setting to default */ status = pjsua_set_ec(PJSUA_DEFAULT_EC_TAIL_LEN, 0); if (status != PJ_SUCCESS) goto on_return; /* * Create player and recorder */ status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths, &player_id); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s", WAV_PLAYBACK_PATH)); goto on_return; } status = pjsua_recorder_create( pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)), 0, 0, -1, 0, &writer_id); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error writing WAV file %s", AEC_REC_PATH)); goto on_return; } /* * Start playback and recording. */ pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0); pj_thread_sleep(100); pjsua_conf_connect(0, pjsua_recorder_get_conf_port(writer_id)); /* Wait user signal */ gui_msgbox(title, "AEC/AES test is running. Press OK to stop this test.", WITH_OK); /* * Stop and close playback and recorder */ pjsua_conf_disconnect(0, pjsua_recorder_get_conf_port(writer_id)); pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0); pjsua_recorder_destroy(writer_id); pjsua_player_destroy(player_id); player_id = PJSUA_INVALID_ID; writer_id = PJSUA_INVALID_ID; /* * Play the result. */ status = pjsua_player_create( pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)), 0, &player_id); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s", AEC_REC_PATH)); goto on_return; } pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0); /* Wait user signal */ gui_msgbox(title, "We are now playing the captured audio from the mic. " "Check if echo (of the audio played back previously) is " "present in the audio. The recording is stored in " AEC_REC_PATH " for offline analysis. " "Press OK to stop.", WITH_OK); pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0); key = gui_msgbox(title, "Did you notice any echo in the recording?", WITH_YESNO); on_return: if (player_id != PJSUA_INVALID_ID) pjsua_player_destroy(player_id); if (writer_id != PJSUA_INVALID_ID) pjsua_recorder_destroy(writer_id); /* Wait until sound device closed before restoring back EC tail setting */ while (pjsua_snd_is_active()) pj_thread_sleep(10); pjsua_set_ec(last_ec_tail, 0); if (status != PJ_SUCCESS) { systest_perror("Sorry we encountered an error: ", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); } else if (key == KEY_YES) { ti->success = PJ_FALSE; if (!ti->success) { pj_ansi_strcpy(ti->reason, USER_ERROR); } } else { char msg[200]; pj_ansi_snprintf(msg, sizeof(msg), "Test succeeded.\r\n"); ti->success = PJ_TRUE; pj_ansi_strncpy(ti->reason, msg, sizeof(ti->reason)); ti->reason[sizeof(ti->reason)-1] = '\0'; } }
static void systest_latency_test(void) { const char *ref_wav_paths[] = { add_path(res_path, WAV_TOCK8_PATH), ALT_PATH1 WAV_TOCK8_PATH }; pj_str_t rec_wav_file; pjsua_player_id play_id = PJSUA_INVALID_ID; pjsua_conf_port_id play_slot = PJSUA_INVALID_ID; pjsua_recorder_id rec_id = PJSUA_INVALID_ID; pjsua_conf_port_id rec_slot = PJSUA_INVALID_ID; pj_pool_t *pool = NULL; pjmedia_port *wav_port = NULL; unsigned lat_sum=0, lat_cnt=0, lat_min=0, lat_max=0; enum gui_key key; test_item_t *ti; const char *title = "Audio Latency Test"; pj_status_t status; ti = systest_alloc_test_item(title); if (!ti) return; key = gui_msgbox(title, "This test will try to find the audio device's " "latency. We will play a special WAV file to the " "speaker for ten seconds, then at the end " "calculate the latency. Please don't do anything " "until the test is done.", WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } key = gui_msgbox(title, "For this test to work, we must be able to capture " "the audio played in the speaker (the echo), and only" " that audio (i.e. you must be in relatively quiet " "place to run this test). " "Press OK to start, or CANCEL to skip.", WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } PJ_LOG(3,(THIS_FILE, "Running %s", title)); status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths, &play_id); if (status != PJ_SUCCESS) goto on_return; play_slot = pjsua_player_get_conf_port(play_id); rec_wav_file = pj_str(add_path(doc_path, WAV_LATENCY_OUT_PATH)); status = pjsua_recorder_create(&rec_wav_file, 0, NULL, -1, 0, &rec_id); if (status != PJ_SUCCESS) goto on_return; rec_slot = pjsua_recorder_get_conf_port(rec_id); /* Setup the test */ //status = pjsua_conf_connect(0, 0); status = pjsua_conf_connect(play_slot, 0); status = pjsua_conf_connect(0, rec_slot); status = pjsua_conf_connect(play_slot, rec_slot); /* We're running */ PJ_LOG(3,(THIS_FILE, "Please wait while test is running (~10 sec)")); gui_sleep(10); /* Done with the test */ //status = pjsua_conf_disconnect(0, 0); status = pjsua_conf_disconnect(play_slot, rec_slot); status = pjsua_conf_disconnect(0, rec_slot); status = pjsua_conf_disconnect(play_slot, 0); pjsua_recorder_destroy(rec_id); rec_id = PJSUA_INVALID_ID; pjsua_player_destroy(play_id); play_id = PJSUA_INVALID_ID; /* Confirm that echo is heard */ gui_msgbox(title, "Test is done. Now we need to confirm that we indeed " "captured the echo. We will play the captured audio " "and please confirm that you can hear the 'tock' echo.", WITH_OK); status = pjsua_player_create(&rec_wav_file, 0, &play_id); if (status != PJ_SUCCESS) goto on_return; play_slot = pjsua_player_get_conf_port(play_id); status = pjsua_conf_connect(play_slot, 0); if (status != PJ_SUCCESS) goto on_return; key = gui_msgbox(title, "The captured audio is being played back now. " "Can you hear the 'tock' echo?", WITH_YESNO); pjsua_player_destroy(play_id); play_id = PJSUA_INVALID_ID; if (key != KEY_YES) goto on_return; /* Now analyze the latency */ pool = pjsua_pool_create("latency", 512, 512); status = pjmedia_wav_player_port_create(pool, rec_wav_file.ptr, 0, 0, 0, &wav_port); if (status != PJ_SUCCESS) goto on_return; status = calculate_latency(pool, wav_port, &lat_sum, &lat_cnt, &lat_min, &lat_max); if (status != PJ_SUCCESS) goto on_return; on_return: if (wav_port) pjmedia_port_destroy(wav_port); if (pool) pj_pool_release(pool); if (play_id != PJSUA_INVALID_ID) pjsua_player_destroy(play_id); if (rec_id != PJSUA_INVALID_ID) pjsua_recorder_destroy(rec_id); if (status != PJ_SUCCESS) { systest_perror("Sorry we encountered an error: ", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); } else if (key != KEY_YES) { ti->success = PJ_FALSE; if (!ti->success) { pj_ansi_strcpy(ti->reason, USER_ERROR); } } else { char msg[200]; pj_size_t msglen; pj_ansi_snprintf(msg, sizeof(msg), "The sound device latency:\r\n" " Min=%u, Max=%u, Avg=%u\r\n", lat_min, lat_max, lat_sum/lat_cnt); msglen = strlen(msg); if (lat_sum/lat_cnt > 500) { pj_ansi_snprintf(msg+msglen, sizeof(msg)-msglen, "The latency is huge!\r\n"); msglen = strlen(msg); } else if (lat_sum/lat_cnt > 200) { pj_ansi_snprintf(msg+msglen, sizeof(msg)-msglen, "The latency is quite high\r\n"); msglen = strlen(msg); } key = gui_msgbox(title, msg, WITH_OK); ti->success = PJ_TRUE; pj_ansi_strncpy(ti->reason, msg, sizeof(ti->reason)); ti->reason[sizeof(ti->reason)-1] = '\0'; } }
/***************************************************************************** * test: record audio */ static void systest_rec_audio(void) { const pj_str_t filename = pj_str(add_path(doc_path, WAV_REC_OUT_PATH)); pj_pool_t *pool = NULL; enum gui_key key; pjsua_recorder_id rec_id = PJSUA_INVALID_ID; pjsua_player_id play_id = PJSUA_INVALID_ID; pjsua_conf_port_id rec_slot = PJSUA_INVALID_ID; pjsua_conf_port_id play_slot = PJSUA_INVALID_ID; pj_status_t status = PJ_SUCCESS; const char *title = "Audio Recording"; test_item_t *ti; ti = systest_alloc_test_item(title); if (!ti) return; key = gui_msgbox(title, "This test will allow you to record audio " "from the microphone, and playback the " "audio to the speaker. Press OK to start recording, " "CANCEL to skip.", WITH_OKCANCEL); if (key != KEY_OK) { ti->skipped = PJ_TRUE; return; } PJ_LOG(3,(THIS_FILE, "Running %s", title)); pool = pjsua_pool_create("rectest", 512, 512); status = pjsua_recorder_create(&filename, 0, NULL, -1, 0, &rec_id); if (status != PJ_SUCCESS) goto on_return; rec_slot = pjsua_recorder_get_conf_port(rec_id); status = pjsua_conf_connect(0, rec_slot); if (status != PJ_SUCCESS) goto on_return; key = gui_msgbox(title, "Recording is in progress now, please say " "something in the microphone. Press OK " "to stop recording", WITH_OK); pjsua_conf_disconnect(0, rec_slot); rec_slot = PJSUA_INVALID_ID; pjsua_recorder_destroy(rec_id); rec_id = PJSUA_INVALID_ID; status = pjsua_player_create(&filename, 0, &play_id); if (status != PJ_SUCCESS) goto on_return; play_slot = pjsua_player_get_conf_port(play_id); status = pjsua_conf_connect(play_slot, 0); if (status != PJ_SUCCESS) goto on_return; key = gui_msgbox(title, "Recording has been stopped. " "The recorded audio is being played now to " "the speaker device, in a loop. Listen for " "any audio impairments. Press OK to stop.", WITH_OK); on_return: if (rec_slot != PJSUA_INVALID_ID) pjsua_conf_disconnect(0, rec_slot); if (rec_id != PJSUA_INVALID_ID) pjsua_recorder_destroy(rec_id); if (play_slot != PJSUA_INVALID_ID) pjsua_conf_disconnect(play_slot, 0); if (play_id != PJSUA_INVALID_ID) pjsua_player_destroy(play_id); if (pool) pj_pool_release(pool); if (status != PJ_SUCCESS) { systest_perror("Sorry we encountered an error: ", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); } else { key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO); ti->success = (key == KEY_YES); if (!ti->success) { pj_ansi_snprintf(textbuf, sizeof(textbuf), "You will probably need to copy the recorded " "WAV file %s to a desktop computer and analyze " "it, to find out whether it's a recording " "or playback problem.", WAV_REC_OUT_PATH); gui_msgbox(title, textbuf, WITH_OK); pj_ansi_strcpy(ti->reason, USER_ERROR); } } }