sdp.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:9k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * sdp.c : SDP creation helpers
  3.  *****************************************************************************
  4.  * Copyright © 2007 Rémi Denis-Courmont
  5.  * $Id: 47bb16fd9ab3ad1bfab36f80e54a127acf6cd6e0 $
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU Lesser General Public License as published by
  9.  * the Free Software Foundation; either version 2.1 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  20.  *****************************************************************************/
  21. #ifdef HAVE_CONFIG_H
  22. # include "config.h"
  23. #endif
  24. #include <vlc_common.h>
  25. #include <stddef.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <assert.h>
  30. #include <vlc_network.h>
  31. #include <vlc_charset.h>
  32. #include "stream_output.h"
  33. #define MAXSDPADDRESS 47
  34. static
  35. char *AddressToSDP (const struct sockaddr *addr, socklen_t addrlen, char *buf)
  36. {
  37.     if (addrlen < offsetof (struct sockaddr, sa_family)
  38.                  + sizeof (addr->sa_family))
  39.         return NULL;
  40.     strcpy (buf, "IN IP* ");
  41.     if (vlc_getnameinfo (addr, addrlen, buf + 7, MAXSDPADDRESS - 7, NULL,
  42.                          NI_NUMERICHOST))
  43.         return NULL;
  44.     switch (addr->sa_family)
  45.     {
  46.         case AF_INET:
  47.         {
  48.             if (net_SockAddrIsMulticast (addr, addrlen))
  49.                 strcat (buf, "/255"); // obsolete in RFC4566, dummy value
  50.             buf[5] = '4';
  51.             break;
  52.         }
  53. #ifdef AF_INET6
  54.         case AF_INET6:
  55.         {
  56.             char *ptr = strchr (buf, '%');
  57.             if (ptr != NULL)
  58.                 *ptr = ''; // remove scope ID
  59.             buf[5] = '6';
  60.             break;
  61.         }
  62. #endif
  63.         default:
  64.             return NULL;
  65.     }
  66.     return buf;
  67. }
  68. static bool IsSDPString (const char *str)
  69. {
  70.     if (strchr (str, 'r') != NULL)
  71.         return false;
  72.     if (strchr (str, 'n') != NULL)
  73.         return false;
  74.     if (!IsUTF8 (str))
  75.         return false;
  76.     return true;
  77. }
  78. static
  79. char *sdp_Start (const char *name, const char *description, const char *url,
  80.                  const char *email, const char *phone,
  81.                  const struct sockaddr *src, size_t srclen,
  82.                  const struct sockaddr *addr, size_t addrlen)
  83. {
  84.     uint64_t now = NTPtime64 ();
  85.     char *sdp;
  86.     char connection[MAXSDPADDRESS], hostname[256],
  87.          sfilter[MAXSDPADDRESS + sizeof ("rna=source-filter: incl * ")];
  88.     const char *preurl = "rnu=", *premail = "rne=", *prephone = "rnp=";
  89.     gethostname (hostname, sizeof (hostname));
  90.     if (name == NULL)
  91.         name = "Unnamed";
  92.     if (description == NULL)
  93.         description = "N/A";
  94.     if (url == NULL)
  95.         preurl = url = "";
  96.     if (email == NULL)
  97.         premail = email = "";
  98.     if (phone == NULL)
  99.         prephone = phone = "";
  100.     if (!IsSDPString (name) || !IsSDPString (description)
  101.      || !IsSDPString (url) || !IsSDPString (email) || !IsSDPString (phone)
  102.      || (AddressToSDP (addr, addrlen, connection) == NULL))
  103.         return NULL;
  104.     strcpy (sfilter, "");
  105.     if (srclen > 0)
  106.     {
  107.         char machine[MAXSDPADDRESS];
  108.         if (AddressToSDP (src, srclen, machine) != NULL)
  109.             sprintf (sfilter, "rna=source-filter: incl IN IP%c * %s",
  110.                      machine[5], machine + 7);
  111.     }
  112.     if (asprintf (&sdp, "v=0"
  113.                     "rno=- %"PRIu64" %"PRIu64" IN IP%c %s"
  114.                     "rns=%s"
  115.                     "rni=%s"
  116.                     "%s%s" // optional URL
  117.                     "%s%s" // optional email
  118.                     "%s%s" // optional phone number
  119.                     "rnc=%s"
  120.                         // bandwidth not specified
  121.                     "rnt=0 0" // one dummy time span
  122.                         // no repeating
  123.                         // no time zone adjustment (silly idea anyway)
  124.                         // no encryption key (deprecated)
  125.                     "rna=tool:"PACKAGE_STRING
  126.                     "rna=recvonly"
  127.                     "rna=type:broadcast"
  128.                     "rna=charset:UTF-8"
  129.                     "%s" // optional source filter
  130.                     "rn",
  131.                /* o= */ now, now, connection[5], hostname,
  132.                /* s= */ name,
  133.                /* i= */ description,
  134.                /* u= */ preurl, url,
  135.                /* e= */ premail, email,
  136.                /* p= */ prephone, phone,
  137.                /* c= */ connection,
  138.     /* source-filter */ sfilter) == -1)
  139.         return NULL;
  140.     return sdp;
  141. }
  142. static char *
  143. vsdp_AddAttribute (char **sdp, const char *name, const char *fmt, va_list ap)
  144. {
  145.     size_t oldlen = strlen (*sdp);
  146.     size_t addlen = sizeof ("a=rn") + strlen (name);
  147.     if (fmt != NULL)
  148.     {
  149.         va_list aq;
  150.         va_copy (aq, ap);
  151.         addlen += 1 + vsnprintf (NULL, 0, fmt, aq);
  152.         va_end (aq);
  153.     }
  154.     char *ret = realloc (*sdp, oldlen + addlen);
  155.     if (ret == NULL)
  156.         return NULL;
  157.     oldlen += sprintf (ret + oldlen, "a=%s", name);
  158.     if (fmt != NULL)
  159.     {
  160.         ret[oldlen++] = ':';
  161.         oldlen += vsprintf (ret + oldlen, fmt, ap);
  162.     }
  163.     strcpy (ret + oldlen, "rn");
  164.     return *sdp = ret;
  165. }
  166. char *sdp_AddAttribute (char **sdp, const char *name, const char *fmt, ...)
  167. {
  168.     char *ret;
  169.     va_list ap;
  170.     va_start (ap, fmt);
  171.     ret = vsdp_AddAttribute (sdp, name, fmt, ap);
  172.     va_end (ap);
  173.     return ret;
  174. }
  175. char *sdp_AddMedia (char **sdp,
  176.                     const char *type, const char *protocol, int dport,
  177.                     unsigned pt, bool bw_indep, unsigned bw,
  178.                     const char *ptname, unsigned clock, unsigned chans,
  179.                     const char *fmtp)
  180. {
  181.     char *newsdp, *ptr;
  182.     size_t inlen = strlen (*sdp), outlen = inlen;
  183.     /* Some default values */
  184.     if (type == NULL)
  185.         type = "video";
  186.     if (protocol == NULL)
  187.         protocol = "RTP/AVP";
  188.     assert (pt < 128u);
  189.     outlen += snprintf (NULL, 0,
  190.                         "m=%s %u %s %drn"
  191.                         "b=TIAS:%urn",
  192.                         type, dport, protocol, pt, bw);
  193.     newsdp = realloc (*sdp, outlen + 1);
  194.     if (newsdp == NULL)
  195.         return NULL;
  196.     *sdp = newsdp;
  197.     ptr = newsdp + inlen;
  198.     ptr += sprintf (ptr, "m=%s %u %s %urn",
  199.                          type, dport, protocol, pt);
  200.     if (bw > 0)
  201.         ptr += sprintf (ptr, "b=%s:%urn", bw_indep ? "TIAS" : "AS", bw);
  202.     /* RTP payload type map */
  203.     if (ptname != NULL)
  204.     {
  205.         if ((strcmp (type, "audio") == 0) && (chans != 1))
  206.             sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u/%u", pt, ptname, clock,
  207.                               chans);
  208.         else
  209.             sdp_AddAttribute (sdp, "rtpmap", "%u %s/%u", pt, ptname, clock);
  210.     }
  211.     /* Format parameters */
  212.     if (fmtp != NULL)
  213.         sdp_AddAttribute (sdp, "fmtp", "%u %s", pt, fmtp);
  214.     return newsdp;
  215. }
  216. char *vlc_sdp_Start (vlc_object_t *obj, const char *cfgpref,
  217.                      const struct sockaddr *src, size_t srclen,
  218.                      const struct sockaddr *addr, size_t addrlen)
  219. {
  220.     size_t cfglen = strlen (cfgpref);
  221.     if (cfglen > 100)
  222.         return NULL;
  223.     char varname[cfglen + sizeof ("description")], *subvar = varname + cfglen;
  224.     strcpy (varname, cfgpref);
  225.     strcpy (subvar, "name");
  226.     char *name = var_GetNonEmptyString (obj, varname);
  227.     strcpy (subvar, "description");
  228.     char *description = var_GetNonEmptyString (obj, varname);
  229.     strcpy (subvar, "url");
  230.     char *url = var_GetNonEmptyString (obj, varname);
  231.     strcpy (subvar, "email");
  232.     char *email = var_GetNonEmptyString (obj, varname);
  233.     strcpy (subvar, "phone");
  234.     char *phone = var_GetNonEmptyString (obj, varname);
  235.     char *sdp = sdp_Start (name, description, url, email, phone,
  236.                            src, srclen, addr, addrlen);
  237.     free (name);
  238.     free (description);
  239.     free (url);
  240.     free (email);
  241.     free (phone);
  242.     if (sdp == NULL)
  243.         return NULL;
  244.     /* Totally non-standard */
  245.     strcpy (subvar, "group");
  246.     char *group = var_GetNonEmptyString (obj, varname);
  247.     if (group != NULL)
  248.     {
  249.         sdp_AddAttribute (&sdp, "x-plgroup", "%s", group);
  250.         free (group);
  251.     }
  252.     return sdp;
  253. }