// 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"); }
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); } } }