summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia/transport_adapter_sample.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjmedia/src/pjmedia/transport_adapter_sample.c')
-rw-r--r--pjmedia/src/pjmedia/transport_adapter_sample.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/pjmedia/src/pjmedia/transport_adapter_sample.c b/pjmedia/src/pjmedia/transport_adapter_sample.c
new file mode 100644
index 00000000..b4d4c9da
--- /dev/null
+++ b/pjmedia/src/pjmedia/transport_adapter_sample.c
@@ -0,0 +1,433 @@
+/* $Id:$ */
+/*
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjmedia/transport_adapter_sample.h>
+#include <pjmedia/endpoint.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+
+
+/* Transport functions prototypes */
+static pj_status_t transport_get_info (pjmedia_transport *tp,
+ pjmedia_transport_info *info);
+static pj_status_t transport_attach (pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ void*,
+ pj_ssize_t));
+static void transport_detach (pjmedia_transport *tp,
+ void *strm);
+static pj_status_t transport_send_rtp( pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_media_start (pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index);
+static pj_status_t transport_media_stop(pjmedia_transport *tp);
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+ pjmedia_dir dir,
+ unsigned pct_lost);
+static pj_status_t transport_destroy (pjmedia_transport *tp);
+
+
+/* The transport operations */
+static struct pjmedia_transport_op tp_adapter_op =
+{
+ &transport_get_info,
+ &transport_attach,
+ &transport_detach,
+ &transport_send_rtp,
+ &transport_send_rtcp,
+ &transport_send_rtcp2,
+ &transport_media_create,
+ &transport_encode_sdp,
+ &transport_media_start,
+ &transport_media_stop,
+ &transport_simulate_lost,
+ &transport_destroy
+};
+
+
+/* The transport adapter instance */
+struct tp_adapter
+{
+ pjmedia_transport base;
+
+ pj_pool_t *pool;
+
+ /* Stream information. */
+ void *stream_user_data;
+ void (*stream_rtp_cb)(void *user_data,
+ void *pkt,
+ pj_ssize_t);
+ void (*stream_rtcp_cb)(void *user_data,
+ void *pkt,
+ pj_ssize_t);
+
+
+ /* Add your own member here.. */
+ pjmedia_transport *slave_tp;
+};
+
+
+/*
+ * Create the adapter.
+ */
+PJ_DEF(pj_status_t) pjmedia_tp_adapter_create( pjmedia_endpt *endpt,
+ const char *name,
+ pjmedia_transport *transport,
+ pjmedia_transport **p_tp)
+{
+ pj_pool_t *pool;
+ struct tp_adapter *adapter;
+
+ if (name == NULL)
+ name = "tpad%p";
+
+ /* Create the pool and initialize the adapter structure */
+ pool = pjmedia_endpt_create_pool(endpt, name, 512, 512);
+ adapter = PJ_POOL_ZALLOC_T(pool, struct tp_adapter);
+ adapter->pool = pool;
+ pj_ansi_strncpy(adapter->base.name, pool->obj_name,
+ sizeof(adapter->base.name));
+ adapter->base.type = PJMEDIA_TRANSPORT_TYPE_USER + 1;
+ adapter->base.op = &tp_adapter_op;
+
+ /* Save the transport as the slave transport */
+ adapter->slave_tp = transport;
+
+ /* Done */
+ *p_tp = &adapter->base;
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * get_info() is called to get the transport addresses to be put
+ * in SDP c= line and a=rtcp line.
+ */
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+ pjmedia_transport_info *info)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* Since we don't have our own connection here, we just pass
+ * this function to the slave transport.
+ */
+ return pjmedia_transport_get_info(adapter->slave_tp, info);
+}
+
+
+/* This is our RTP callback, that is called by the slave transport when it
+ * receives RTP packet.
+ */
+static void transport_rtp_cb(void *user_data, void *pkt, pj_ssize_t size)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)user_data;
+
+ pj_assert(adapter->stream_rtp_cb != NULL);
+
+ /* Call stream's callback */
+ adapter->stream_rtp_cb(adapter->stream_user_data, pkt, size);
+}
+
+/* This is our RTCP callback, that is called by the slave transport when it
+ * receives RTCP packet.
+ */
+static void transport_rtcp_cb(void *user_data, void *pkt, pj_ssize_t size)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)user_data;
+
+ pj_assert(adapter->stream_rtcp_cb != NULL);
+
+ /* Call stream's callback */
+ adapter->stream_rtcp_cb(adapter->stream_user_data, pkt, size);
+}
+
+
+/*
+ * attach() is called by stream to register callbacks that we should
+ * call on receipt of RTP and RTCP packets.
+ */
+static pj_status_t transport_attach(pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ void*,
+ pj_ssize_t))
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+ pj_status_t status;
+
+ /* In this example, we will save the stream information and callbacks
+ * to our structure, and we will register different RTP/RTCP callbacks
+ * instead.
+ */
+ pj_assert(adapter->stream_user_data == NULL);
+ adapter->stream_user_data = user_data;
+ adapter->stream_rtp_cb = rtp_cb;
+ adapter->stream_rtcp_cb = rtcp_cb;
+
+ status = pjmedia_transport_attach(adapter->slave_tp, adapter, rem_addr,
+ rem_rtcp, addr_len, &transport_rtp_cb,
+ &transport_rtcp_cb);
+ if (status != PJ_SUCCESS) {
+ adapter->stream_user_data = NULL;
+ adapter->stream_rtp_cb = NULL;
+ adapter->stream_rtcp_cb = NULL;
+ return status;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * detach() is called when the media is terminated, and the stream is
+ * to be disconnected from us.
+ */
+static void transport_detach(pjmedia_transport *tp, void *strm)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ PJ_UNUSED_ARG(strm);
+
+ if (adapter->stream_user_data != NULL) {
+ pjmedia_transport_detach(adapter->slave_tp, adapter);
+ adapter->stream_user_data = NULL;
+ adapter->stream_rtp_cb = NULL;
+ adapter->stream_rtcp_cb = NULL;
+ }
+}
+
+
+/*
+ * send_rtp() is called to send RTP packet. The "pkt" and "size" argument
+ * contain both the RTP header and the payload.
+ */
+static pj_status_t transport_send_rtp( pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* You may do some processing to the RTP packet here if you want. */
+
+ /* Send the packet using the slave transport */
+ return pjmedia_transport_send_rtp(adapter->slave_tp, pkt, size);
+}
+
+
+/*
+ * send_rtcp() is called to send RTCP packet. The "pkt" and "size" argument
+ * contain the RTCP packet.
+ */
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* You may do some processing to the RTCP packet here if you want. */
+
+ /* Send the packet using the slave transport */
+ return pjmedia_transport_send_rtcp(adapter->slave_tp, pkt, size);
+}
+
+
+/*
+ * This is another variant of send_rtcp(), with the alternate destination
+ * address in the argument.
+ */
+static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+ return pjmedia_transport_send_rtcp2(adapter->slave_tp, addr, addr_len,
+ pkt, size);
+}
+
+/*
+ * The media_create() is called when the transport is about to be used for
+ * a new call.
+ */
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* if "rem_sdp" is not NULL, it means we are UAS. You may do some
+ * inspections on the incoming SDP to verify that the SDP is acceptable
+ * for us. If the SDP is not acceptable, we can reject the SDP by
+ * returning non-PJ_SUCCESS.
+ */
+ if (rem_sdp) {
+ /* Do your stuff.. */
+ }
+
+ /* Once we're done with our initialization, pass the call to the
+ * slave transports to let it do it's own initialization too.
+ */
+ return pjmedia_transport_media_create(adapter->slave_tp, sdp_pool, options,
+ rem_sdp, media_index);
+}
+
+/*
+ * The encode_sdp() is called when we're about to send SDP to remote party,
+ * either as SDP offer or as SDP answer.
+ */
+static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* If "rem_sdp" is not NULL, it means we're encoding SDP answer. You may
+ * do some more checking on the SDP's once again to make sure that
+ * everything is okay before we send SDP.
+ */
+ if (rem_sdp) {
+ /* Do checking stuffs here.. */
+ }
+
+ /* You may do anything to the local_sdp, e.g. adding new attributes, or
+ * even modifying the SDP if you want.
+ */
+ if (1) {
+ /* Say we add a proprietary attribute here.. */
+ pjmedia_sdp_attr *my_attr;
+
+ my_attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr);
+ pj_strdup2(sdp_pool, &my_attr->name, "X-adapter");
+ pj_strdup2(sdp_pool, &my_attr->value, "some value");
+
+ pjmedia_sdp_attr_add(&local_sdp->media[media_index]->attr_count,
+ local_sdp->media[media_index]->attr,
+ my_attr);
+ }
+
+ /* And then pass the call to slave transport to let it encode its
+ * information in the SDP. You may choose to call encode_sdp() to slave
+ * first before adding your custom attributes if you want.
+ */
+ return pjmedia_transport_encode_sdp(adapter->slave_tp, sdp_pool, local_sdp,
+ rem_sdp, media_index);
+}
+
+/*
+ * The media_start() is called once both local and remote SDP have been
+ * negotiated successfully, and the media is ready to start. Here we can start
+ * committing our processing.
+ */
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ unsigned media_index)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* Do something.. */
+
+ /* And pass the call to the slave transport */
+ return pjmedia_transport_media_start(adapter->slave_tp, pool, local_sdp,
+ rem_sdp, media_index);
+}
+
+/*
+ * The media_stop() is called when media has been stopped.
+ */
+static pj_status_t transport_media_stop(pjmedia_transport *tp)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* Do something.. */
+
+ /* And pass the call to the slave transport */
+ return pjmedia_transport_media_stop(adapter->slave_tp);
+}
+
+/*
+ * simulate_lost() is called to simulate packet lost
+ */
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+ pjmedia_dir dir,
+ unsigned pct_lost)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+ return pjmedia_transport_simulate_lost(adapter->slave_tp, dir, pct_lost);
+}
+
+/*
+ * destroy() is called when the transport is no longer needed.
+ */
+static pj_status_t transport_destroy (pjmedia_transport *tp)
+{
+ struct tp_adapter *adapter = (struct tp_adapter*)tp;
+
+ /* Close the slave transport */
+ pjmedia_transport_close(adapter->slave_tp);
+
+ /* Self destruct.. */
+ pj_pool_release(adapter->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+
+
+