int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod) { SCOPED_AO2WRLOCK(lock, codecs); struct ast_codec *codec_new; /* Some types have specific requirements */ if (codec->type == AST_MEDIA_TYPE_UNKNOWN) { ast_log(LOG_ERROR, "A media type must be specified for codec '%s'\n", codec->name); return -1; } else if (codec->type == AST_MEDIA_TYPE_AUDIO) { if (!codec->sample_rate) { ast_log(LOG_ERROR, "A sample rate must be specified for codec '%s' of type '%s'\n", codec->name, ast_codec_media_type2str(codec->type)); return -1; } } codec_new = ao2_find(codecs, codec, OBJ_SEARCH_OBJECT | OBJ_NOLOCK); if (codec_new) { ast_log(LOG_ERROR, "A codec with name '%s' of type '%s' and sample rate '%u' is already registered\n", codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); ao2_ref(codec_new, -1); return -1; } codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); if (!codec_new) { ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n", codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate); return -1; } *codec_new = *codec; codec_new->id = codec_id++; ao2_link_flags(codecs, codec_new, OBJ_NOLOCK); /* Once registered a codec can not be unregistered, and the module must persist until shutdown */ ast_module_shutdown_ref(mod); ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n", ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->id); ao2_ref(codec_new, -1); return 0; }
struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec) { struct ast_format *format; struct format_interface *format_interface; format = ao2_t_alloc_options(sizeof(*format), format_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, "")); if (!format) { return NULL; } format->name = format_name; format->codec = ao2_bump(codec); format->channel_count = 1; format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY); if (format_interface) { format->interface = format_interface->interface; ao2_ref(format_interface, -1); } return format; }
/*! * \brief Create a pjsip transport. */ static int transport_create(void *data) { struct transport_create_data *create_data = data; struct ws_transport *newtransport = NULL; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt); pj_pool_t *pool; pj_str_t buf; pj_status_t status; newtransport = ao2_t_alloc_options(sizeof(*newtransport), transport_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK, "pjsip websocket transport"); if (!newtransport) { ast_log(LOG_ERROR, "Failed to allocate WebSocket transport.\n"); goto on_error; } newtransport->transport.endpt = endpt; if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) { ast_log(LOG_ERROR, "Failed to allocate WebSocket endpoint pool.\n"); goto on_error; } newtransport->transport.pool = pool; newtransport->ws_session = create_data->ws_session; /* Keep the session until transport dies */ ast_websocket_ref(newtransport->ws_session); status = pj_atomic_create(pool, 0, &newtransport->transport.ref_cnt); if (status != PJ_SUCCESS) { goto on_error; } status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &newtransport->transport.lock); if (status != PJ_SUCCESS) { goto on_error; } pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session))), &newtransport->transport.key.rem_addr); newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET(); newtransport->transport.key.type = ast_websocket_is_secure(newtransport->ws_session) ? transport_type_wss : transport_type_ws; newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr); newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, newtransport->transport.addr_len+4); pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, newtransport->transport.addr_len+4, 0); newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); newtransport->transport.type_name = (char *)pjsip_transport_get_type_name(newtransport->transport.key.type); newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); newtransport->transport.tpmgr = tpmgr; newtransport->transport.send_msg = &ws_send_msg; newtransport->transport.destroy = &ws_destroy; status = pjsip_transport_register(newtransport->transport.tpmgr, (pjsip_transport *)newtransport); if (status != PJ_SUCCESS) { goto on_error; } /* Add a reference for pjsip transport manager */ ao2_ref(newtransport, +1); newtransport->rdata.tp_info.transport = &newtransport->transport; newtransport->rdata.tp_info.pool = pjsip_endpt_create_pool(endpt, "rtd%p", PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC); if (!newtransport->rdata.tp_info.pool) { ast_log(LOG_ERROR, "Failed to allocate WebSocket rdata.\n"); pjsip_transport_destroy((pjsip_transport *)newtransport); goto on_error; } create_data->transport = newtransport; return 0; on_error: ao2_cleanup(newtransport); return -1; }