PJ_DEF(pj_status_t) pjmedia_converter_mgr_create(pj_pool_t *pool, pjmedia_converter_mgr **p_mgr) { pjmedia_converter_mgr *mgr; pj_status_t status = PJ_SUCCESS; mgr = PJ_POOL_ALLOC_T(pool, pjmedia_converter_mgr); pj_list_init(&mgr->factory_list); if (!converter_manager_instance) converter_manager_instance = mgr; #if defined(PJMEDIA_HAS_LIBYUV) && PJMEDIA_HAS_LIBYUV != 0 status = pjmedia_libyuv_converter_init(mgr); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error initializing libyuv converter")); } #endif #if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL status = pjmedia_libswscale_converter_init(mgr); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error initializing libswscale converter")); } #endif if (p_mgr) *p_mgr = mgr; return status; }
/* * API: set capability * Currently just supporting toggle between speaker and earpiece */ static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm, pjmedia_aud_dev_cap cap, const void *value) { struct bb10_stream *stream = (struct bb10_stream*)strm; if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE && (stream->param.dir & PJMEDIA_DIR_PLAYBACK)) { pjmedia_aud_dev_route route; pj_bool_t need_restart; pj_status_t ret; PJ_ASSERT_RETURN(value, PJ_EINVAL); /* OS 10.2.1 requires pausing audio stream */ need_restart = (stream->pb_thread != NULL); if (need_restart) { PJ_LOG(4,(THIS_FILE, "pausing audio stream..")); ret = bb10_stream_stop(strm); if (ret != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, ret, "Error pausing stream")); return ret; } } route = *((pjmedia_aud_dev_route*)value); PJ_LOG(4,(THIS_FILE, "setting audio route to %d..", route)); /* Use the initialization function which lazy-inits the * handle for routing */ if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER) { ret = bb10_initialize_playback_ctrl(stream,true); } else { ret = bb10_initialize_playback_ctrl(stream,false); } if (need_restart) { PJ_LOG(4,(THIS_FILE, "resuming audio stream..")); ret = bb10_stream_start(strm); if (ret != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, ret, "Error resuming stream")); } } return ret; } else if (cap==PJMEDIA_AUD_DEV_CAP_EC && (stream->param.dir & PJMEDIA_DIR_CAPTURE)) { /* EC is always enabled. Silently ignore the request */ return PJ_SUCCESS; } TRACE_((THIS_FILE,"bb10_stream_set_cap() = PJMEDIA_EAUD_INVCAP")); return PJMEDIA_EAUD_INVCAP; }
static int stun_destroy_test_session(struct stun_test_session *test_sess) { unsigned i; pj_stun_sock_cb stun_cb; pj_status_t status; pj_stun_sock *stun_sock[MAX_SOCK_CLIENTS]; pj_bzero(&stun_cb, sizeof(stun_cb)); stun_cb.on_status = &stun_sock_on_status; pj_event_reset(test_sess->server_event); /* Create all clients first */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { char name[10]; sprintf(name, "stun%02d", i); status = pj_stun_sock_create(&test_sess->stun_cfg, name, pj_AF_INET(), &stun_cb, NULL, test_sess, &stun_sock[i]); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error creating stun socket")); return -10; } } /* Start resolution */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { pj_str_t server_ip = pj_str("127.0.0.1"); status = pj_stun_sock_start(stun_sock[i], &server_ip, (pj_uint16_t)test_sess->server_port, NULL); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error starting stun socket")); return -20; } } /* settle down */ pj_thread_sleep(test_sess->param.client_sleep_after_start); /* Resume server threads */ pj_event_set(test_sess->server_event); pj_thread_sleep(test_sess->param.client_sleep_before_destroy); /* Destroy clients */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { status = pj_stun_sock_destroy(stun_sock[i]); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error destroying stun socket")); } } /* Give some time to ioqueue to free sockets */ pj_thread_sleep(PJ_IOQUEUE_KEY_FREE_DELAY); return 0; }
/* * main() */ int main(int argc, char *argv[]) { pj_caching_pool cp; pj_status_t status; if (argc < 2 || argc > 3) { puts("Usage: httpdemo URL [output-filename]"); return 1; } pj_log_set_level(5); pj_init(); pj_caching_pool_init(&cp, NULL, 0); mem = &cp.factory; pjlib_util_init(); if (argc > 2) f = fopen(argv[2], "wb"); else f = stdout; status = getURL(argv[1]); if (status != PJ_SUCCESS) { PJ_PERROR(1, (THIS_FILE, status, "Error")); } if (f != stdout) fclose(f); pj_caching_pool_destroy(&cp); pj_shutdown(); return 0; }
/* * udp_on_write_complete() * * This is callback notification from ioqueue that a pending sendto() * operation has completed. */ static void udp_on_write_complete( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_sent) { struct udp_transport *tp = (struct udp_transport*) pj_ioqueue_get_user_data(key); pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key; tdata_op_key->tdata = NULL; #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 if (-bytes_sent == PJ_ESOCKETSTOP) { pj_status_t status; /* Try to recover by restarting the transport. */ PJ_LOG(4,(tp->base.obj_name, "Restarting SIP UDP transport")); status = pjsip_udp_transport_restart2( &tp->base, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET, PJ_INVALID_SOCKET, &tp->base.local_addr, &tp->base.local_name); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error restarting SIP UDP transport")); } return; } #endif if (tdata_op_key->callback) { tdata_op_key->callback(&tp->base, tdata_op_key->token, bytes_sent); } }
static pj_status_t create_converter(pjmedia_vid_port *vp) { if (vp->conv.conv) { pjmedia_converter_destroy(vp->conv.conv); vp->conv.conv = NULL; } /* Instantiate converter if necessary */ if (vp->conv.conv_param.src.id != vp->conv.conv_param.dst.id || (vp->conv.conv_param.src.det.vid.size.w != vp->conv.conv_param.dst.det.vid.size.w) || (vp->conv.conv_param.src.det.vid.size.h != vp->conv.conv_param.dst.det.vid.size.h)) { pj_status_t status; /* Yes, we need converter */ status = pjmedia_converter_create(NULL, vp->pool, &vp->conv.conv_param, &vp->conv.conv); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error creating converter")); return status; } } if (vp->conv.conv || (vp->role==ROLE_ACTIVE && (vp->dir & PJMEDIA_DIR_ENCODING))) { pj_status_t status; const pjmedia_video_format_info *vfi; pjmedia_video_apply_fmt_param vafp; /* Allocate buffer for conversion */ vfi = pjmedia_get_video_format_info(NULL, vp->conv.conv_param.dst.id); if (!vfi) return PJMEDIA_EBADFMT; pj_bzero(&vafp, sizeof(vafp)); vafp.size = vp->conv.conv_param.dst.det.vid.size; status = vfi->apply_fmt(vfi, &vafp); if (status != PJ_SUCCESS) return PJMEDIA_EBADFMT; if (vafp.framebytes > vp->conv.conv_buf_size) { vp->conv.conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes); vp->conv.conv_buf_size = vafp.framebytes; } } vp->conv.usec_ctr = 0; vp->conv.usec_src = PJMEDIA_PTIME(&vp->conv.conv_param.src.det.vid.fps); vp->conv.usec_dst = PJMEDIA_PTIME(&vp->conv.conv_param.dst.det.vid.fps); return PJ_SUCCESS; }
/* Notify application that session has failed */ static pj_bool_t sess_fail(pj_stun_sock *stun_sock, pj_stun_sock_op op, pj_status_t status) { pj_bool_t ret; PJ_PERROR(4,(stun_sock->obj_name, status, "Session failed because %s failed", pj_stun_sock_op_name(op))); ret = (*stun_sock->cb.on_status)(stun_sock, op, status); return ret; }
static void on_complete(pj_http_req *hreq, pj_status_t status, const pj_http_resp *resp) { PJ_UNUSED_ARG(hreq); if (status != PJ_SUCCESS) { PJ_PERROR(1, (THIS_FILE, status, "HTTP request completed with error")); return; } PJ_LOG(3, (THIS_FILE, "Data completed: %d bytes", resp->size)); if (resp->size > 0 && resp->data) { #ifdef VERBOSE printf("%.*s\n", (int)resp->size, (char *)resp->data); #endif } }
static pj_status_t create_converter(pjmedia_vid_port *vp) { /* Instantiate converter if necessary */ if (vp->conv_param.src.id != vp->conv_param.dst.id || vp->conv_param.src.det.vid.size.w != vp->conv_param.dst.det.vid.size.w || vp->conv_param.src.det.vid.size.h != vp->conv_param.dst.det.vid.size.h) { pj_status_t status; /* Yes, we need converter */ const pjmedia_video_format_info *vfi; pjmedia_video_apply_fmt_param vafp; if (vp->conv) { pjmedia_converter_destroy(vp->conv); vp->conv = NULL; } status = pjmedia_converter_create(NULL, vp->pool, &vp->conv_param, &vp->conv); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error creating converter")); return status; } /* Allocate buffer for conversion */ vfi = pjmedia_get_video_format_info(NULL, vp->conv_param.dst.id); if (!vfi) return PJMEDIA_EBADFMT; pj_bzero(&vafp, sizeof(vafp)); vafp.size = vp->conv_param.dst.det.vid.size; status = vfi->apply_fmt(vfi, &vafp); if (status != PJ_SUCCESS) return PJMEDIA_EBADFMT; if (vafp.framebytes > vp->conv_buf_size) { vp->conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes); vp->conv_buf_size = vafp.framebytes; } } return PJ_SUCCESS; }
/* API: Refresh the list of video devices installed in the system. */ PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void) { unsigned i; vid_subsys.dev_cnt = 0; for (i=0; i<vid_subsys.drv_cnt; ++i) { pjmedia_vid_driver *drv = &vid_subsys.drv[i]; if (drv->f && drv->f->op->refresh) { pj_status_t status = drv->f->op->refresh(drv->f); if (status != PJ_SUCCESS) { PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device " "list for %s", drv->name)); } } pjmedia_vid_driver_init(i, PJ_TRUE); } return PJ_SUCCESS; }
static pj_status_t openh264_codec_decode( pjmedia_vid_codec *codec, pj_size_t pkt_count, pjmedia_frame packets[], unsigned out_size, pjmedia_frame *output) { openh264_private *ff = (openh264_private*)codec->codec_data; pj_status_t status; PJ_ASSERT_RETURN(codec && pkt_count > 0 && packets && output, PJ_EINVAL); if (ff->whole) { pj_assert(pkt_count==1); return openh264_codec_decode_whole(codec, &packets[0], out_size, output); } else { pjmedia_frame whole_frm; unsigned whole_len = 0; unsigned i; for (i=0; i<pkt_count; ++i) { if (whole_len + packets[i].size > ff->dec_buf_size) { PJ_LOG(5,(THIS_FILE, "Decoding buffer overflow")); break; } status = openh264_unpacketize(codec, packets[i].buf, packets[i].size, ff->dec_buf, ff->dec_buf_size, &whole_len); if (status != PJ_SUCCESS) { PJ_PERROR(5,(THIS_FILE, status, "Unpacketize error")); continue; } } whole_frm.buf = ff->dec_buf; whole_frm.size = whole_len; whole_frm.timestamp = output->timestamp = packets[i].timestamp; whole_frm.bit_info = 0; return openh264_codec_decode_whole(codec, &whole_frm, out_size, output); } }
/* * Simple implementation of app_main() for console targets */ pj_status_t app_main(pj_cli_t *cli) { print_msg(("", "APP STARTED \n \n \n")); print_msg(("", "======================================================================\n")); pj_status_t status; pj_cli_sess *sess; pj_cli_console_cfg console_cfg; pj_cli_console_cfg_default(&console_cfg); console_cfg.prompt_str = pj_str("CMD> "); /* * Create the console front end */ status = pj_cli_console_create(cli, &console_cfg, &sess, NULL); if (status != PJ_SUCCESS) return status; pj_log_set_log_func(&log_writer); /* * Main loop. */ for (;;) { char cmdline[PJ_CLI_MAX_CMDBUF]; pj_status_t status; status = pj_cli_console_process(sess, &cmdline[0], sizeof(cmdline)); if (status != PJ_SUCCESS) break; // pj_ansi_strcpy(cmdline, "sayhello {Teluu Inc.}"); if (status == PJ_CLI_EEXIT) { /* exit is called */ break; } else if (status != PJ_SUCCESS) { /* Something wrong with the cmdline */ PJ_PERROR(1, (THIS_FILE, status, "Exec error")); } } return PJ_SUCCESS; }
PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool, pj_ioqueue_t *ioque, pj_oshandle_t sock, void *user_data, const pj_ioqueue_callback *cb) { pj_ioqueue_key_t *key = NULL; pj_uint32_t value; pj_mutex_lock(ioque->mutex); if (ioque->count >= ioque->max) goto on_return; /* Set socket to nonblocking. */ value = 1; if (pj_sock_ioctl((pj_sock_t)sock, PJ_FIONBIO, &value)) { PJ_PERROR(("ioqueue", "Error setting FIONBIO")); goto on_return; } /* Create key. */ key = (pj_ioqueue_key_t*)pj_pool_calloc(pool, 1, sizeof(pj_ioqueue_key_t)); key->fd = (pj_sock_t)sock; key->user_data = user_data; /* Save callback. */ pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback)); /* Register */ pj_list_insert_before(&ioque->hlist, key); ++ioque->count; on_return: pj_mutex_unlock(ioque->mutex); return key; }
/* * Set socket option. */ PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd, const pj_sockopt_params *params) { unsigned int i = 0; pj_status_t retval = PJ_SUCCESS; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(params, PJ_EINVAL); for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) { pj_status_t status = pj_sock_setsockopt(sockfd, (pj_uint16_t)params->options[i].level, (pj_uint16_t)params->options[i].optname, params->options[i].optval, params->options[i].optlen); if (status != PJ_SUCCESS) { retval = status; PJ_PERROR(4,(THIS_FILE, status, "Warning: error applying sock opt %d", params->options[i].optname)); } } return retval; }
static int server_thread_proc(void *p) { struct stun_test_session *test_sess = (struct stun_test_session*)p; pj_pool_t *pool; pj_status_t status; PJ_LOG(4,(THIS_FILE, "Server thread running")); pool = pj_pool_create(test_sess->stun_cfg.pf, "server", 512, 512, NULL); while (!test_sess->thread_quit_flag) { pj_time_val timeout = {0, 10}; pj_fd_set_t rdset; int n; /* Serve client */ PJ_FD_ZERO(&rdset); PJ_FD_SET(test_sess->server_sock, &rdset); n = pj_sock_select(test_sess->server_sock+1, &rdset, NULL, NULL, &timeout); if (n==1 && PJ_FD_ISSET(test_sess->server_sock, &rdset)) { pj_uint8_t pkt[512]; pj_ssize_t pkt_len; pj_size_t res_len; pj_sockaddr client_addr; int addr_len; pj_stun_msg *stun_req, *stun_res; pj_pool_reset(pool); /* Got query */ pkt_len = sizeof(pkt); addr_len = sizeof(client_addr); status = pj_sock_recvfrom(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, &addr_len); if (status != PJ_SUCCESS) { continue; } status = pj_stun_msg_decode(pool, pkt, pkt_len, PJ_STUN_IS_DATAGRAM, &stun_req, NULL, NULL); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN request decode error")); continue; } status = pj_stun_msg_create_response(pool, stun_req, PJ_STUN_SC_BAD_REQUEST, NULL, &stun_res); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN create response error")); continue; } status = pj_stun_msg_encode(stun_res, pkt, sizeof(pkt), 0, NULL, &res_len); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "STUN encode error")); continue; } /* Ignore request */ if (test_sess->param.server_drop_request) continue; /* Wait for signal to continue */ if (test_sess->param.server_wait_for_event) pj_event_wait(test_sess->server_event); pkt_len = res_len; pj_sock_sendto(test_sess->server_sock, pkt, &pkt_len, 0, &client_addr, pj_sockaddr_get_len(&client_addr)); } } pj_pool_release(pool); PJ_LOG(4,(THIS_FILE, "Server thread quitting")); return 0; }
/* * pj_ioqueue_sendto() * * Start asynchronous write() to the descriptor. */ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, const void *data, pj_ssize_t *length, pj_uint32_t flags, const pj_sockaddr_t *addr, int addrlen) { struct write_operation *write_op; unsigned retry; pj_bool_t restart_retry = PJ_FALSE; pj_status_t status; pj_ssize_t sent; PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL); PJ_CHECK_STACK(); #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 retry_on_restart: #else PJ_UNUSED_ARG(restart_retry); #endif /* Check if key is closing. */ if (IS_CLOSING(key)) return PJ_ECANCELLED; /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */ flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC); /* Fast track: * Try to send data immediately, only if there's no pending write! * Note: * We are speculating that the list is empty here without properly * acquiring ioqueue's mutex first. This is intentional, to maximize * performance via parallelism. * * This should be safe, because: * - by convention, we require caller to make sure that the * key is not unregistered while other threads are invoking * an operation on the same key. * - pj_list_empty() is safe to be invoked by multiple threads, * even when other threads are modifying the list. */ if (pj_list_empty(&key->write_list)) { /* * See if data can be sent immediately. */ sent = *length; status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen); if (status == PJ_SUCCESS) { /* Success! */ *length = sent; return PJ_SUCCESS; } else { /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report * the error to caller. */ if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) { #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 /* Special treatment for dead UDP sockets here, see ticket #1107 */ if (status==PJ_STATUS_FROM_OS(EPIPE) && !IS_CLOSING(key) && key->fd_type==pj_SOCK_DGRAM() && !restart_retry) { PJ_PERROR(4,(THIS_FILE, status, "Send error for socket %d, retrying", key->fd)); replace_udp_sock(key); restart_retry = PJ_TRUE; goto retry_on_restart; } #endif return status; } } } /* * Check that address storage can hold the address parameter. */ PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG); /* * Schedule asynchronous send. */ write_op = (struct write_operation*)op_key; /* Spin if write_op has pending operation */ for (retry=0; write_op->op != 0 && retry<PENDING_RETRY; ++retry) pj_thread_sleep(0); /* Last chance */ if (write_op->op) { /* Unable to send packet because there is already pending write on the * write_op. We could not put the operation into the write_op * because write_op already contains a pending operation! And * we could not send the packet directly with sendto() either, * because that will break the order of the packet. So we can * only return error here. * * This could happen for example in multithreads program, * where polling is done by one thread, while other threads are doing * the sending only. If the polling thread runs on lower priority * than the sending thread, then it's possible that the pending * write flag is not cleared in-time because clearing is only done * during polling. * * Aplication should specify multiple write operation keys on * situation like this. */ //pj_assert(!"ioqueue: there is pending operation on this key!"); return PJ_EBUSY; } write_op->op = PJ_IOQUEUE_OP_SEND_TO; write_op->buf = (char*)data; write_op->size = *length; write_op->written = 0; write_op->flags = flags; pj_memcpy(&write_op->rmt_addr, addr, addrlen); write_op->rmt_addrlen = addrlen; pj_ioqueue_lock_key(key); /* Check again. Handle may have been closed after the previous check * in multithreaded app. If we add bad handle to the set it will * corrupt the ioqueue set. See #913 */ if (IS_CLOSING(key)) { pj_ioqueue_unlock_key(key); return PJ_ECANCELLED; } pj_list_insert_before(&key->write_list, write_op); ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT); pj_ioqueue_unlock_key(key); return PJ_EPENDING; }
/* Display error */ static void show_err(pj_turn_sock *turn_sock, const char *title, pj_status_t status) { PJ_PERROR(4,(turn_sock->obj_name, status, title)); }
/* * This is the public API to create, initialize, register, and start the * TCP listener. */ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3( pjsip_endpoint *endpt, const pjsip_tcp_transport_cfg *cfg, pjsip_tpfactory **p_factory ) { pj_pool_t *pool; pj_sock_t sock = PJ_INVALID_SOCKET; struct tcp_listener *listener; pj_activesock_cfg asock_cfg; pj_activesock_cb listener_cb; pj_sockaddr *listener_addr; int addr_len; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (cfg->addr_name.host.slen) { pj_sockaddr tmp; status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, (pj_uint16_t)cfg->addr_name.port); if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || (cfg->af==pj_AF_INET() && tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) { /* Invalid address */ return PJ_EINVAL; } } pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT, POOL_LIS_INC); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener); listener->factory.pool = pool; listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP : PJSIP_TRANSPORT_TCP6; listener->factory.type_name = (char*) pjsip_transport_get_type_name(listener->factory.type); listener->factory.flag = pjsip_transport_get_flag_from_type(listener->factory.type); listener->qos_type = cfg->qos_type; pj_memcpy(&listener->qos_params, &cfg->qos_params, sizeof(cfg->qos_params)); pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); if (listener->factory.type==PJSIP_TRANSPORT_TCP6) pj_ansi_strcat(listener->factory.obj_name, "6"); status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name, &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; /* Create socket */ status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) goto on_error; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 2, listener->factory.obj_name, "SIP TCP listener socket"); /* Apply SO_REUSEADDR */ if (cfg->reuse_addr) { int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); if (status != PJ_SUCCESS) { PJ_PERROR(4,(listener->factory.obj_name, status, "Warning: error applying SO_REUSEADDR")); } } /* Bind address may be different than factory.local_addr because * factory.local_addr will be resolved below. */ pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr); /* Bind socket */ listener_addr = &listener->factory.local_addr; pj_sockaddr_cp(listener_addr, &cfg->bind_addr); status = pj_sock_bind(sock, listener_addr, pj_sockaddr_get_len(listener_addr)); if (status != PJ_SUCCESS) goto on_error; /* Retrieve the bound address */ addr_len = pj_sockaddr_get_len(listener_addr); status = pj_sock_getsockname(sock, listener_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; /* If published host/IP is specified, then use that address as the * listener advertised address. */ if (cfg->addr_name.host.slen) { /* Copy the address */ listener->factory.addr_name = cfg->addr_name; pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, &cfg->addr_name.host); listener->factory.addr_name.port = cfg->addr_name.port; } else { /* No published address is given, use the bound address */ /* If the address returns 0.0.0.0, use the default * interface address as the transport's address. */ if (!pj_sockaddr_has_addr(listener_addr)) { pj_sockaddr hostip; status = pj_gethostip(listener->bound_addr.addr.sa_family, &hostip); if (status != PJ_SUCCESS) goto on_error; pj_sockaddr_copy_addr(listener_addr, &hostip); } /* Save the address name */ sockaddr_to_host_port(listener->factory.pool, &listener->factory.addr_name, listener_addr); } /* If port is zero, get the bound port */ if (listener->factory.addr_name.port == 0) { listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); } pj_ansi_snprintf(listener->factory.obj_name, sizeof(listener->factory.obj_name), "tcplis:%d", listener->factory.addr_name.port); /* Start listening to the address */ status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG); if (status != PJ_SUCCESS) goto on_error; /* Create active socket */ pj_activesock_cfg_default(&asock_cfg); if (cfg->async_cnt > MAX_ASYNC_CNT) asock_cfg.async_cnt = MAX_ASYNC_CNT; else asock_cfg.async_cnt = cfg->async_cnt; pj_bzero(&listener_cb, sizeof(listener_cb)); listener_cb.on_accept_complete = &on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg, pjsip_endpt_get_ioqueue(endpt), &listener_cb, listener, &listener->asock); /* Register to transport manager */ listener->endpt = endpt; listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); listener->factory.create_transport = lis_create_transport; listener->factory.destroy = lis_destroy; listener->is_registered = PJ_TRUE; status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, &listener->factory); if (status != PJ_SUCCESS) { listener->is_registered = PJ_FALSE; goto on_error; } /* Start pending accept() operations */ status = pj_activesock_start_accept(listener->asock, pool); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4,(listener->factory.obj_name, "SIP TCP listener ready for incoming connections at %.*s:%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port)); /* Return the pointer to user */ if (p_factory) *p_factory = &listener->factory; return PJ_SUCCESS; on_error: if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET) pj_sock_close(sock); lis_destroy(&listener->factory); return status; }
static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, parse_context *ctx) { pj_str_t str; ctx->last_error = PJMEDIA_SDP_EINMEDIA; /* check the equal sign */ if (*(scanner->curptr+1) != '=') { on_scanner_error(scanner); return; } /* m= */ pj_scan_advance_n(scanner, 2, SKIP_WS); /* type */ pj_scan_get_until_ch(scanner, ' ', &med->desc.media); pj_scan_get_char(scanner); /* port */ pj_scan_get(scanner, &cs_token, &str); med->desc.port = (unsigned short)pj_strtoul(&str); if (*scanner->curptr == '/') { /* port count */ pj_scan_get_char(scanner); pj_scan_get(scanner, &cs_token, &str); med->desc.port_count = pj_strtoul(&str); } else { med->desc.port_count = 0; } if (pj_scan_get_char(scanner) != ' ') { PJ_THROW(SYNTAX_ERROR); } /* transport */ pj_scan_get_until_chr(scanner, " \t\r\n", &med->desc.transport); /* format list */ med->desc.fmt_count = 0; while (*scanner->curptr == ' ') { pj_str_t fmt; pj_scan_get_char(scanner); /* Check again for the end of the line */ if ((*scanner->curptr == '\r') || (*scanner->curptr == '\n')) break; pj_scan_get(scanner, &cs_token, &fmt); if (med->desc.fmt_count < PJMEDIA_MAX_SDP_FMT) med->desc.fmt[med->desc.fmt_count++] = fmt; else PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY, "Error adding SDP media format %.*s, " "format is ignored", (int)fmt.slen, fmt.ptr)); } /* We've got what we're looking for, skip anything until newline */ pj_scan_skip_line(scanner); }
static int encode_decode_test(pj_pool_t *pool, const char *codec_id, pjmedia_vid_packing packing) { const pj_str_t port_name = {"codec", 5}; pjmedia_vid_codec *codec=NULL; pjmedia_port codec_port; codec_port_data_t codec_port_data; pjmedia_vid_codec_param codec_param; const pjmedia_vid_codec_info *codec_info; const char *packing_name; pjmedia_vid_dev_index cap_idx, rdr_idx; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_port_param vport_param; pjmedia_video_format_detail *vfd; char codec_name[5]; pj_status_t status; int rc = 0; switch (packing) { case PJMEDIA_VID_PACKING_PACKETS: packing_name = "framed"; break; case PJMEDIA_VID_PACKING_WHOLE: packing_name = "whole"; break; default: packing_name = "unknown"; break; } PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s", codec_id, packing_name)); /* Lookup codec */ { pj_str_t codec_id_st; unsigned info_cnt = 1; /* Lookup codec */ pj_cstr(&codec_id_st, codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 205; goto on_return; } } #if CAPTURE_DEV == -1 /* Lookup colorbar source */ status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx); if (status != PJ_SUCCESS) { rc = 206; goto on_return; } #elif CAPTURE_DEV == -2 /* Lookup any first non-colorbar source */ { unsigned i, cnt; pjmedia_vid_dev_info info; cap_idx = -1; cnt = pjmedia_vid_dev_count(); for (i = 0; i < cnt; ++i) { status = pjmedia_vid_dev_get_info(i, &info); if (status != PJ_SUCCESS) { rc = 206; goto on_return; } if (info.dir & PJMEDIA_DIR_CAPTURE && pj_ansi_stricmp(info.driver, "Colorbar")) { cap_idx = i; break; } } if (cap_idx == -1) { status = PJ_ENOTFOUND; rc = 206; goto on_return; } } #else cap_idx = CAPTURE_DEV; #endif /* Lookup SDL renderer */ status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx); if (status != PJ_SUCCESS) { rc = 207; goto on_return; } /* Prepare codec */ { pj_str_t codec_id_st; unsigned info_cnt = 1; const pjmedia_vid_codec_info *codec_info; /* Lookup codec */ pj_cstr(&codec_id_st, codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 245; goto on_return; } status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); if (status != PJ_SUCCESS) { rc = 246; goto on_return; } codec_param.packing = packing; /* Open codec */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec); if (status != PJ_SUCCESS) { rc = 250; goto on_return; } status = pjmedia_vid_codec_init(codec, pool); if (status != PJ_SUCCESS) { rc = 251; goto on_return; } status = pjmedia_vid_codec_open(codec, &codec_param); if (status != PJ_SUCCESS) { rc = 252; goto on_return; } /* After opened, codec will update the param, let's sync encoder & * decoder format detail. */ codec_param.dec_fmt.det = codec_param.enc_fmt.det; /* Subscribe to codec events */ pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data, codec); } pjmedia_vid_port_param_default(&vport_param); /* Create capture, set it to active (master) */ status = pjmedia_vid_dev_default_param(pool, cap_idx, &vport_param.vidparam); if (status != PJ_SUCCESS) { rc = 220; goto on_return; } pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt); vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE; vport_param.active = PJ_TRUE; if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) { rc = 221; goto on_return; } vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt, PJ_TRUE); if (vfd == NULL) { rc = 225; goto on_return; } status = pjmedia_vid_port_create(pool, &vport_param, &capture); if (status != PJ_SUCCESS) { rc = 226; goto on_return; } /* Create renderer, set it to passive (slave) */ vport_param.active = PJ_FALSE; vport_param.vidparam.dir = PJMEDIA_DIR_RENDER; vport_param.vidparam.rend_id = rdr_idx; vport_param.vidparam.disp_size = vfd->size; status = pjmedia_vid_port_create(pool, &vport_param, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } /* Init codec port */ pj_bzero(&codec_port, sizeof(codec_port)); status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234, PJMEDIA_DIR_ENCODING, &codec_param.dec_fmt); if (status != PJ_SUCCESS) { rc = 260; goto on_return; } codec_port_data.codec = codec; codec_port_data.rdr_port = renderer; codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w * codec_param.dec_fmt.det.vid.size.h * 4; codec_port_data.enc_buf = pj_pool_alloc(pool, codec_port_data.enc_buf_size); codec_port_data.pack_buf_size = codec_port_data.enc_buf_size; codec_port_data.pack_buf = pj_pool_alloc(pool, codec_port_data.pack_buf_size); codec_port.put_frame = &codec_put_frame; codec_port.port_data.pdata = &codec_port_data; /* Connect capture to codec port */ status = pjmedia_vid_port_connect(capture, &codec_port, PJ_FALSE); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } PJ_LOG(3, (THIS_FILE, " starting codec test: %s<->%.*s %dx%d", pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name), codec_info->encoding_name.slen, codec_info->encoding_name.ptr, codec_param.dec_fmt.det.vid.size.w, codec_param.dec_fmt.det.vid.size.h )); /* Start streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 275; goto on_return; } status = pjmedia_vid_port_start(capture); if (status != PJ_SUCCESS) { rc = 280; goto on_return; } /* Sleep while the video is being displayed... */ pj_thread_sleep(10000); on_return: if (status != PJ_SUCCESS) { PJ_PERROR(3, (THIS_FILE, status, " error")); } if (capture) pjmedia_vid_port_stop(capture); if (renderer) pjmedia_vid_port_stop(renderer); if (capture) pjmedia_vid_port_destroy(capture); if (renderer) pjmedia_vid_port_destroy(renderer); if (codec) { pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data, codec); pjmedia_vid_codec_close(codec); pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec); } return rc; }
/* * main() */ int main(int argc, char *argv[]) { pj_caching_pool cp; pjmedia_endpt *med_endpt; pj_pool_t *pool; pj_status_t status; /* Codec */ char *codec_id = (char*)"H264"; const pjmedia_vid_codec_info *codec_info; pjmedia_vid_codec_param codec_param; pjmedia_vid_codec *codec = NULL; //const char *save_filename = // "/home/bennylp/Desktop/opt/src/openh264-svn/testbin/test.264"; const char *save_filename = NULL; /* File */ enum { WIDTH = 320, HEIGHT = 192, FPS = 12, YUV_SIZE = WIDTH * HEIGHT * 3 >> 1, YUV_BUF_SIZE = YUV_SIZE + WIDTH, MAX_FRAMES = 32, MTU = 1500 }; FILE *fyuv = NULL; FILE *f264 = NULL; typedef pj_uint8_t enc_buf_type[MTU]; pj_uint8_t yuv_frame[YUV_BUF_SIZE]; enc_buf_type enc_buf[MAX_FRAMES]; unsigned read_cnt = 0, pkt_cnt = 0, dec_cnt = 0, enc_cnt; if (0) { diff_file(); return 1; } /* init PJLIB : */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* Initialize media endpoint. */ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create memory pool for application purpose */ pool = pj_pool_create( &cp.factory, /* pool factory */ "app", /* pool name. */ 4000, /* init size */ 4000, /* increment size */ NULL /* callback on error */ ); /* Init video format manager */ pjmedia_video_format_mgr_create(pool, 64, 0, NULL); /* Init video converter manager */ pjmedia_converter_mgr_create(pool, NULL); /* Init event manager */ pjmedia_event_mgr_create(pool, 0, NULL); /* Init video codec manager */ pjmedia_vid_codec_mgr_create(pool, NULL); /* Register all supported codecs */ status = init_codecs(&cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Open YUV file */ fyuv = fopen("pjsip-apps/bin/CiscoVT2people_320x192_12fps.yuv", "rb"); if (!fyuv) { puts("Unable to open ../CiscoVT2people_320x192_12fps.yuv"); status = -1; goto on_exit; } /* Write 264 file if wanted */ if (save_filename) { f264 = fopen(save_filename, "wb"); } /* Find which codec to use. */ if (codec_id) { unsigned count = 1; pj_str_t str_codec_id = pj_str(codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &str_codec_id, &count, &codec_info, NULL); if (status != PJ_SUCCESS) { printf("Error: unable to find codec %s\n", codec_id); return 1; } } else { static pjmedia_vid_codec_info info[1]; unsigned count = PJ_ARRAY_SIZE(info); /* Default to first codec */ pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL); codec_info = &info[0]; } /* Get codec default param for info */ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); pj_assert(status == PJ_SUCCESS); /* Alloc encoder */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Error allocating codec")); goto on_exit; } codec_param.dir = PJMEDIA_DIR_ENCODING_DECODING; codec_param.packing = PJMEDIA_VID_PACKING_PACKETS; codec_param.enc_mtu = MTU; codec_param.enc_fmt.det.vid.size.w = WIDTH; codec_param.enc_fmt.det.vid.size.h = HEIGHT; codec_param.enc_fmt.det.vid.fps.num = FPS; codec_param.enc_fmt.det.vid.avg_bps = WIDTH * HEIGHT * FPS; status = pjmedia_vid_codec_init(codec, pool); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Error initializing codec")); goto on_exit; } status = pjmedia_vid_codec_open(codec, &codec_param); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Error opening codec")); goto on_exit; } while (fread(yuv_frame, 1, YUV_SIZE, fyuv) == YUV_SIZE) { pjmedia_frame frm_yuv, frm_enc[MAX_FRAMES]; pj_bool_t has_more = PJ_FALSE; const pj_uint8_t start_nal[] = { 0, 0, 1 }; unsigned i; ++ read_cnt; pj_bzero(&frm_enc, sizeof(frm_enc)); pj_bzero(&frm_yuv, sizeof(frm_yuv)); frm_yuv.buf = yuv_frame; frm_yuv.size = YUV_SIZE; enc_cnt = 0; frm_enc[enc_cnt].buf = enc_buf[enc_cnt]; frm_enc[enc_cnt].size = MTU; status = pjmedia_vid_codec_encode_begin(codec, NULL, &frm_yuv, MTU, &frm_enc[enc_cnt], &has_more); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Codec encode error")); goto on_exit; } if (frm_enc[enc_cnt].size) { if (f264) { fwrite(start_nal, 1, sizeof(start_nal), f264); fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264); } ++pkt_cnt; ++enc_cnt; } while (has_more) { if (enc_cnt >= MAX_FRAMES) { status = -1; puts("Error: too many encoded frames"); goto on_exit; } has_more = PJ_FALSE; frm_enc[enc_cnt].buf = enc_buf[enc_cnt]; frm_enc[enc_cnt].size = MTU; status = pjmedia_vid_codec_encode_more(codec, MTU, &frm_enc[enc_cnt], &has_more); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Codec encode error")); goto on_exit; } if (frm_enc[enc_cnt].size) { if (f264) { fwrite(start_nal, 1, sizeof(start_nal), f264); fwrite(frm_enc[enc_cnt].buf, 1, frm_enc[enc_cnt].size, f264); } ++pkt_cnt; ++enc_cnt; } } if (enc_cnt) { frm_yuv.buf = yuv_frame; frm_yuv.size = YUV_BUF_SIZE; status = pjmedia_vid_codec_decode(codec, enc_cnt, frm_enc, YUV_BUF_SIZE, &frm_yuv); if (status != PJ_SUCCESS) { PJ_PERROR(3,(THIS_FILE, status, "Codec decode error")); goto on_exit; } if (frm_yuv.size != 0) { ++dec_cnt; } } } printf("Done.\n" " Read YUV frames: %d\n" " Encoded packets: %d\n" " Decoded YUV frames: %d\n", read_cnt, pkt_cnt, dec_cnt); /* Start deinitialization: */ on_exit: if (codec) { pjmedia_vid_codec_close(codec); pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec); } if (f264) fclose(f264); if (fyuv) fclose(fyuv); /* Deinit codecs */ deinit_codecs(); /* Destroy event manager */ pjmedia_event_mgr_destroy(NULL); /* Release application pool */ pj_pool_release( pool ); /* Destroy media endpoint. */ pjmedia_endpt_destroy( med_endpt ); /* Destroy pool factory */ pj_caching_pool_destroy( &cp ); /* Shutdown PJLIB */ pj_shutdown(); return (status == PJ_SUCCESS) ? 0 : 1; } #else int main(int argc, char *argv[]) { PJ_UNUSED_ARG(argc); PJ_UNUSED_ARG(argv); puts("Error: this sample requires video capability " "(PJMEDIA_HAS_VIDEO == 1)"); return -1; }
/* * Parse SDP message. */ PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool, char *buf, pj_size_t len, pjmedia_sdp_session **p_sdp) { pj_scanner scanner; pjmedia_sdp_session *session; pjmedia_sdp_media *media = NULL; pjmedia_sdp_attr *attr; pjmedia_sdp_conn *conn; pjmedia_sdp_bandw *bandw; pj_str_t dummy; int cur_name = 254; parse_context ctx; PJ_USE_EXCEPTION; ctx.last_error = PJ_SUCCESS; init_sdp_parser(); pj_scan_init(&scanner, buf, len, 0, &on_scanner_error); session = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); /* Ignore leading newlines */ while (*scanner.curptr=='\r' || *scanner.curptr=='\n') pj_scan_get_char(&scanner); PJ_TRY { while (!pj_scan_is_eof(&scanner)) { cur_name = *scanner.curptr; switch (cur_name) { case 'a': attr = parse_attr(pool, &scanner, &ctx); if (attr) { if (media) { if (media->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_media_add_attr(media, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media attribute, " "attribute is ignored")); } else { if (session->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_session_add_attr(session, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session attribute" ", attribute is ignored")); } } break; case 'o': parse_origin(&scanner, session, &ctx); break; case 's': parse_generic_line(&scanner, &session->name, &ctx); break; case 'c': conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); parse_connection_info(&scanner, conn, &ctx); if (media) { media->conn = conn; } else { session->conn = conn; } break; case 't': parse_time(&scanner, session, &ctx); break; case 'm': media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); parse_media(&scanner, media, &ctx); if (session->media_count < PJMEDIA_MAX_SDP_MEDIA) session->media[ session->media_count++ ] = media; else PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY, "Error adding media, media is ignored")); break; case 'v': parse_version(&scanner, &ctx); break; case 13: case 10: pj_scan_get_char(&scanner); /* Allow empty newlines at the end of the message */ while (!pj_scan_is_eof(&scanner)) { if (*scanner.curptr != 13 && *scanner.curptr != 10) { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } pj_scan_get_char(&scanner); } break; case 'b': bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw); parse_bandwidth_info(&scanner, bandw, &ctx); if (media) { if (media->bandw_count < PJMEDIA_MAX_SDP_BANDW) media->bandw[media->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media bandwidth " "info, info is ignored")); } else { if (session->bandw_count < PJMEDIA_MAX_SDP_BANDW) session->bandw[session->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session bandwidth " "info, info is ignored")); } break; default: if (cur_name >= 'a' && cur_name <= 'z') parse_generic_line(&scanner, &dummy, &ctx); else { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } break; } } ctx.last_error = PJ_SUCCESS; } PJ_CATCH_ANY { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(ctx.last_error, errmsg, sizeof(errmsg)); PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s", scanner.line, pj_scan_get_col(&scanner), errmsg)); session = NULL; pj_assert(ctx.last_error != PJ_SUCCESS); } PJ_END; pj_scan_fini(&scanner); if (session) apply_media_direction(session); *p_sdp = session; return ctx.last_error; }
/* Scan V4L2 devices */ static pj_status_t v4l2_scan_devs(vid4lin_factory *f) { vid4lin_dev_info vdi[V4L2_MAX_DEVS]; char dev_name[32]; unsigned i, old_count; pj_status_t status; if (f->dev_pool) { pj_pool_release(f->dev_pool); f->dev_pool = NULL; } pj_bzero(vdi, sizeof(vdi)); old_count = f->dev_count; f->dev_count = 0; f->dev_pool = pj_pool_create(f->pf, DRIVER_NAME, 500, 500, NULL); for (i=0; i<V4L2_MAX_DEVS && f->dev_count < V4L2_MAX_DEVS; ++i) { int fd; vid4lin_dev_info *pdi; pj_uint32_t fmt_cap[8]; int j, fmt_cnt=0; pdi = &vdi[f->dev_count]; snprintf(dev_name, sizeof(dev_name), "/dev/video%d", i); if (!pj_file_exists(dev_name)) continue; fd = v4l2_open(dev_name, O_RDWR, 0); if (fd == -1) continue; status = xioctl(fd, VIDIOC_QUERYCAP, &pdi->v4l2_cap); if (status != PJ_SUCCESS) { PJ_PERROR(4,(THIS_FILE, status, "Error querying %s", dev_name)); v4l2_close(fd); continue; } if ((pdi->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { v4l2_close(fd); continue; } PJ_LOG(5,(THIS_FILE, "Found capture device %s", pdi->v4l2_cap.card)); PJ_LOG(5,(THIS_FILE, " Enumerating formats:")); for (j=0; fmt_cnt<PJ_ARRAY_SIZE(fmt_cap); ++j) { struct v4l2_fmtdesc fdesc; unsigned k; pj_bzero(&fdesc, sizeof(fdesc)); fdesc.index = j; fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; status = xioctl(fd, VIDIOC_ENUM_FMT, &fdesc); if (status != PJ_SUCCESS) break; for (k=0; k<PJ_ARRAY_SIZE(v4l2_fmt_maps); ++k) { if (v4l2_fmt_maps[k].v4l2_fmt_id == fdesc.pixelformat) { fmt_cap[fmt_cnt++] = v4l2_fmt_maps[k].pjmedia_fmt_id; PJ_LOG(5,(THIS_FILE, " Supported: %s", fdesc.description)); break; } } if (k==PJ_ARRAY_SIZE(v4l2_fmt_maps)) { PJ_LOG(5,(THIS_FILE, " Unsupported: %s", fdesc.description)); } } v4l2_close(fd); if (fmt_cnt==0) { PJ_LOG(5,(THIS_FILE, " Found no common format")); continue; } strncpy(pdi->dev_name, dev_name, sizeof(pdi->dev_name)); pdi->dev_name[sizeof(pdi->dev_name)-1] = '\0'; strncpy(pdi->info.name, (char*)pdi->v4l2_cap.card, sizeof(pdi->info.name)); pdi->info.name[sizeof(pdi->info.name)-1] = '\0'; strncpy(pdi->info.driver, DRIVER_NAME, sizeof(pdi->info.driver)); pdi->info.driver[sizeof(pdi->info.driver)-1] = '\0'; pdi->info.dir = PJMEDIA_DIR_CAPTURE; pdi->info.has_callback = PJ_FALSE; pdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT; pdi->info.fmt_cnt = fmt_cnt; for (j=0; j<fmt_cnt; ++j) { pjmedia_format_init_video(&pdi->info.fmt[j], fmt_cap[j], DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS, 1); } if (j < fmt_cnt) continue; f->dev_count++; } if (f->dev_count == 0) return PJ_SUCCESS; if (f->dev_count > old_count || f->dev_info == NULL) { f->dev_info = (vid4lin_dev_info*) pj_pool_calloc(f->dev_pool, f->dev_count, sizeof(vid4lin_dev_info)); } pj_memcpy(f->dev_info, vdi, f->dev_count * sizeof(vid4lin_dev_info)); return PJ_SUCCESS; }
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'; } }
/* * Transmit message. */ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx, pj_bool_t mod_count) { pj_status_t status; PJ_ASSERT_RETURN(tsx->retransmit_timer.id == TIMER_INACTIVE || !tsx->require_retransmit, PJ_EBUSY); if (tsx->require_retransmit && mod_count) { /* Calculate retransmit/timeout delay */ if (tsx->transmit_count == 0) { tsx->retransmit_time.sec = 0; tsx->retransmit_time.msec = tsx->rto_msec; } else if (tsx->transmit_count < PJ_STUN_MAX_TRANSMIT_COUNT-1) { unsigned msec; msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time); msec <<= 1; tsx->retransmit_time.sec = msec / 1000; tsx->retransmit_time.msec = msec % 1000; } else { tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000; tsx->retransmit_time.msec = PJ_STUN_TIMEOUT_VALUE % 1000; } /* Schedule timer first because when send_msg() failed we can * cancel it (as opposed to when schedule_timer() failed we cannot * cancel transmission). */; status = pj_timer_heap_schedule_w_grp_lock(tsx->timer_heap, &tsx->retransmit_timer, &tsx->retransmit_time, TIMER_ACTIVE, tsx->grp_lock); if (status != PJ_SUCCESS) { tsx->retransmit_timer.id = TIMER_INACTIVE; return status; } } if (mod_count) tsx->transmit_count++; PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)", tsx->transmit_count)); pj_log_push_indent(); /* Send message */ status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size); if (status == PJNATH_ESTUNDESTROYED) { /* We've been destroyed, don't access the object. */ } else if (status != PJ_SUCCESS) { if (mod_count) { pj_timer_heap_cancel_if_active( tsx->timer_heap, &tsx->retransmit_timer, TIMER_INACTIVE); } PJ_PERROR(4, (tsx->obj_name, status, "STUN error sending message")); } pj_log_pop_indent(); return status; }
static int aviplay(pj_pool_t *pool, const char *fname) { pjmedia_vid_port *renderer=NULL; pjmedia_vid_port_param param; const pjmedia_video_format_info *vfi; pjmedia_video_format_detail *vfd; pjmedia_snd_port *snd_port = NULL; pj_status_t status; int rc = 0; pjmedia_avi_streams *avi_streams; pjmedia_avi_stream *vid_stream, *aud_stream; pjmedia_port *vid_port = NULL, *aud_port = NULL; pjmedia_vid_codec *codec=NULL; avi_port_t avi_port; pj_bzero(&avi_port, sizeof(avi_port)); status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams); if (status != PJ_SUCCESS) { PJ_PERROR(2,("", status, " Error playing %s", fname)); rc = 210; goto on_return; } vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams, 0, PJMEDIA_TYPE_VIDEO); vid_port = pjmedia_avi_stream_get_port(vid_stream); if (vid_port) { pjmedia_vid_port_param_default(¶m); status = pjmedia_vid_dev_default_param(pool, PJMEDIA_VID_DEFAULT_RENDER_DEV, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 220; goto on_return; } /* Create renderer, set it to active */ param.active = PJ_TRUE; param.vidparam.dir = PJMEDIA_DIR_RENDER; vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt, PJ_TRUE); pjmedia_format_init_video(¶m.vidparam.fmt, vid_port->info.fmt.id, vfd->size.w, vfd->size.h, vfd->fps.num, vfd->fps.denum); vfi = pjmedia_get_video_format_info( pjmedia_video_format_mgr_instance(), vid_port->info.fmt.id); /* Check whether the frame is encoded */ if (!vfi || vfi->bpp == 0) { /* Yes, prepare codec */ pj_str_t codec_id_st; unsigned info_cnt = 1, i, k; const pjmedia_vid_codec_info *codec_info; pj_str_t port_name = {"codec", 5}; pj_uint8_t *enc_buf = NULL; pj_size_t enc_buf_size = 0; pjmedia_vid_dev_info rdr_info; pjmedia_port codec_port; codec_port_data_t codec_port_data; pjmedia_vid_codec_param codec_param; struct codec_fmt *codecp = NULL; /* Lookup codec */ for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) { if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) { codecp = &codec_fmts[i]; break; } } if (!codecp) { rc = 242; goto on_return; } pj_cstr(&codec_id_st, codecp->codec_id); status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, &info_cnt, &codec_info, NULL); if (status != PJ_SUCCESS) { rc = 245; goto on_return; } status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, &codec_param); if (status != PJ_SUCCESS) { rc = 246; goto on_return; } pjmedia_format_copy(&codec_param.enc_fmt, ¶m.vidparam.fmt); pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info); for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) { for (k=0; k<rdr_info.fmt_cnt; ++k) { if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id) { param.vidparam.fmt.id = codec_info->dec_fmt_id[i]; i = codec_info->dec_fmt_id_cnt; break; } } } /* Open codec */ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info, &codec); if (status != PJ_SUCCESS) { rc = 250; goto on_return; } status = pjmedia_vid_codec_init(codec, pool); if (status != PJ_SUCCESS) { rc = 251; goto on_return; } pjmedia_format_copy(&codec_param.dec_fmt, ¶m.vidparam.fmt); codec_param.dir = PJMEDIA_DIR_DECODING; codec_param.packing = PJMEDIA_VID_PACKING_WHOLE; status = pjmedia_vid_codec_open(codec, &codec_param); if (status != PJ_SUCCESS) { rc = 252; goto on_return; } /* Alloc encoding buffer */ enc_buf_size = codec_param.dec_fmt.det.vid.size.w * codec_param.dec_fmt.det.vid.size.h * 4 + 16; /*< padding, just in case */ enc_buf = pj_pool_alloc(pool,enc_buf_size); /* Init codec port */ pj_bzero(&codec_port, sizeof(codec_port)); status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234, PJMEDIA_DIR_ENCODING, &codec_param.dec_fmt); if (status != PJ_SUCCESS) { rc = 260; goto on_return; } pj_bzero(&codec_port_data, sizeof(codec_port_data)); codec_port_data.codec = codec; codec_port_data.src_port = vid_port; codec_port_data.enc_buf = enc_buf; codec_port_data.enc_buf_size = enc_buf_size; codec_port.get_frame = &codec_get_frame; codec_port.port_data.pdata = &codec_port_data; /* Check whether we need to convert the decoded frame */ if (codecp->need_conversion) { pjmedia_conversion_param conv_param; pjmedia_format_copy(&conv_param.src, ¶m.vidparam.fmt); pjmedia_format_copy(&conv_param.dst, ¶m.vidparam.fmt); conv_param.dst.id = codecp->dst_fmt; param.vidparam.fmt.id = conv_param.dst.id; status = pjmedia_converter_create(NULL, pool, &conv_param, &codec_port_data.conv); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } } status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } status = pjmedia_vid_port_connect(renderer, &codec_port, PJ_FALSE); } else { status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 230; goto on_return; } /* Connect avi port to renderer */ status = pjmedia_vid_port_connect(renderer, vid_port, PJ_FALSE); } if (status != PJ_SUCCESS) { rc = 240; goto on_return; } } aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams, 0, PJMEDIA_TYPE_AUDIO); aud_port = pjmedia_avi_stream_get_port(aud_stream); if (aud_port) { /* Create sound player port. */ status = pjmedia_snd_port_create_player( pool, /* pool */ -1, /* use default dev. */ PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate. */ PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels. */ PJMEDIA_PIA_SPF(&aud_port->info), /* samples per frame. */ PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample. */ 0, /* options */ &snd_port /* returned port */ ); if (status != PJ_SUCCESS) { rc = 310; goto on_return; } /* Connect file port to the sound player. * Stream playing will commence immediately. */ status = pjmedia_snd_port_connect(snd_port, aud_port); if (status != PJ_SUCCESS) { rc = 330; goto on_return; } } if (vid_port) { pjmedia_vid_dev_cb cb; pj_bzero(&cb, sizeof(cb)); avi_port.snd_port = snd_port; avi_port.vid_port = renderer; avi_port.is_running = PJ_TRUE; pjmedia_vid_port_set_cb(renderer, &cb, &avi_port); /* subscribe events */ pjmedia_event_subscribe(NULL, &avi_event_cb, &avi_port, renderer); if (snd_port) { /* Synchronize video rendering and audio playback */ pjmedia_vid_port_set_clock_src( renderer, pjmedia_snd_port_get_clock_src( snd_port, PJMEDIA_DIR_PLAYBACK)); } /* Start video streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 270; goto on_return; } } while (!avi_port.is_quitting) { pj_thread_sleep(100); } on_return: if (snd_port) { pjmedia_snd_port_disconnect(snd_port); /* Without this sleep, Windows/DirectSound will repeteadly * play the last frame during destroy. */ pj_thread_sleep(100); pjmedia_snd_port_destroy(snd_port); } if (renderer) { pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port, renderer); pjmedia_vid_port_destroy(renderer); } if (aud_port) pjmedia_port_destroy(aud_port); if (vid_port) pjmedia_port_destroy(vid_port); if (codec) { pjmedia_vid_codec_close(codec); pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec); } return rc; }
/* Parse a multipart part. "pct" is parent content-type */ static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool, char *start, pj_size_t len, const pjsip_media_type *pct) { pjsip_multipart_part *part = pjsip_multipart_create_part(pool); char *p = start, *end = start+len, *end_hdr = NULL, *start_body = NULL; pjsip_ctype_hdr *ctype_hdr = NULL; TRACE_((THIS_FILE, "Parsing part: begin--\n%.*s\n--end", (int)len, start)); /* Find the end of header area, by looking at an empty line */ for (;;) { while (p!=end && *p!='\n') ++p; if (p==end) { start_body = end; break; } if ((p==start) || (p==start+1 && *(p-1)=='\r')) { /* Empty header section */ end_hdr = start; start_body = ++p; break; } else if (p==end-1) { /* Empty body section */ end_hdr = end; start_body = ++p; } else if ((p>=start+1 && *(p-1)=='\n') || (p>=start+2 && *(p-1)=='\r' && *(p-2)=='\n')) { /* Found it */ end_hdr = (*(p-1)=='\r') ? (p-1) : p; start_body = ++p; break; } else { ++p; } } /* Parse the headers */ if (end_hdr-start > 0) { pjsip_hdr *hdr; pj_status_t status; status = pjsip_parse_headers(pool, start, end_hdr-start, &part->hdr, 0); if (status != PJ_SUCCESS) { PJ_PERROR(2,(THIS_FILE, status, "Warning: error parsing multipart" " header")); } /* Find Content-Type header */ hdr = part->hdr.next; while (hdr != &part->hdr) { TRACE_((THIS_FILE, "Header parsed: %.*s", (int)hdr->name.slen, hdr->name.ptr)); if (hdr->type == PJSIP_H_CONTENT_TYPE) { ctype_hdr = (pjsip_ctype_hdr*)hdr; } hdr = hdr->next; } } /* Assign the body */ part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body); if (ctype_hdr) { pjsip_media_type_cp(pool, &part->body->content_type, &ctype_hdr->media); } else if (pct && pj_stricmp2(&pct->subtype, "digest")==0) { part->body->content_type.type = pj_str("message"); part->body->content_type.subtype = pj_str("rfc822"); } else { part->body->content_type.type = pj_str("text"); part->body->content_type.subtype = pj_str("plain"); } if (start_body < end) { part->body->data = start_body; part->body->len = (unsigned)(end - start_body); } else { part->body->data = (void*)""; part->body->len = 0; } TRACE_((THIS_FILE, "Body parsed: \"%.*s\"", (int)part->body->len, part->body->data)); part->body->print_body = &pjsip_print_text_body; part->body->clone_data = &pjsip_clone_text_data; return part; }
/* Create m=video SDP media line */ PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt, pj_pool_t *pool, const pjmedia_sock_info *si, unsigned options, pjmedia_sdp_media **p_m) { const pj_str_t STR_VIDEO = { "video", 5 }; pjmedia_sdp_media *m; pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS]; unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS]; pjmedia_sdp_attr *attr; unsigned cnt, i; unsigned max_bitrate = 0; pj_status_t status; PJ_UNUSED_ARG(options); /* Make sure video codec manager is instantiated */ if (!pjmedia_vid_codec_mgr_instance()) pjmedia_vid_codec_mgr_create(endpt->pool, NULL); /* Create and init basic SDP media */ m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); status = init_sdp_media(m, pool, &STR_VIDEO, si); if (status != PJ_SUCCESS) return status; cnt = PJ_ARRAY_SIZE(codec_info); status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, codec_info, codec_prio); /* Check that there are not too many codecs */ PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT, PJ_ETOOMANY); /* Add format, rtpmap, and fmtp (when applicable) for each codec */ for (i=0; i<cnt; ++i) { pjmedia_sdp_rtpmap rtpmap; pjmedia_vid_codec_param codec_param; pj_str_t *fmt; pjmedia_video_format_detail *vfd; pj_bzero(&rtpmap, sizeof(rtpmap)); if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED) break; if (i > PJMEDIA_MAX_SDP_FMT) { /* Too many codecs, perhaps it is better to tell application by * returning appropriate status code. */ PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY, "Skipping some video codecs")); break; } /* Must support RTP packetization and bidirectional */ if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 || codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING) { continue; } pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i], &codec_param); fmt = &m->desc.fmt[m->desc.fmt_count++]; fmt->ptr = (char*) pj_pool_alloc(pool, 8); fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr); rtpmap.pt = *fmt; /* Encoding name */ rtpmap.enc_name = codec_info[i].encoding_name; /* Clock rate */ rtpmap.clock_rate = codec_info[i].clock_rate; if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) { pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr); m->attr[m->attr_count++] = attr; } /* Add fmtp params */ if (codec_param.dec_fmtp.cnt > 0) { enum { MAX_FMTP_STR_LEN = 160 }; char buf[MAX_FMTP_STR_LEN]; unsigned buf_len = 0, j; pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp; /* Print codec PT */ buf_len += pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN - buf_len, "%d", codec_info[i].pt); for (j = 0; j < dec_fmtp->cnt; ++j) { unsigned test_len = 2; /* Check if buf still available */ test_len = dec_fmtp->param[j].val.slen + dec_fmtp->param[j].name.slen; if (test_len + buf_len >= MAX_FMTP_STR_LEN) return PJ_ETOOBIG; /* Print delimiter */ buf_len += pj_ansi_snprintf(&buf[buf_len], MAX_FMTP_STR_LEN - buf_len, (j == 0?" ":";")); /* Print an fmtp param */ if (dec_fmtp->param[j].name.slen) buf_len += pj_ansi_snprintf( &buf[buf_len], MAX_FMTP_STR_LEN - buf_len, "%.*s=%.*s", (int)dec_fmtp->param[j].name.slen, dec_fmtp->param[j].name.ptr, (int)dec_fmtp->param[j].val.slen, dec_fmtp->param[j].val.ptr); else buf_len += pj_ansi_snprintf(&buf[buf_len], MAX_FMTP_STR_LEN - buf_len, "%.*s", (int)dec_fmtp->param[j].val.slen, dec_fmtp->param[j].val.ptr); } attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); attr->name = pj_str("fmtp"); attr->value = pj_strdup3(pool, buf); m->attr[m->attr_count++] = attr; } /* Find maximum bitrate in this media */ vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt, PJ_TRUE); if (vfd && max_bitrate < vfd->max_bps) max_bitrate = vfd->max_bps; } /* Put bandwidth info in media level using bandwidth modifier "TIAS" * (RFC3890). */ if (max_bitrate) { const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 }; pjmedia_sdp_bandw *b; b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw); b->modifier = STR_BANDW_MODIFIER; b->value = max_bitrate; m->bandw[m->bandw_count++] = b; } *p_m = m; return PJ_SUCCESS; }
int errno_test(void) { enum { CUT = 6 }; pj_status_t rc = 0; char errbuf[256]; PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully")); PJ_UNUSED_ARG(rc); /* * Windows platform error. */ # ifdef ERROR_INVALID_DATA rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA); pj_set_os_error(rc); /* Whole */ pj_strerror(rc, errbuf, sizeof(errbuf)); trim_newlines(errbuf); PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf)); if (my_stristr(errbuf, "invalid") == NULL) { PJ_LOG(3, (THIS_FILE, "...error: expecting \"invalid\" string in the msg")); #ifndef PJ_WIN32_WINCE return -20; #endif } /* Cut version. */ pj_strerror(rc, errbuf, CUT); PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf)); # endif /* * Unix errors */ # if defined(EINVAL) && !defined(PJ_SYMBIAN) rc = PJ_STATUS_FROM_OS(EINVAL); pj_set_os_error(rc); /* Whole */ pj_strerror(rc, errbuf, sizeof(errbuf)); trim_newlines(errbuf); PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf)); if (my_stristr(errbuf, "invalid") == NULL) { PJ_LOG(3, (THIS_FILE, "...error: expecting \"invalid\" string in the msg")); return -30; } /* Cut */ pj_strerror(rc, errbuf, CUT); PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf)); # endif /* * Windows WSA errors */ # ifdef WSAEINVAL rc = PJ_STATUS_FROM_OS(WSAEINVAL); pj_set_os_error(rc); /* Whole */ pj_strerror(rc, errbuf, sizeof(errbuf)); trim_newlines(errbuf); PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf)); if (my_stristr(errbuf, "invalid") == NULL) { PJ_LOG(3, (THIS_FILE, "...error: expecting \"invalid\" string in the msg")); return -40; } /* Cut */ pj_strerror(rc, errbuf, CUT); PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf)); # endif pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf)); PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf)); if (my_stristr(errbuf, "BUG") == NULL) { PJ_LOG(3, (THIS_FILE, "...error: expecting \"BUG\" string in the msg")); return -20; } pj_strerror(PJ_EBUG, errbuf, CUT); PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", CUT, errbuf)); /* Perror */ pj_perror(3, THIS_FILE, PJ_SUCCESS, "...testing %s", "pj_perror"); PJ_PERROR(3,(THIS_FILE, PJ_SUCCESS, "...testing %s", "PJ_PERROR")); return 0; }
static int capture_render_loopback(pj_bool_t active, int cap_dev_id, int rend_dev_id, const pjmedia_format *fmt) { pj_pool_t *pool; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_dev_info cdi, rdi; pjmedia_vid_port_param param; pjmedia_video_format_detail *vfd; pj_status_t status; int rc = 0, i; pool = pj_pool_create(mem, "vidportloop", 1000, 1000, NULL); status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi); if (status != PJ_SUCCESS) goto on_return; status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi); if (status != PJ_SUCCESS) goto on_return; PJ_LOG(3,(THIS_FILE, " %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps", cdi.name, cdi.driver, rdi.name, rdi.driver, pjmedia_get_video_format_info(NULL, fmt->id)->name, fmt->det.vid.size.w, fmt->det.vid.size.h, fmt->det.vid.fps.num, fmt->det.vid.fps.denum)); pjmedia_vid_port_param_default(¶m); /* Create capture, set it to active (master) */ status = pjmedia_vid_dev_default_param(pool, cap_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 100; goto on_return; } param.vidparam.dir = PJMEDIA_DIR_CAPTURE; param.vidparam.fmt = *fmt; param.active = (active? PJ_TRUE: PJ_FALSE); if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) { rc = 103; goto on_return; } vfd = pjmedia_format_get_video_format_detail(¶m.vidparam.fmt, PJ_TRUE); if (vfd == NULL) { rc = 105; goto on_return; } status = pjmedia_vid_port_create(pool, ¶m, &capture); if (status != PJ_SUCCESS) { rc = 110; goto on_return; } /* Create renderer, set it to passive (slave) */ status = pjmedia_vid_dev_default_param(pool, rend_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 120; goto on_return; } param.active = (active? PJ_FALSE: PJ_TRUE); param.vidparam.dir = PJMEDIA_DIR_RENDER; param.vidparam.rend_id = rend_dev_id; param.vidparam.fmt = *fmt; param.vidparam.disp_size = vfd->size; status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 130; goto on_return; } /* Set event handler */ pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer); /* Connect capture to renderer */ status = pjmedia_vid_port_connect( (active? capture: renderer), pjmedia_vid_port_get_passive_port(active? renderer: capture), PJ_FALSE); if (status != PJ_SUCCESS) { rc = 140; goto on_return; } /* Start streaming.. */ status = pjmedia_vid_port_start(renderer); if (status != PJ_SUCCESS) { rc = 150; goto on_return; } status = pjmedia_vid_port_start(capture); if (status != PJ_SUCCESS) { rc = 160; goto on_return; } /* Sleep while the webcam is being displayed... */ for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) { pj_thread_sleep(100); } on_return: if (status != PJ_SUCCESS) PJ_PERROR(3, (THIS_FILE, status, " error")); if (capture) pjmedia_vid_port_stop(capture); if (renderer) pjmedia_vid_port_stop(renderer); if (capture) pjmedia_vid_port_destroy(capture); if (renderer) { pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer); pjmedia_vid_port_destroy(renderer); } pj_pool_release(pool); return rc; }