static int parse_test(void) { unsigned i; for (i=0; i<PJ_ARRAY_SIZE(p_tests); ++i) { pj_pool_t *pool; pjsip_media_type ctype; pjsip_msg_body *body; pj_str_t str; int rc; pool = pjsip_endpt_create_pool(endpt, NULL, 512, 512); init_media_type(&ctype, p_tests[i].ctype, p_tests[i].csubtype, p_tests[i].boundary); pj_strdup2_with_null(pool, &str, p_tests[i].msg); body = pjsip_multipart_parse(pool, str.ptr, str.slen, &ctype, 0); if (!body) return -100; if (p_tests[i].verify) { rc = p_tests[i].verify(pool, body); } else { rc = 0; } pj_pool_release(pool); if (rc) return rc; } return 0; }
static void zrtpShowSas(void* data, char* sas, int verified){ zrtp_cb_user_data* zrtp_data = (zrtp_cb_user_data*) data; PJ_LOG(4, (THIS_FILE, "Show sas : %s in ctxt %x", sas, zrtp_data)); pj_strdup2_with_null(css_var.pool, &zrtp_data->sas, sas); zrtp_data->sas_verified = verified; on_zrtp_show_sas_wrapper(zrtp_data->call_id, sas, verified); }
/**************** UTILS ******************/ static pjmedia_sdp_session *create_sdp(pj_pool_t *pool, const char *body) { pjmedia_sdp_session *sdp; pj_str_t dup; pj_status_t status; pj_strdup2_with_null(pool, &dup, body); status = pjmedia_sdp_parse(pool, dup.ptr, dup.slen, &sdp); pj_assert(status == PJ_SUCCESS); return sdp; }
/*! \brief Internal function which adds a contact to a response */ static int registrar_add_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; pjsip_tx_data *tdata = arg; pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool); pj_str_t uri; pj_strdup2_with_null(tdata->pool, &uri, contact->uri); hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR); hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); return 0; }
/*! \brief Helper function which validates a permanent contact */ static int permanent_contact_validate(void *data) { const char *value = data; pj_pool_t *pool; pj_str_t contact_uri; static const pj_str_t HCONTACT = { "Contact", 7 }; pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Permanent Contact Validation", 256, 256); if (!pool) { return -1; } pj_strdup2_with_null(pool, &contact_uri, value); if (!pjsip_parse_hdr(pool, &HCONTACT, contact_uri.ptr, contact_uri.slen, NULL)) { pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); return -1; } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); return 0; }
/* Set default config. */ static void default_config(struct app_config *cfg) { char tmp[80]; unsigned i; pjsua_config_default(&cfg->cfg); pj_ansi_sprintf(tmp, "Sipek on PJSUA v%s/%s", pj_get_version(), PJ_OS_NAME); pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp); pjsua_logging_config_default(&cfg->log_cfg); pjsua_media_config_default(&cfg->media_cfg); pjsua_transport_config_default(&cfg->udp_cfg); cfg->udp_cfg.port = 5060; pjsua_transport_config_default(&cfg->rtp_cfg); cfg->rtp_cfg.port = 4000; cfg->duration = NO_LIMIT; cfg->wav_id = PJSUA_INVALID_ID; cfg->rec_id = PJSUA_INVALID_ID; cfg->wav_port = PJSUA_INVALID_ID; cfg->rec_port = PJSUA_INVALID_ID; cfg->mic_level = cfg->speaker_level = 1.0; cfg->capture_dev = PJSUA_INVALID_ID; cfg->playback_dev = PJSUA_INVALID_ID; cfg->capture_lat = PJMEDIA_SND_DEFAULT_REC_LATENCY; cfg->playback_lat = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; cfg->ringback_slot = PJSUA_INVALID_ID; cfg->ring_slot = PJSUA_INVALID_ID; for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i) pjsua_acc_config_default(&cfg->acc_cfg[i]); for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i) pjsua_buddy_config_default(&cfg->buddy_cfg[i]); cfg->log_cfg.log_filename = pj_str("pjsip.log"); }
pj_str_t jzrtp_getInfo(pjmedia_transport* tp) { pj_str_t result; char msg[512]; ZrtpContext *ctx = pjmedia_transport_zrtp_getZrtpContext(tp); int32_t state = zrtp_inState(ctx, SecureState); zrtp_cb_user_data* zrtp_cb_data = (zrtp_cb_user_data*) pjmedia_transport_zrtp_getUserData(tp); if (state) { pj_ansi_snprintf(msg, sizeof(msg), "ZRTP - %s\n%.*s\n%.*s", "OK", zrtp_cb_data->sas.slen, zrtp_cb_data->sas.ptr, zrtp_cb_data->cipher.slen, zrtp_cb_data->cipher.ptr); } else { pj_ansi_snprintf(msg, sizeof(msg), ""); } pj_strdup2_with_null(css_var.pool, &result, msg); PJ_LOG(4, (THIS_FILE, "ZRTP getInfos : %s", msg)); return result; }
/* API: create stream */ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param, pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_aud_strm) { struct android_aud_factory *pa = (struct android_aud_factory*)f; pj_pool_t *pool; struct android_aud_stream *stream; pj_status_t status = PJ_SUCCESS; int state = 0; int buffSize, inputBuffSizePlay, inputBuffSizeRec; int channelInCfg, channelOutCfg, sampleFormat; jmethodID constructor_method=0, bufsize_method = 0; jmethodID method_id = 0; jclass jcl; JNIEnv *jni_env = 0; pj_bool_t attached; PJ_ASSERT_RETURN(param->channel_count >= 1 && param->channel_count <= 2, PJ_EINVAL); PJ_ASSERT_RETURN(param->bits_per_sample==8 || param->bits_per_sample==16, PJ_EINVAL); PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL); pool = pj_pool_create(pa->pf, "jnistrm", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; PJ_LOG(4, (THIS_FILE, "Creating Android JNI stream")); stream = PJ_POOL_ZALLOC_T(pool, struct android_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, "JNI stream"); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; pj_memcpy(&stream->param, param, sizeof(*param)); stream->user_data = user_data; stream->rec_cb = rec_cb; stream->play_cb = play_cb; buffSize = stream->param.samples_per_frame*stream->param.bits_per_sample/8; stream->rec_buf_size = stream->play_buf_size = buffSize; channelInCfg = (param->channel_count == 1)? 16 /*CHANNEL_IN_MONO*/: 12 /*CHANNEL_IN_STEREO*/; channelOutCfg = (param->channel_count == 1)? 4 /*CHANNEL_OUT_MONO*/: 12 /*CHANNEL_OUT_STEREO*/; sampleFormat = (param->bits_per_sample == 8)? 3 /*ENCODING_PCM_8BIT*/: 2 /*ENCODING_PCM_16BIT*/; attached = attach_jvm(&jni_env); if (stream->dir & PJMEDIA_DIR_CAPTURE) { /* Find audio record class and create global ref */ jcl = (*jni_env)->FindClass(jni_env, "android/media/AudioRecord"); if (jcl == NULL) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record class")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->record_class = (jclass)(*jni_env)->NewGlobalRef(jni_env, jcl); (*jni_env)->DeleteLocalRef(jni_env, jcl); if (stream->record_class == 0) { status = PJ_ENOMEM; goto on_error; } /* Get the min buffer size function */ bufsize_method = (*jni_env)->GetStaticMethodID(jni_env, stream->record_class, "getMinBufferSize", "(III)I"); if (bufsize_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record " "getMinBufferSize() method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } inputBuffSizeRec = (*jni_env)->CallStaticIntMethod(jni_env, stream->record_class, bufsize_method, param->clock_rate, channelInCfg, sampleFormat); if (inputBuffSizeRec <= 0) { PJ_LOG(3, (THIS_FILE, "Unsupported audio record params")); status = PJMEDIA_EAUD_INIT; goto on_error; } } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { /* Find audio track class and create global ref */ jcl = (*jni_env)->FindClass(jni_env, "android/media/AudioTrack"); if (jcl == NULL) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track class")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->track_class = (jclass)(*jni_env)->NewGlobalRef(jni_env, jcl); (*jni_env)->DeleteLocalRef(jni_env, jcl); if (stream->track_class == 0) { status = PJ_ENOMEM; goto on_error; } /* Get the min buffer size function */ bufsize_method = (*jni_env)->GetStaticMethodID(jni_env, stream->track_class, "getMinBufferSize", "(III)I"); if (bufsize_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track " "getMinBufferSize() method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } inputBuffSizePlay = (*jni_env)->CallStaticIntMethod(jni_env, stream->track_class, bufsize_method, param->clock_rate, channelOutCfg, sampleFormat); if (inputBuffSizePlay <= 0) { PJ_LOG(3, (THIS_FILE, "Unsupported audio track params")); status = PJMEDIA_EAUD_INIT; goto on_error; } } if (stream->dir & PJMEDIA_DIR_CAPTURE) { jthrowable exc; int mic_source = 0; /* DEFAULT: default audio source */ /* Get pointer to the constructor */ constructor_method = (*jni_env)->GetMethodID(jni_env, stream->record_class, "<init>", "(IIIII)V"); if (constructor_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record's constructor")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } if (mic_source == 0) { /* Android-L (android-21) removes __system_property_get * from the NDK. */ /* char sdk_version[PROP_VALUE_MAX]; pj_str_t pj_sdk_version; int sdk_v; __system_property_get("ro.build.version.sdk", sdk_version); pj_sdk_version = pj_str(sdk_version); sdk_v = pj_strtoul(&pj_sdk_version); if (sdk_v > 10) */ mic_source = 7; /* VOICE_COMMUNICATION */ } PJ_LOG(4, (THIS_FILE, "Using audio input source : %d", mic_source)); do { stream->record = (*jni_env)->NewObject(jni_env, stream->record_class, constructor_method, mic_source, param->clock_rate, channelInCfg, sampleFormat, inputBuffSizeRec); if (stream->record == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio record object")); status = PJMEDIA_EAUD_INIT; goto on_error; } exc = (*jni_env)->ExceptionOccurred(jni_env); if (exc) { (*jni_env)->ExceptionDescribe(jni_env); (*jni_env)->ExceptionClear(jni_env); PJ_LOG(3, (THIS_FILE, "Failure in audio record's constructor")); if (mic_source == 0) { status = PJMEDIA_EAUD_INIT; goto on_error; } mic_source = 0; PJ_LOG(4, (THIS_FILE, "Trying the default audio source.")); continue; } /* Check state */ method_id = (*jni_env)->GetMethodID(jni_env, stream->record_class, "getState", "()I"); if (method_id == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio record getState() " "method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } state = (*jni_env)->CallIntMethod(jni_env, stream->record, method_id); if (state == 0) { /* STATE_UNINITIALIZED */ PJ_LOG(3, (THIS_FILE, "Failure in initializing audio record.")); if (mic_source == 0) { status = PJMEDIA_EAUD_INIT; goto on_error; } mic_source = 0; PJ_LOG(4, (THIS_FILE, "Trying the default audio source.")); } } while (state == 0); stream->record = (*jni_env)->NewGlobalRef(jni_env, stream->record); if (stream->record == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio record global ref.")); status = PJMEDIA_EAUD_INIT; goto on_error; } status = pj_sem_create(stream->pool, NULL, 0, 1, &stream->rec_sem); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(stream->pool, "android_recorder", AndroidRecorderCallback, stream, 0, 0, &stream->rec_thread); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4, (THIS_FILE, "Audio record initialized successfully.")); } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { jthrowable exc; /* Get pointer to the constructor */ constructor_method = (*jni_env)->GetMethodID(jni_env, stream->track_class, "<init>", "(IIIIII)V"); if (constructor_method == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track's constructor.")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } stream->track = (*jni_env)->NewObject(jni_env, stream->track_class, constructor_method, 0, /* STREAM_VOICE_CALL */ param->clock_rate, channelOutCfg, sampleFormat, inputBuffSizePlay, 1 /* MODE_STREAM */); if (stream->track == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio track object.")); status = PJMEDIA_EAUD_INIT; goto on_error; } exc = (*jni_env)->ExceptionOccurred(jni_env); if (exc) { (*jni_env)->ExceptionDescribe(jni_env); (*jni_env)->ExceptionClear(jni_env); PJ_LOG(3, (THIS_FILE, "Failure in audio track's constructor")); status = PJMEDIA_EAUD_INIT; goto on_error; } stream->track = (*jni_env)->NewGlobalRef(jni_env, stream->track); if (stream->track == 0) { PJ_LOG(3, (THIS_FILE, "Unable to create audio track's global ref")); status = PJMEDIA_EAUD_INIT; goto on_error; } /* Check state */ method_id = (*jni_env)->GetMethodID(jni_env, stream->track_class, "getState", "()I"); if (method_id == 0) { PJ_LOG(3, (THIS_FILE, "Unable to find audio track getState() " "method")); status = PJMEDIA_EAUD_SYSERR; goto on_error; } state = (*jni_env)->CallIntMethod(jni_env, stream->track, method_id); if (state == 0) { /* STATE_UNINITIALIZED */ PJ_LOG(3, (THIS_FILE, "Failure in initializing audio track.")); status = PJMEDIA_EAUD_INIT; goto on_error; } status = pj_sem_create(stream->pool, NULL, 0, 1, &stream->play_sem); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(stream->pool, "android_track", AndroidTrackCallback, stream, 0, 0, &stream->play_thread); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4, (THIS_FILE, "Audio track initialized successfully.")); } if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) { strm_set_cap(&stream->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, ¶m->output_vol); } /* Done */ stream->base.op = &android_strm_op; *p_aud_strm = &stream->base; detach_jvm(attached); return PJ_SUCCESS; on_error: detach_jvm(attached); strm_destroy(&stream->base); return status; }
/* * Create the resolver. */ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf, const char *name, unsigned options, pj_timer_heap_t *timer, pj_ioqueue_t *ioqueue, pj_dns_resolver **p_resolver) { pj_pool_t *pool; pj_dns_resolver *resv; pj_ioqueue_callback socket_cb; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL); if (name == NULL) name = THIS_FILE; /* Create and initialize resolver instance */ pool = pj_pool_create(pf, name, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; /* Create pool and name */ resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver); resv->pool = pool; resv->udp_sock = PJ_INVALID_SOCKET; pj_strdup2_with_null(pool, &resv->name, name); /* Create the mutex */ status = pj_mutex_create_recursive(pool, name, &resv->mutex); if (status != PJ_SUCCESS) goto on_error; /* Timer, ioqueue, and settings */ resv->timer = timer; resv->ioqueue = ioqueue; resv->last_id = 1; pj_dns_settings_default(&resv->settings); resv->settings.options = options; /* Create the timer heap if one is not specified */ if (resv->timer == NULL) { status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer); if (status != PJ_SUCCESS) goto on_error; } /* Create the ioqueue if one is not specified */ if (resv->ioqueue == NULL) { status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue); if (status != PJ_SUCCESS) goto on_error; } /* Response cache hash table */ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE); /* Query hash table and free list. */ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE); resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE); pj_list_init(&resv->query_free_nodes); /* Create the UDP socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind to any address/port */ status = pj_sock_bind_in(resv->udp_sock, 0, 0); if (status != PJ_SUCCESS) goto on_error; /* Register to ioqueue */ pj_bzero(&socket_cb, sizeof(socket_cb)); socket_cb.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock, resv, &socket_cb, &resv->udp_key); if (status != PJ_SUCCESS) goto on_error; pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key)); /* Start asynchronous read to the UDP socket */ resv->udp_len = sizeof(resv->udp_rx_pkt); resv->udp_addr_len = sizeof(resv->udp_src_addr); status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key, resv->udp_rx_pkt, &resv->udp_len, PJ_IOQUEUE_ALWAYS_ASYNC, &resv->udp_src_addr, &resv->udp_addr_len); if (status != PJ_EPENDING) goto on_error; /* Looks like everything is okay */ *p_resolver = resv; return PJ_SUCCESS; on_error: pj_dns_resolver_destroy(resv, PJ_FALSE); return status; }
/* * Create the resolver. */ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf, const char *name, unsigned options, pj_timer_heap_t *timer, pj_ioqueue_t *ioqueue, pj_dns_resolver **p_resolver) { pj_pool_t *pool; pj_dns_resolver *resv; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL); if (name == NULL) name = THIS_FILE; /* Create and initialize resolver instance */ pool = pj_pool_create(pf, name, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; /* Create pool and name */ resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver); resv->pool = pool; resv->udp_sock = PJ_INVALID_SOCKET; pj_strdup2_with_null(pool, &resv->name, name); /* Create the mutex */ status = pj_mutex_create_recursive(pool, name, &resv->mutex); if (status != PJ_SUCCESS) goto on_error; /* Timer, ioqueue, and settings */ resv->timer = timer; resv->ioqueue = ioqueue; resv->last_id = 1; pj_dns_settings_default(&resv->settings); resv->settings.options = options; /* Create the timer heap if one is not specified */ if (resv->timer == NULL) { status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer); if (status != PJ_SUCCESS) goto on_error; } /* Create the ioqueue if one is not specified */ if (resv->ioqueue == NULL) { status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue); if (status != PJ_SUCCESS) goto on_error; } /* Response cache hash table */ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE); /* Query hash table and free list. */ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE); resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE); pj_list_init(&resv->query_free_nodes); /* Initialize the UDP socket */ status = init_sock(resv); if (status != PJ_SUCCESS) goto on_error; /* Looks like everything is okay */ *p_resolver = resv; return PJ_SUCCESS; on_error: pj_dns_resolver_destroy(resv, PJ_FALSE); return status; }
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted) { pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256), }; if (!details.pool) { return -1; } while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { int expiration = registrar_get_expiration(aor, contact, rdata); RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup); if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ if ((expiration != 0) || previous) { pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } continue; } else if (previous && previous->star) { /* If there is a previous contact and it is a '*' this is a deal breaker */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } previous = contact; if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { continue; } details.uri = pjsip_uri_get_uri(contact->uri); /* Determine if this is an add, update, or delete for policy enforcement purposes */ if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) { if (expiration) { (*added)++; } } else if (expiration) { (*updated)++; } else { (*deleted)++; } } /* The provided contacts are acceptable, huzzah! */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return 0; } /*! \brief Callback function which prunes static contacts */ static int registrar_prune_static(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0; } /*! \brief Internal function used to delete all contacts from an AOR */ static int registrar_delete_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; const char *aor_name = arg; ast_sip_location_delete_contact(contact); if (!ast_strlen_zero(aor_name)) { ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s", contact->uri, aor_name); } return 0; } /*! \brief Internal function which adds a contact to a response */ static int registrar_add_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; pjsip_tx_data *tdata = arg; pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool); pj_str_t uri; pj_strdup2_with_null(tdata->pool, &uri, contact->uri); hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR); hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); return 0; } /*! \brief Helper function which adds a Date header to a response */ static void registrar_add_date_header(pjsip_tx_data *tdata) { char date[256]; struct tm tm; time_t t = time(NULL); gmtime_r(&t, &tm); strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm); ast_sip_add_header(tdata, "Date", date); }
static void zrtpSecureOn(void* data, char* cipher) { zrtp_cb_user_data* zrtp_data = (zrtp_cb_user_data*) data; pj_strdup2_with_null(css_var.pool, &zrtp_data->cipher, cipher); on_zrtp_update_transport_wrapper(data); }
static void zrtpShowSas(void* data, char* sas, int verified) { zrtp_cb_user_data* zrtp_data = (zrtp_cb_user_data*) data; pj_strdup2_with_null(css_var.pool, &zrtp_data->sas, sas); on_zrtp_show_sas_wrapper(data, sas, verified); }
/* API: create stream */ static pj_status_t opensl_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param, pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_aud_strm) { /* Audio sink for recorder and audio source for player */ #ifdef __ANDROID__ SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS }; #else SLDataLocator_BufferQueue loc_bq = { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS }; #endif struct opensl_aud_factory *pa = (struct opensl_aud_factory*)f; pj_pool_t *pool; struct opensl_aud_stream *stream; pj_status_t status = PJ_SUCCESS; int i, bufferSize; SLresult result; SLDataFormat_PCM format_pcm; /* Only supports for mono channel for now */ PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL); PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL); PJ_LOG(4,(THIS_FILE, "Creating OpenSL stream")); pool = pj_pool_create(pa->pf, "openslstrm", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; stream = PJ_POOL_ZALLOC_T(pool, struct opensl_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, "OpenSL"); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; pj_memcpy(&stream->param, param, sizeof(*param)); stream->user_data = user_data; stream->rec_cb = rec_cb; stream->play_cb = play_cb; bufferSize = param->samples_per_frame * param->bits_per_sample / 8; /* Configure audio PCM format */ format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = param->channel_count; /* Here samples per sec should be supported else we will get an error */ format_pcm.samplesPerSec = (SLuint32) param->clock_rate * 1000; format_pcm.bitsPerSample = (SLuint16) param->bits_per_sample; format_pcm.containerSize = (SLuint16) param->bits_per_sample; format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER; format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; status = on_validate_audio_clock_rate_wrapper(param->clock_rate); if(status != PJ_SUCCESS){ return PJMEDIA_EAUD_INVOP; } on_setup_audio_wrapper(PJ_TRUE); if (stream->dir & PJMEDIA_DIR_PLAYBACK) { /* Audio source */ SLDataSource audioSrc = {&loc_bq, &format_pcm}; /* Audio sink */ SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, pa->outputMixObject}; SLDataSink audioSnk = {&loc_outmix, NULL}; /* Audio interface */ #ifdef __ANDROID__ int numIface = 3; const SLInterfaceID ids[3] = {W_SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION}; const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; SLAndroidConfigurationItf playerConfig; SLint32 streamType = SL_ANDROID_STREAM_VOICE; #else const SLInterfaceID ids[2] = {W_SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; int numIface = 2; #endif /* Create audio player */ result = (*pa->engineEngine)->CreateAudioPlayer(pa->engineEngine, &stream->playerObj, &audioSrc, &audioSnk, numIface, ids, req); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot create audio player: %d", result)); goto on_error; } #ifdef __ANDROID__ /* Set Android configuration */ result = (*stream->playerObj)->GetInterface(stream->playerObj, SL_IID_ANDROIDCONFIGURATION, &playerConfig); if (result == SL_RESULT_SUCCESS && playerConfig) { result = (*playerConfig)->SetConfiguration( playerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32)); } if (result != SL_RESULT_SUCCESS) { PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android " "player configuration")); } #endif /* Realize the player */ result = (*stream->playerObj)->Realize(stream->playerObj, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot realize player : %d", result)); goto on_error; } /* Get the play interface */ result = (*stream->playerObj)->GetInterface(stream->playerObj, SL_IID_PLAY, &stream->playerPlay); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot get play interface")); goto on_error; } /* Get the buffer queue interface */ result = (*stream->playerObj)->GetInterface(stream->playerObj, W_SL_IID_BUFFERQUEUE, &stream->playerBufQ); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot get buffer queue interface")); goto on_error; } /* Get the volume interface */ result = (*stream->playerObj)->GetInterface(stream->playerObj, SL_IID_VOLUME, &stream->playerVol); /* Register callback on the buffer queue */ result = (*stream->playerBufQ)->RegisterCallback(stream->playerBufQ, bqPlayerCallback, (void *)stream); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot register player callback")); goto on_error; } stream->playerBufferSize = bufferSize; for (i = 0; i < NUM_BUFFERS; i++) { stream->playerBuffer[i] = (char *) pj_pool_alloc(stream->pool, stream->playerBufferSize); } } if (stream->dir & PJMEDIA_DIR_CAPTURE) { /* Audio source */ SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; SLDataSource audioSrc = {&loc_dev, NULL}; /* Audio sink */ SLDataSink audioSnk = {&loc_bq, &format_pcm}; /* Audio interface */ #ifdef __ANDROID__ int numIface = 2; const SLInterfaceID ids[2] = {W_SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION}; const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; SLAndroidConfigurationItf recorderConfig; #else int numIface = 1; const SLInterfaceID ids[1] = {W_SL_IID_BUFFERQUEUE}; const SLboolean req[1] = {SL_BOOLEAN_TRUE}; #endif /* Create audio recorder * (requires the RECORD_AUDIO permission) */ result = (*pa->engineEngine)->CreateAudioRecorder(pa->engineEngine, &stream->recordObj, &audioSrc, &audioSnk, numIface, ids, req); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot create recorder: %d", result)); goto on_error; } #ifdef __ANDROID__ /* Set Android configuration */ result = (*stream->recordObj)->GetInterface(stream->recordObj, SL_IID_ANDROIDCONFIGURATION, &recorderConfig); if (result == SL_RESULT_SUCCESS) { SLint32 streamType = SL_ANDROID_RECORDING_PRESET_GENERIC; #if __ANDROID_API__ >= 14 char sdk_version[PROP_VALUE_MAX]; pj_str_t pj_sdk_version; int sdk_v; __system_property_get("ro.build.version.sdk", sdk_version); pj_sdk_version = pj_str(sdk_version); sdk_v = pj_strtoul(&pj_sdk_version); if (sdk_v >= 14) streamType = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; PJ_LOG(4, (THIS_FILE, "Recording stream type %d, SDK : %d", streamType, sdk_v)); #endif result = (*recorderConfig)->SetConfiguration( recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET, &streamType, sizeof(SLint32)); } if (result != SL_RESULT_SUCCESS) { PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android " "recorder configuration")); } #endif /* Realize the recorder */ result = (*stream->recordObj)->Realize(stream->recordObj, SL_BOOLEAN_FALSE); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot realize recorder : %d", result)); goto on_error; } /* Get the record interface */ result = (*stream->recordObj)->GetInterface(stream->recordObj, SL_IID_RECORD, &stream->recordRecord); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot get record interface")); goto on_error; } /* Get the buffer queue interface */ result = (*stream->recordObj)->GetInterface( stream->recordObj, W_SL_IID_BUFFERQUEUE, &stream->recordBufQ); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot get recorder buffer queue iface")); goto on_error; } /* Register callback on the buffer queue */ result = (*stream->recordBufQ)->RegisterCallback(stream->recordBufQ, bqRecorderCallback, (void *) stream); if (result != SL_RESULT_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Cannot register recorder callback")); goto on_error; } stream->recordBufferSize = bufferSize; for (i = 0; i < NUM_BUFFERS; i++) { stream->recordBuffer[i] = (char *) pj_pool_alloc(stream->pool, stream->recordBufferSize); } } if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) { strm_set_cap(&stream->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, ¶m->output_vol); } /* Done */ stream->base.op = &opensl_strm_op; *p_aud_strm = &stream->base; return PJ_SUCCESS; on_error: strm_destroy(&stream->base); return PJMEDIA_EAUD_INVOP; }
/* API: create stream */ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param, pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_aud_strm) { PJ_LOG(4,(THIS_FILE, "Creating stream")); struct android_aud_factory *pa = (struct android_aud_factory*)f; pj_pool_t *pool; struct android_aud_stream *stream; pj_status_t status; int has_set_in_call = 0; int state = 0; PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL); // Only supports for mono channel for now PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL); pool = pj_pool_create(pa->pf, "sndstream", 1024, 1024, NULL); if (!pool) { return PJ_ENOMEM; } stream = PJ_POOL_ZALLOC_T(pool, struct android_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, "Android stream"); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; stream->param = *param; stream->user_data = user_data; stream->samples_per_sec = param->clock_rate; stream->samples_per_frame = param->samples_per_frame; stream->bytes_per_sample = param->bits_per_sample / 8; stream->channel_count = param->channel_count; stream->rec_cb = rec_cb; stream->play_cb = play_cb; PJ_LOG(3, (THIS_FILE, "Create stream : %d samples/sec, %d samples/frame, %d bytes/sample", stream->samples_per_sec, stream->samples_per_frame, stream->bytes_per_sample)); /* if(pj_sem_create(pool, NULL, 0, 2, &stream->audio_launch_sem) != PJ_SUCCESS){ pj_pool_release(pool); return PJ_ENOMEM; } */ int inputBuffSize=0, inputBuffSizePlay, inputBuffSizeRec; int sampleFormat; //TODO : return codes should be better JNIEnv *jni_env = 0; ATTACH_JVM(jni_env); jmethodID constructor_method=0, get_min_buffer_size_method = 0, method_id = 0; status = on_setup_audio_wrapper(param->clock_rate); if(status != PJ_SUCCESS){ return PJMEDIA_EAUD_INVOP; } has_set_in_call = 1; /* if (attachResult != 0) { PJ_LOG(1, (THIS_FILE, "Not able to attach the jvm")); pj_pool_release(pool); return PJ_ENOMEM; } */ if (param->bits_per_sample == 8) { sampleFormat = 3; //ENCODING_PCM_8BIT } else if (param->bits_per_sample == 16) { sampleFormat = 2; //ENCODING_PCM_16BIT } else { pj_pool_release(pool); return PJMEDIA_EAUD_SAMPFORMAT; } PJ_LOG(3, (THIS_FILE, "Sample format is : %d for %d ", sampleFormat, param->bits_per_sample)); if (stream->dir & PJMEDIA_DIR_CAPTURE) { //Get pointer to the java class stream->record_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/media/AudioRecord")); if (stream->record_class == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio record class")); goto on_error; } PJ_LOG(3, (THIS_FILE, "We have the class")); //Get the min buffer function get_min_buffer_size_method = jni_env->GetStaticMethodID(stream->record_class, "getMinBufferSize", "(III)I"); if (get_min_buffer_size_method == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio record getMinBufferSize method")); goto on_error; } PJ_LOG(3, (THIS_FILE, "We have the buffer method")); //Call it inputBuffSizeRec = jni_env->CallStaticIntMethod(stream->record_class, get_min_buffer_size_method, param->clock_rate, 2, sampleFormat); if(inputBuffSizeRec <= 0){ PJ_LOG(2, (THIS_FILE, "Min buffer size is not a valid value")); goto on_error; } if(inputBuffSizeRec <= 4096){ inputBuffSizeRec = 4096 * 3/2; } int frameSizeInBytes = (param->bits_per_sample == 8) ? 1 : 2; if ( inputBuffSizeRec % frameSizeInBytes != 0 ){ inputBuffSizeRec ++; } PJ_LOG(3, (THIS_FILE, "Min record buffer %d", inputBuffSizeRec)); if(inputBuffSizeRec > inputBuffSize){ inputBuffSize = inputBuffSizeRec; } } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { //Get pointer to the java class stream->track_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/media/AudioTrack")); if (stream->track_class == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio track class")); goto on_error; } PJ_LOG(3, (THIS_FILE, "We have the track class")); //Get the min buffer function get_min_buffer_size_method = jni_env->GetStaticMethodID(stream->track_class, "getMinBufferSize", "(III)I"); if (get_min_buffer_size_method == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio record getMinBufferSize method")); goto on_error; } PJ_LOG(3, (THIS_FILE, "We have the buffer method")); //Call it inputBuffSizePlay = jni_env->CallStaticIntMethod(stream->track_class, get_min_buffer_size_method, param->clock_rate, 2, sampleFormat); if(inputBuffSizePlay < 0){ PJ_LOG(2, (THIS_FILE, "Min buffer size is not a valid value")); goto on_error; } //Not sure that's a good idea if(inputBuffSizePlay < 2*2*1024*param->clock_rate/8000){ inputBuffSizePlay = 2*2*1024*param->clock_rate/8000; } int frameSizeInBytes = (param->bits_per_sample == 8) ? 1 : 2; if ( inputBuffSizePlay % frameSizeInBytes != 0 ){ inputBuffSizePlay ++; } //inputBuffSizePlay = inputBuffSizePlay << 1; PJ_LOG(3, (THIS_FILE, "Min play buffer %d", inputBuffSizePlay)); if(inputBuffSizePlay > inputBuffSize){ inputBuffSize = inputBuffSizePlay; } } PJ_LOG(3, (THIS_FILE, "Min buffer %d", inputBuffSize)); if (stream->dir & PJMEDIA_DIR_CAPTURE) { //Get pointer to the constructor constructor_method = jni_env->GetMethodID(stream->record_class,"<init>", "(IIIII)V"); if (constructor_method == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio record class constructor")); goto on_error; } int mic_source = on_set_micro_source_wrapper(); if(mic_source == 0){ mic_source = 1; char sdk_version[PROP_VALUE_MAX]; __system_property_get("ro.build.version.sdk", sdk_version); pj_str_t pj_sdk_version = pj_str(sdk_version); int sdk_v = pj_strtoul(&pj_sdk_version); if(sdk_v >= 10){ mic_source = 7; } } PJ_LOG(3, (THIS_FILE, "Use micro source : %d", mic_source)); stream->record = jni_env->NewObject(stream->record_class, constructor_method, mic_source, // Mic input source: 1 = MIC / 7 = VOICE_COMMUNICATION param->clock_rate, 2, // CHANNEL_CONFIGURATION_MONO sampleFormat, inputBuffSizeRec); if (stream->record == 0) { PJ_LOG(1, (THIS_FILE, "Not able to instantiate record class")); goto on_error; } jthrowable exc = jni_env->ExceptionOccurred(); if (exc) { jni_env->ExceptionDescribe(); jni_env->ExceptionClear(); PJ_LOG(2, (THIS_FILE, "The micro source was probably not valid")); // Try to fallback on MIC source -- lazy failure if(mic_source != 1){ PJ_LOG(4, (THIS_FILE, "Try default source")); stream->record = jni_env->NewObject(stream->record_class, constructor_method, 1, // Mic input source: 1 = MIC / 7 = VOICE_COMMUNICATION param->clock_rate, 2, // CHANNEL_CONFIGURATION_MONO sampleFormat, inputBuffSizeRec); if (stream->record == 0) { PJ_LOG(1, (THIS_FILE, "Not able to instantiate record class")); goto on_error; } }else{ PJ_LOG(1, (THIS_FILE, "Not able to instantiate record class")); goto on_error; } } // Check state method_id = jni_env->GetMethodID(stream->record_class,"getState", "()I"); state = jni_env->CallIntMethod(stream->record, method_id); if(state == 0){ /* STATE_UNINITIALIZED */ // Try to fallback on MIC source -- lazy failure if(mic_source != 1){ PJ_LOG(4, (THIS_FILE, "Try default source")); stream->record = jni_env->NewObject(stream->record_class, constructor_method, 1, // Mic input source: 1 = MIC / 7 = VOICE_COMMUNICATION param->clock_rate, 2, // CHANNEL_CONFIGURATION_MONO sampleFormat, inputBuffSizeRec); if (stream->record == 0) { PJ_LOG(1, (THIS_FILE, "Not able to instantiate record class")); goto on_error; } }else{ PJ_LOG(1, (THIS_FILE, "Not able to instantiate record class")); goto on_error; } } stream->record = jni_env->NewGlobalRef(stream->record); PJ_LOG(3, (THIS_FILE, "We have capture the instance done")); } if (stream->dir & PJMEDIA_DIR_PLAYBACK) { //Get pointer to the constructor constructor_method = jni_env->GetMethodID(stream->track_class,"<init>", "(IIIIII)V"); if (constructor_method == 0) { PJ_LOG(2, (THIS_FILE, "Not able to find audio track class constructor")); goto on_error; } stream->track = jni_env->NewObject(stream->track_class, constructor_method, 0, // VOICE_CALL // 3, //MUSIC param->clock_rate, 2, // CHANNEL_CONFIGURATION_MONO sampleFormat, inputBuffSizePlay /**2*/, 1); // MODE_STREAM stream->track = jni_env->NewGlobalRef(stream->track); if (stream->track == 0) { PJ_LOG(1, (THIS_FILE, "Not able to instantiate track class")); goto on_error; } //TODO check if initialized properly PJ_LOG(3, (THIS_FILE, "We have the track instance done")); } //OK, done *p_aud_strm = &stream->base; (*p_aud_strm)->op = &android_strm_op; DETACH_JVM(jni_env); return PJ_SUCCESS; on_error: if(has_set_in_call == 1){ on_teardown_audio_wrapper(); } DETACH_JVM(jni_env); pj_pool_release(pool); return PJ_ENOMEM; }
/* Internal: Create both player and recorder stream */ static pj_status_t create_bidir_stream(struct pa_aud_factory *pa, const pjmedia_aud_param *param, pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_snd_strm) { pj_pool_t *pool; pjmedia_aud_dev_index rec_id, play_id; struct pa_aud_stream *stream; PaStream *paStream = NULL; PaStreamParameters inputParam; PaStreamParameters outputParam; int sampleFormat; const PaDeviceInfo *paRecDevInfo = NULL; const PaDeviceInfo *paPlayDevInfo = NULL; const PaHostApiInfo *paRecHostApiInfo = NULL; const PaHostApiInfo *paPlayHostApiInfo = NULL; const PaStreamInfo *paSI; unsigned paFrames, paRate, paInputLatency, paOutputLatency; PaError err; PJ_ASSERT_RETURN(play_cb && rec_cb && p_snd_strm, PJ_EINVAL); rec_id = param->rec_id; if (rec_id < 0) { rec_id = pa_get_default_input_dev(param->channel_count); if (rec_id < 0) { /* No such device. */ return PJMEDIA_EAUD_NODEFDEV; } } paRecDevInfo = Pa_GetDeviceInfo(rec_id); if (!paRecDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_EAUD_INVDEV; } play_id = param->play_id; if (play_id < 0) { play_id = pa_get_default_output_dev(param->channel_count); if (play_id < 0) { /* No such device. */ return PJMEDIA_EAUD_NODEFDEV; } } paPlayDevInfo = Pa_GetDeviceInfo(play_id); if (!paPlayDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_EAUD_INVDEV; } if (param->bits_per_sample == 8) sampleFormat = paUInt8; else if (param->bits_per_sample == 16) sampleFormat = paInt16; else if (param->bits_per_sample == 32) sampleFormat = paInt32; else return PJMEDIA_EAUD_SAMPFORMAT; pool = pj_pool_create(pa->pf, "sndstream", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; stream = PJ_POOL_ZALLOC_T(pool, struct pa_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; stream->play_id = play_id; stream->rec_id = rec_id; stream->user_data = user_data; stream->samples_per_sec = param->clock_rate; stream->samples_per_frame = param->samples_per_frame; stream->bytes_per_sample = param->bits_per_sample / 8; stream->channel_count = param->channel_count; stream->rec_cb = rec_cb; stream->play_cb = play_cb; stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, stream->samples_per_frame * stream->bytes_per_sample); stream->rec_buf_count = 0; stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, stream->samples_per_frame * stream->bytes_per_sample); stream->play_buf_count = 0; pj_bzero(&inputParam, sizeof(inputParam)); inputParam.device = rec_id; inputParam.channelCount = param->channel_count; inputParam.hostApiSpecificStreamInfo = NULL; inputParam.sampleFormat = sampleFormat; if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) inputParam.suggestedLatency = param->input_latency_ms / 1000.0; else inputParam.suggestedLatency = PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000.0; paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi); pj_bzero(&outputParam, sizeof(outputParam)); outputParam.device = play_id; outputParam.channelCount = param->channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) outputParam.suggestedLatency=param->output_latency_ms / 1000.0; else outputParam.suggestedLatency=PJMEDIA_SND_DEFAULT_PLAY_LATENCY/1000.0; paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi); /* Frames in PortAudio is number of samples in a single channel */ paFrames = param->samples_per_frame / param->channel_count; /* If both input and output are on the same device, open a single stream * for both input and output. */ if (rec_id == play_id) { err = Pa_OpenStream( &paStream, &inputParam, &outputParam, param->clock_rate, paFrames, paClipOff, &PaRecorderPlayerCallback, stream ); if (err == paNoError) { /* Set play stream and record stream to the same stream */ stream->play_strm = stream->rec_strm = paStream; } } else { err = -1; } /* .. otherwise if input and output are on the same device, OR if we're * unable to open a bidirectional stream, then open two separate * input and output stream. */ if (paStream == NULL) { /* Open input stream */ err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL, param->clock_rate, paFrames, paClipOff, &PaRecorderCallback, stream ); if (err == paNoError) { /* Open output stream */ err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam, param->clock_rate, paFrames, paClipOff, &PaPlayerCallback, stream ); if (err != paNoError) Pa_CloseStream(stream->rec_strm); } } if (err != paNoError) { pj_pool_release(pool); return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err); } paSI = Pa_GetStreamInfo(stream->rec_strm); paRate = (unsigned)(paSI->sampleRate); paInputLatency = (unsigned)(paSI->inputLatency * 1000); paSI = Pa_GetStreamInfo(stream->play_strm); paOutputLatency = (unsigned)(paSI->outputLatency * 1000); PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and " "playback, sample rate=%d, ch=%d, " "bits=%d, %d samples per frame, input latency=%d ms, " "output latency=%d ms", paRecDevInfo->name, paRecHostApiInfo->name, paPlayDevInfo->name, paPlayHostApiInfo->name, paRate, param->channel_count, param->bits_per_sample, param->samples_per_frame, paInputLatency, paOutputLatency)); *p_snd_strm = &stream->base; return PJ_SUCCESS; }
/* Internal: create playback stream */ static pj_status_t create_play_stream(struct pa_aud_factory *pa, const pjmedia_aud_param *param, pjmedia_aud_play_cb play_cb, void *user_data, pjmedia_aud_stream **p_snd_strm) { pj_pool_t *pool; pjmedia_aud_dev_index play_id; struct pa_aud_stream *stream; PaStreamParameters outputParam; int sampleFormat; const PaDeviceInfo *paDevInfo = NULL; const PaHostApiInfo *paHostApiInfo = NULL; const PaStreamInfo *paSI; unsigned paFrames, paRate, paLatency; PaError err; PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL); play_id = param->play_id; if (play_id < 0) { play_id = pa_get_default_output_dev(param->channel_count); if (play_id < 0) { /* No such device. */ return PJMEDIA_EAUD_NODEFDEV; } } paDevInfo = Pa_GetDeviceInfo(play_id); if (!paDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_EAUD_INVDEV; } if (param->bits_per_sample == 8) sampleFormat = paUInt8; else if (param->bits_per_sample == 16) sampleFormat = paInt16; else if (param->bits_per_sample == 32) sampleFormat = paInt32; else return PJMEDIA_EAUD_SAMPFORMAT; pool = pj_pool_create(pa->pf, "playstrm", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; stream = PJ_POOL_ZALLOC_T(pool, struct pa_aud_stream); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, paDevInfo->name); stream->dir = PJMEDIA_DIR_PLAYBACK; stream->play_id = play_id; stream->rec_id = -1; stream->user_data = user_data; stream->samples_per_sec = param->clock_rate; stream->samples_per_frame = param->samples_per_frame; stream->bytes_per_sample = param->bits_per_sample / 8; stream->channel_count = param->channel_count; stream->play_cb = play_cb; stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, stream->samples_per_frame * stream->bytes_per_sample); stream->play_buf_count = 0; pj_bzero(&outputParam, sizeof(outputParam)); outputParam.device = play_id; outputParam.channelCount = param->channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) outputParam.suggestedLatency=param->output_latency_ms / 1000.0; else outputParam.suggestedLatency=PJMEDIA_SND_DEFAULT_PLAY_LATENCY/1000.0; paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi); /* Frames in PortAudio is number of samples in a single channel */ paFrames = param->samples_per_frame / param->channel_count; err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam, param->clock_rate, paFrames, paClipOff, &PaPlayerCallback, stream ); if (err != paNoError) { pj_pool_release(pool); return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err); } paSI = Pa_GetStreamInfo(stream->play_strm); paRate = (unsigned)(paSI->sampleRate); paLatency = (unsigned)(paSI->outputLatency * 1000); PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d" ", ch=%d, " "bits=%d, %d samples per frame, latency=%d ms", play_id, paDevInfo->name, paHostApiInfo->name, paRate, param->channel_count, param->bits_per_sample, param->samples_per_frame, paLatency)); *p_snd_strm = &stream->base; return PJ_SUCCESS; }
/* * Open both player and recorder. */ PJ_DEF(pj_status_t) pjmedia_snd_open( int *prec_id, int *pplay_id, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, pjmedia_snd_rec_cb rec_cb, pjmedia_snd_play_cb play_cb, void *user_data, pjmedia_snd_stream **p_snd_strm) { pj_pool_t *pool; pjmedia_snd_stream *stream; PaStream *paStream = NULL; PaStreamParameters inputParam; PaStreamParameters outputParam; int sampleFormat; const PaDeviceInfo *paRecDevInfo = NULL; const PaDeviceInfo *paPlayDevInfo = NULL; const PaHostApiInfo *paRecHostApiInfo = NULL; const PaHostApiInfo *paPlayHostApiInfo = NULL; const PaStreamInfo *paSI; unsigned paFrames, paRate, paInputLatency, paOutputLatency; PaError err; if (*prec_id < 0) { *prec_id = pa_get_default_input_dev(channel_count); if (*prec_id < 0) { /* No such device. */ return PJMEDIA_ENOSNDREC; } } int rec_id=*prec_id; paRecDevInfo = Pa_GetDeviceInfo(rec_id); if (!paRecDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_ESNDINDEVID; } if (*pplay_id < 0) { *pplay_id = pa_get_default_output_dev(channel_count); if (*pplay_id < 0) { /* No such device. */ return PJMEDIA_ENOSNDPLAY; } } int play_id=*pplay_id; paPlayDevInfo = Pa_GetDeviceInfo(play_id); if (!paPlayDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_ESNDINDEVID; } if (bits_per_sample == 8) sampleFormat = paUInt8; else if (bits_per_sample == 16) sampleFormat = paInt16; else if (bits_per_sample == 32) sampleFormat = paInt32; else return PJMEDIA_ESNDINSAMPLEFMT; pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; stream = pj_pool_zalloc(pool, sizeof(*stream)); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name); stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; stream->play_id = play_id; stream->rec_id = rec_id; stream->user_data = user_data; stream->samples_per_sec = clock_rate; stream->samples_per_frame = samples_per_frame; stream->bytes_per_sample = bits_per_sample / 8; stream->channel_count = channel_count; stream->rec_cb = rec_cb; stream->play_cb = play_cb; pj_bzero(&inputParam, sizeof(inputParam)); inputParam.device = rec_id; inputParam.channelCount = channel_count; inputParam.hostApiSpecificStreamInfo = NULL; inputParam.sampleFormat = sampleFormat; inputParam.suggestedLatency = paRecDevInfo->defaultLowInputLatency; paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi); pj_bzero(&outputParam, sizeof(outputParam)); outputParam.device = play_id; outputParam.channelCount = channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; outputParam.suggestedLatency = paPlayDevInfo->defaultLowOutputLatency; paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi); /* Frames in PortAudio is number of samples in a single channel */ paFrames = samples_per_frame / channel_count; /* If both input and output are on the same device, open a single stream * for both input and output. */ if (rec_id == play_id) { err = Pa_OpenStream( &paStream, &inputParam, &outputParam, clock_rate, paFrames, paClipOff, &PaRecorderPlayerCallback, stream ); if (err == paNoError) { /* Set play stream and record stream to the same stream */ stream->play_strm = stream->rec_strm = paStream; } } else { err = -1; } /* .. otherwise if input and output are on the same device, OR if we're * unable to open a bidirectional stream, then open two separate * input and output stream. */ if (paStream == NULL) { /* Open input stream */ err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL, clock_rate, paFrames, paClipOff, &PaRecorderCallback, stream ); if (err == paNoError) { /* Open output stream */ err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam, clock_rate, paFrames, paClipOff, &PaPlayerCallback, stream ); if (err != paNoError) Pa_CloseStream(stream->rec_strm); } } if (err != paNoError) { pj_pool_release(pool); return PJMEDIA_ERRNO_FROM_PORTAUDIO(err); } paSI = Pa_GetStreamInfo(stream->rec_strm); paRate = (unsigned)(paSI->sampleRate); paInputLatency = (unsigned)(paSI->inputLatency * 1000); paSI = Pa_GetStreamInfo(stream->play_strm); paOutputLatency = (unsigned)(paSI->outputLatency * 1000); PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and " "playback, sample rate=%d, ch=%d, " "bits=%d, %d samples per frame, input latency=%d ms, " "output latency=%d ms", paRecDevInfo->name, paRecHostApiInfo->name, paPlayDevInfo->name, paPlayHostApiInfo->name, paRate, channel_count, bits_per_sample, samples_per_frame, paInputLatency, paOutputLatency)); *p_snd_strm = stream; return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pjmedia_snd_open_player( int *pindex, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, pjmedia_snd_play_cb play_cb, void *user_data, pjmedia_snd_stream **p_snd_strm) { pj_pool_t *pool; pjmedia_snd_stream *stream; PaStreamParameters outputParam; int sampleFormat; const PaDeviceInfo *paDevInfo = NULL; const PaHostApiInfo *paHostApiInfo = NULL; const PaStreamInfo *paSI; unsigned paFrames, paRate, paLatency; PaError err; if (*pindex < 0) { *pindex = pa_get_default_output_dev(channel_count); if (*pindex < 0) { /* No such device. */ return PJMEDIA_ENOSNDPLAY; } } int index=*pindex; paDevInfo = Pa_GetDeviceInfo(index); if (!paDevInfo) { /* Assumed it is "No such device" error. */ return PJMEDIA_ESNDINDEVID; } if (bits_per_sample == 8) sampleFormat = paUInt8; else if (bits_per_sample == 16) sampleFormat = paInt16; else if (bits_per_sample == 32) sampleFormat = paInt32; else return PJMEDIA_ESNDINSAMPLEFMT; pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL); if (!pool) return PJ_ENOMEM; stream = pj_pool_calloc(pool, 1, sizeof(*stream)); stream->pool = pool; pj_strdup2_with_null(pool, &stream->name, paDevInfo->name); stream->dir = stream->dir = PJMEDIA_DIR_PLAYBACK; stream->play_id = index; stream->rec_id = -1; stream->user_data = user_data; stream->samples_per_sec = clock_rate; stream->samples_per_frame = samples_per_frame; stream->bytes_per_sample = bits_per_sample / 8; stream->channel_count = channel_count; stream->play_cb = play_cb; pj_bzero(&outputParam, sizeof(outputParam)); outputParam.device = index; outputParam.channelCount = channel_count; outputParam.hostApiSpecificStreamInfo = NULL; outputParam.sampleFormat = sampleFormat; outputParam.suggestedLatency = 1.0 * samples_per_frame / clock_rate;; paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi); /* Frames in PortAudio is number of samples in a single channel */ paFrames = samples_per_frame / channel_count; err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam, clock_rate, paFrames, paClipOff, &PaPlayerCallback, stream ); if (err != paNoError) { pj_pool_release(pool); return PJMEDIA_ERRNO_FROM_PORTAUDIO(err); } paSI = Pa_GetStreamInfo(stream->play_strm); paRate = (unsigned)(paSI->sampleRate); paLatency = (unsigned)(paSI->outputLatency * 1000); PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d" ", ch=%d, " "bits=%d, %d samples per frame, latency=%d ms", index, paDevInfo->name, paHostApiInfo->name, paRate, channel_count, bits_per_sample, samples_per_frame, paLatency)); *p_snd_strm = stream; return PJ_SUCCESS; }
/** * Is call using a secure RTP method (SRTP/ZRTP) */ PJ_DECL(pj_str_t) call_secure_info(pjsua_call_id call_id) { pjsua_call *call; pj_status_t status; unsigned i; pjmedia_transport_info tp_info; pj_str_t result = pj_str(""); PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, result); PJSUA_LOCK(); if (pjsua_call_has_media(call_id)) { call = &pjsua_var.calls[call_id]; for (i = 0; i < call->med_cnt; ++i) { pjsua_call_media *call_med = &call->media[i]; PJ_LOG(4, (THIS_FILE, "Get secure for media type %d", call_med->type)); if (call_med->tp && call_med->type == PJMEDIA_TYPE_AUDIO) { pjmedia_transport_info tp_info; pjmedia_transport_info_init(&tp_info); pjmedia_transport_get_info(call_med->tp, &tp_info); if (tp_info.specific_info_cnt > 0) { unsigned j; for (j = 0; j < tp_info.specific_info_cnt; ++j) { if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_SRTP) { pjmedia_srtp_info *srtp_info = (pjmedia_srtp_info*) tp_info.spc_info[j].buffer; if (srtp_info->active) { result = pj_str("SRTP"); break; } } #if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0 else if (tp_info.spc_info[j].type == PJMEDIA_TRANSPORT_TYPE_ZRTP) { zrtp_state_info info = jzrtp_getInfoFromTransport(call_med->tp); if(info.secure){ char msg[512]; PJ_LOG(4, (THIS_FILE, "ZRTP :: V %d", info.sas_verified)); PJ_LOG(4, (THIS_FILE, "ZRTP :: S L %d", info.sas.slen)); PJ_LOG(4, (THIS_FILE, "ZRTP :: C L %d", info.cipher.slen)); pj_ansi_snprintf(msg, sizeof(msg), "ZRTP - %s\n%.*s\n%.*s", info.sas_verified ? "Verified": "Not verified", info.sas.slen, info.sas.ptr, info.cipher.slen, info.cipher.ptr); pj_strdup2_with_null(css_var.pool, &result, msg); break; } } #endif } } } } } PJSUA_UNLOCK(); return result; }
PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool, const pjmedia_vid_port_param *prm, pjmedia_vid_port **p_vid_port) { pjmedia_vid_port *vp; const pjmedia_video_format_detail *vfd; char dev_name[64]; char fmt_name[5]; pjmedia_vid_dev_cb vid_cb; pj_bool_t need_frame_buf = PJ_FALSE; pj_status_t status; unsigned ptime_usec; pjmedia_vid_dev_param vparam; pjmedia_vid_dev_info di; unsigned i; PJ_ASSERT_RETURN(pool && prm && p_vid_port, PJ_EINVAL); PJ_ASSERT_RETURN(prm->vidparam.fmt.type == PJMEDIA_TYPE_VIDEO && prm->vidparam.dir != PJMEDIA_DIR_NONE && prm->vidparam.dir != PJMEDIA_DIR_CAPTURE_RENDER, PJ_EINVAL); /* Retrieve the video format detail */ vfd = pjmedia_format_get_video_format_detail(&prm->vidparam.fmt, PJ_TRUE); if (!vfd) return PJ_EINVAL; PJ_ASSERT_RETURN(vfd->fps.num, PJ_EINVAL); /* Allocate videoport */ vp = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_port); vp->pool = pj_pool_create(pool->factory, "video port", 500, 500, NULL); vp->role = prm->active ? ROLE_ACTIVE : ROLE_PASSIVE; vp->dir = prm->vidparam.dir; // vp->cap_size = vfd->size; vparam = prm->vidparam; dev_name[0] = '\0'; /* Get device info */ if (vp->dir & PJMEDIA_DIR_CAPTURE) status = pjmedia_vid_dev_get_info(prm->vidparam.cap_id, &di); else status = pjmedia_vid_dev_get_info(prm->vidparam.rend_id, &di); if (status != PJ_SUCCESS) return status; pj_ansi_snprintf(dev_name, sizeof(dev_name), "%s [%s]", di.name, di.driver); for (i = 0; i < di.fmt_cnt; ++i) { if (prm->vidparam.fmt.id == di.fmt[i].id) break; } if (i == di.fmt_cnt) { /* The device has no no matching format. Pick one from * the supported formats, and later use converter to * convert it to the required format. */ pj_assert(di.fmt_cnt != 0); vparam.fmt.id = di.fmt[0].id; } pj_strdup2_with_null(pool, &vp->dev_name, di.name); vp->stream_role = di.has_callback ? ROLE_ACTIVE : ROLE_PASSIVE; pjmedia_fourcc_name(vparam.fmt.id, fmt_name); PJ_LOG(4,(THIS_FILE, "Opening device %s for %s: format=%s, size=%dx%d @%d:%d fps", dev_name, vid_dir_name(prm->vidparam.dir), fmt_name, vfd->size.w, vfd->size.h, vfd->fps.num, vfd->fps.denum)); ptime_usec = PJMEDIA_PTIME(&vfd->fps); pjmedia_clock_src_init(&vp->clocksrc, PJMEDIA_TYPE_VIDEO, prm->vidparam.clock_rate, ptime_usec); vp->sync_clocksrc.max_sync_ticks = PJMEDIA_CLOCK_SYNC_MAX_RESYNC_DURATION * 1000 / vp->clocksrc.ptime_usec; /* Create the video stream */ pj_bzero(&vid_cb, sizeof(vid_cb)); vid_cb.capture_cb = &vidstream_cap_cb; vid_cb.render_cb = &vidstream_render_cb; status = pjmedia_vid_dev_stream_create(&vparam, &vid_cb, vp, &vp->strm); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4,(THIS_FILE, "Device %s opened: format=%s, size=%dx%d @%d:%d fps", dev_name, fmt_name, vparam.fmt.det.vid.size.w, vparam.fmt.det.vid.size.h, vparam.fmt.det.vid.fps.num, vparam.fmt.det.vid.fps.denum)); /* Subscribe to device's events */ pjmedia_event_subscribe(NULL, &vidstream_event_cb, vp, vp->strm); if (vp->dir & PJMEDIA_DIR_CAPTURE) { pjmedia_format_copy(&vp->conv.conv_param.src, &vparam.fmt); pjmedia_format_copy(&vp->conv.conv_param.dst, &prm->vidparam.fmt); } else { pjmedia_format_copy(&vp->conv.conv_param.src, &prm->vidparam.fmt); pjmedia_format_copy(&vp->conv.conv_param.dst, &vparam.fmt); } status = create_converter(vp); if (status != PJ_SUCCESS) goto on_error; if (vp->role==ROLE_ACTIVE && ((vp->dir & PJMEDIA_DIR_ENCODING) || vp->stream_role==ROLE_PASSIVE)) { pjmedia_clock_param param; /* Active role is wanted, but our device is passive, so create * master clocks to run the media flow. For encoding direction, * we also want to create our own clock since the device's clock * may run at a different rate. */ need_frame_buf = PJ_TRUE; param.usec_interval = PJMEDIA_PTIME(&vfd->fps); param.clock_rate = prm->vidparam.clock_rate; status = pjmedia_clock_create2(pool, ¶m, PJMEDIA_CLOCK_NO_HIGHEST_PRIO, (vp->dir & PJMEDIA_DIR_ENCODING) ? &enc_clock_cb: &dec_clock_cb, vp, &vp->clock); if (status != PJ_SUCCESS) goto on_error; } else if (vp->role==ROLE_PASSIVE) { vid_pasv_port *pp; /* Always need to create media port for passive role */ vp->pasv_port = pp = PJ_POOL_ZALLOC_T(pool, vid_pasv_port); pp->vp = vp; pp->base.get_frame = &vid_pasv_port_get_frame; pp->base.put_frame = &vid_pasv_port_put_frame; pjmedia_port_info_init2(&pp->base.info, &vp->dev_name, PJMEDIA_SIG_VID_PORT, prm->vidparam.dir, &prm->vidparam.fmt); need_frame_buf = PJ_TRUE; } if (need_frame_buf) { const pjmedia_video_format_info *vfi; pjmedia_video_apply_fmt_param vafp; vfi = pjmedia_get_video_format_info(NULL, vparam.fmt.id); if (!vfi) { status = PJ_ENOTFOUND; goto on_error; } pj_bzero(&vafp, sizeof(vafp)); vafp.size = vparam.fmt.det.vid.size; status = vfi->apply_fmt(vfi, &vafp); if (status != PJ_SUCCESS) goto on_error; vp->frm_buf = PJ_POOL_ZALLOC_T(pool, pjmedia_frame); vp->frm_buf_size = vafp.framebytes; vp->frm_buf->buf = pj_pool_alloc(pool, vafp.framebytes); vp->frm_buf->size = vp->frm_buf_size; vp->frm_buf->type = PJMEDIA_FRAME_TYPE_NONE; status = pj_mutex_create_simple(pool, vp->dev_name.ptr, &vp->frm_mutex); if (status != PJ_SUCCESS) goto on_error; } *p_vid_port = vp; return PJ_SUCCESS; on_error: pjmedia_vid_port_destroy(vp); return status; }
pjmedia_mp3_writer_port_create( pj_pool_t *pool, const char *filename, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, const pjmedia_mp3_encoder_option *param_option, pjmedia_port **p_port ) { struct mp3_file_port *fport; pj_status_t status; status = init_blade_dll(); if (status != PJ_SUCCESS) return status; /* Check arguments. */ PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL); /* Only supports 16bits per sample for now. */ PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL); /* Create file port instance. */ fport = pj_pool_zalloc(pool, sizeof(struct mp3_file_port)); PJ_ASSERT_RETURN(fport != NULL, PJ_ENOMEM); /* Initialize port info. */ pj_strdup2_with_null(pool, &fport->mp3_filename, filename); pjmedia_port_info_init(&fport->base.info, &fport->mp3_filename, SIGNATURE, sampling_rate, channel_count, bits_per_sample, samples_per_frame); fport->base.get_frame = &file_get_frame; fport->base.put_frame = &file_put_frame; fport->base.on_destroy = &file_on_destroy; /* Open file in write and read mode. * We need the read mode because we'll modify the WAVE header once * the recording has completed. */ status = pj_file_open(pool, filename, PJ_O_WRONLY, &fport->fd); if (status != PJ_SUCCESS) { deinit_blade_dll(); return status; } /* Copy and initialize option with default settings */ if (param_option) { pj_memcpy(&fport->mp3_option, param_option, sizeof(pjmedia_mp3_encoder_option)); } else { pj_bzero(&fport->mp3_option, sizeof(pjmedia_mp3_encoder_option)); fport->mp3_option.vbr = PJ_TRUE; } /* Calculate bitrate if it's not specified, only if it's not VBR. */ if (fport->mp3_option.bit_rate == 0 && !fport->mp3_option.vbr) fport->mp3_option.bit_rate = sampling_rate * channel_count; /* Set default quality if it's not specified */ if (fport->mp3_option.quality == 0) fport->mp3_option.quality = 2; /* Init mp3 encoder */ status = init_mp3_encoder(fport, pool); if (status != PJ_SUCCESS) { pj_file_close(fport->fd); deinit_blade_dll(); return status; } /* Done. */ *p_port = &fport->base; PJ_LOG(4,(THIS_FILE, "MP3 file writer '%.*s' created: samp.rate=%dKHz, " "bitrate=%dkbps%s, quality=%d", (int)fport->base.info.name.slen, fport->base.info.name.ptr, fport->base.info.clock_rate/1000, fport->mp3_option.bit_rate/1000, (fport->mp3_option.vbr ? " (VBR)" : ""), fport->mp3_option.quality)); return PJ_SUCCESS; }