构建具有不同参数且可扩展的字符串

发布于 2024-12-13 08:29:38 字数 3497 浏览 2 评论 0原文

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
    c89

只是想知道是否有更好的方法可以使用我在下面提供的代码来做到这一点。

我正在根据一些参数构建 sdp(会话描述协议)字符串。

但是,我可能需要扩展 sdp 以包含其他参数,即视频编解码器。

但是,我真的不想再用 if else 来构建我在下面完成的完整字符串。

我只是想知道这是否足够可扩展?我可以使用比我所做的更好的技术吗?

我刚刚复制了构建 sdp 的函数:

void create_sdp_string(char *sdp_string, char reinvite)
{
    char session_id[MAX_STRING_LEN];
    char session_version[MAX_STRING_LEN];
    const char *local_ip_addr = "10.10.10.244";
    apr_time_t time_usec = 0;
    char session_identifier[MAX_STRING_LEN];
    char media_transport[MAX_STRING_LEN];
    char connection_info[MAX_STRING_LEN];
    const char *audio_port = "49152";

    /* Required sdp attributes */
#define V_PROTOCOL_VERSION "0"
#define USERNAME "JOEBLOGGS"
#define NETTYPE "IN"
#define ADDR_TYPE "IP4"
#define S_SESSION_NAME "SIP_CALL"
#define T_TIME_DESCRIPTION "0 0"
#define M_MEDIA_NAME_TRANSPORT_ADDR "RTP/AVP 0 8 101"
#define A_PCMU "rtpmap:0 PCMU/8000"
#define A_PCMA "rtpmap:8 PCMA/8000"
#define A_TELEPHONE "rtpmap:101 telephone-event/8000"

    /* Get the time in micro seconds to create an unique session id */
    time_usec = apr_time_usec(apr_time_now());
    apr_snprintf(session_id, MAX_STRING_LEN, "%lu", (unsigned long)time_usec);

    /* Get the time in micro seconds to create an unique session version */
    time_usec = apr_time_usec(apr_time_now());
    apr_snprintf(session_version, MAX_STRING_LEN, "%lu", (unsigned long)time_usec);

    /* Build session identifier */
    apr_snprintf(session_identifier,
                 MAX_STRING_LEN,
                 "o="USERNAME" "NETTYPE" %s %s "ADDR_TYPE" %s\n",
                 session_id,
                 session_version,
                 local_ip_addr);

    /* Build media transport */
    apr_snprintf(media_transport,
                 MAX_STRING_LEN,
                 "m=audio %s "M_MEDIA_NAME_TRANSPORT_ADDR"\n",
                 audio_port);

    /* Build connection information */
    apr_snprintf(connection_info,
                 MAX_STRING_LEN,
                 "c="NETTYPE" "ADDR_TYPE" %s\n",
                 local_ip_addr);

    if(reinvite == FALSE) {
        /* Build complete sdp string for cases that are not reinvite */
        apr_snprintf(sdp_string,
                     MAX_SDP_STRING_LEN,
                     "v="V_PROTOCOL_VERSION"\n"
                     "%s"
                     "s="S_SESSION_NAME"\n"
                     "%s"
                     "t="T_TIME_DESCRIPTION"\n"
                     "%s"
                     "a="A_PCMU"\n"
                     "a="A_PCMA"\n"
                     "a="A_TELEPHONE"\n",
                     session_identifier,
                     connection_info,
                     media_transport);
    }
    else if(reinvite == TRUE) {
        /* Build complete sdp string for cases that are for reinvite 'inactive' */
#define INACTIVE "inactive"
        apr_snprintf(sdp_string,
                     MAX_SDP_STRING_LEN,
                     "v="V_PROTOCOL_VERSION"\n"
                     "%s"
                     "s="S_SESSION_NAME"\n"
                     "%s"
                     "t="T_TIME_DESCRIPTION"\n"
                     "%s"
                     "a="A_PCMU"\n"
                     "a="A_PCMA"\n"
                     "a="A_TELEPHONE"\n"
                     "a="INACTIVE"\n",
                     session_identifier,
                     connection_info,
                     media_transport);
    }
}
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
    c89

Just wondering is there a better way to do this with the code I have provided below.

I am building a sdp (session description protocol) string from some parameters.

However, I might need to extend the sdp to include other parameters i.e. video codecs.

However, I don't really want to have another if else to build the complete string I have done below.

I am just wondering is this scalable enough? Is there any technique I could use that is better than what I have done.

I have just copied the function that does the sdp building:

void create_sdp_string(char *sdp_string, char reinvite)
{
    char session_id[MAX_STRING_LEN];
    char session_version[MAX_STRING_LEN];
    const char *local_ip_addr = "10.10.10.244";
    apr_time_t time_usec = 0;
    char session_identifier[MAX_STRING_LEN];
    char media_transport[MAX_STRING_LEN];
    char connection_info[MAX_STRING_LEN];
    const char *audio_port = "49152";

    /* Required sdp attributes */
#define V_PROTOCOL_VERSION "0"
#define USERNAME "JOEBLOGGS"
#define NETTYPE "IN"
#define ADDR_TYPE "IP4"
#define S_SESSION_NAME "SIP_CALL"
#define T_TIME_DESCRIPTION "0 0"
#define M_MEDIA_NAME_TRANSPORT_ADDR "RTP/AVP 0 8 101"
#define A_PCMU "rtpmap:0 PCMU/8000"
#define A_PCMA "rtpmap:8 PCMA/8000"
#define A_TELEPHONE "rtpmap:101 telephone-event/8000"

    /* Get the time in micro seconds to create an unique session id */
    time_usec = apr_time_usec(apr_time_now());
    apr_snprintf(session_id, MAX_STRING_LEN, "%lu", (unsigned long)time_usec);

    /* Get the time in micro seconds to create an unique session version */
    time_usec = apr_time_usec(apr_time_now());
    apr_snprintf(session_version, MAX_STRING_LEN, "%lu", (unsigned long)time_usec);

    /* Build session identifier */
    apr_snprintf(session_identifier,
                 MAX_STRING_LEN,
                 "o="USERNAME" "NETTYPE" %s %s "ADDR_TYPE" %s\n",
                 session_id,
                 session_version,
                 local_ip_addr);

    /* Build media transport */
    apr_snprintf(media_transport,
                 MAX_STRING_LEN,
                 "m=audio %s "M_MEDIA_NAME_TRANSPORT_ADDR"\n",
                 audio_port);

    /* Build connection information */
    apr_snprintf(connection_info,
                 MAX_STRING_LEN,
                 "c="NETTYPE" "ADDR_TYPE" %s\n",
                 local_ip_addr);

    if(reinvite == FALSE) {
        /* Build complete sdp string for cases that are not reinvite */
        apr_snprintf(sdp_string,
                     MAX_SDP_STRING_LEN,
                     "v="V_PROTOCOL_VERSION"\n"
                     "%s"
                     "s="S_SESSION_NAME"\n"
                     "%s"
                     "t="T_TIME_DESCRIPTION"\n"
                     "%s"
                     "a="A_PCMU"\n"
                     "a="A_PCMA"\n"
                     "a="A_TELEPHONE"\n",
                     session_identifier,
                     connection_info,
                     media_transport);
    }
    else if(reinvite == TRUE) {
        /* Build complete sdp string for cases that are for reinvite 'inactive' */
#define INACTIVE "inactive"
        apr_snprintf(sdp_string,
                     MAX_SDP_STRING_LEN,
                     "v="V_PROTOCOL_VERSION"\n"
                     "%s"
                     "s="S_SESSION_NAME"\n"
                     "%s"
                     "t="T_TIME_DESCRIPTION"\n"
                     "%s"
                     "a="A_PCMU"\n"
                     "a="A_PCMA"\n"
                     "a="A_TELEPHONE"\n"
                     "a="INACTIVE"\n",
                     session_identifier,
                     connection_info,
                     media_transport);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟花肆意 2024-12-20 08:29:38

如果你想要更通用的东西,请看这个:

void append_to_sdp_string(char *sdp_string, char *param)
{
  int size = strlen(sdp_string);
  apr_snprintf(sdp_string + size, MAX_SDP_STRING_LEN - size, "%s\n", param);
}

void create_sdp_string(char *sdp_string, char reinvite)
{
  /* Defines and variables here */

  apr_snprintf(session_id, MAX_STRING_LEN, "%lu", (unsigned long) apr_time_usec(apr_time_now());
  apr_snprintf(session_version, MAX_STRING_LEN, "%lu", (unsigned long) apr_time_usec(apr_time_now());
  apr_snprintf(session_identifier, MAX_STRING_LEN, "o="USERNAME" "NETTYPE" %s %s "ADDR_TYPE" %s", session_id, session_version, local_ip_addr);
  apr_snprintf(media_transport, MAX_STRING_LEN, "m=audio %s "M_MEDIA_NAME_TRANSPORT_ADDR"", audio_port);
  apr_snprintf(connection_info, MAX_STRING_LEN, "c="NETTYPE" "ADDR_TYPE" %s", local_ip_addr);

  append_to_sdp_string(sdp_string, "v="V_PROTOCOL_VERSION);
  append_to_sdp_string(sdp_string, session_identifier);
  append_to_sdp_string(sdp_string, "s="S_SESSION_NAME);
  append_to_sdp_string(sdp_string, connection_info);
  append_to_sdp_string(sdp_string, "t="T_TIME_DESCRIPTION);
  append_to_sdp_string(sdp_string, media_transport);
  append_to_sdp_string(sdp_string, "a="A_PCMU);
  append_to_sdp_string(sdp_string, "a="A_PCMA);
  append_to_sdp_string(sdp_string, "a="A_TELEPHONE);

  if(reinvite == TRUE)
    append_to_sdp_string(sdp_string, "a="INACTIVE);

  /* Here you can add as many simple conditional appends as you need */
}

这样可以很容易地将任何内容附加到你已经创建的字符串中。

If you want something more generic look at this:

void append_to_sdp_string(char *sdp_string, char *param)
{
  int size = strlen(sdp_string);
  apr_snprintf(sdp_string + size, MAX_SDP_STRING_LEN - size, "%s\n", param);
}

void create_sdp_string(char *sdp_string, char reinvite)
{
  /* Defines and variables here */

  apr_snprintf(session_id, MAX_STRING_LEN, "%lu", (unsigned long) apr_time_usec(apr_time_now());
  apr_snprintf(session_version, MAX_STRING_LEN, "%lu", (unsigned long) apr_time_usec(apr_time_now());
  apr_snprintf(session_identifier, MAX_STRING_LEN, "o="USERNAME" "NETTYPE" %s %s "ADDR_TYPE" %s", session_id, session_version, local_ip_addr);
  apr_snprintf(media_transport, MAX_STRING_LEN, "m=audio %s "M_MEDIA_NAME_TRANSPORT_ADDR"", audio_port);
  apr_snprintf(connection_info, MAX_STRING_LEN, "c="NETTYPE" "ADDR_TYPE" %s", local_ip_addr);

  append_to_sdp_string(sdp_string, "v="V_PROTOCOL_VERSION);
  append_to_sdp_string(sdp_string, session_identifier);
  append_to_sdp_string(sdp_string, "s="S_SESSION_NAME);
  append_to_sdp_string(sdp_string, connection_info);
  append_to_sdp_string(sdp_string, "t="T_TIME_DESCRIPTION);
  append_to_sdp_string(sdp_string, media_transport);
  append_to_sdp_string(sdp_string, "a="A_PCMU);
  append_to_sdp_string(sdp_string, "a="A_PCMA);
  append_to_sdp_string(sdp_string, "a="A_TELEPHONE);

  if(reinvite == TRUE)
    append_to_sdp_string(sdp_string, "a="INACTIVE);

  /* Here you can add as many simple conditional appends as you need */
}

This way it's easy to append anything to string which you already created.

甜是你 2024-12-20 08:29:38

我认为代码底部的 if/else if 语句非常丑陋,因为您已将大量代码复制到两个不同的位置。您可能会在一处编辑它,但忘记在另一处编辑它。你真的应该尽力避免这种情况。一种方法是用以下语句替换 if/else if 语句:

apr_snprintf(sdp_string,
  MAX_SDP_STRING_LEN,
  "v="V_PROTOCOL_VERSION"\n"
  "%s"
  "s="S_SESSION_NAME"\n"
  "%s"
  "t="T_TIME_DESCRIPTION"\n"
  "%s"
  "a="A_PCMU"\n"
  "a="A_PCMA"\n"
  "a="A_TELEPHONE"\n"
  "%s",
  session_identifier,
  connection_info,
  media_transport,
  reinvite ? "a=inactive\n" : "");

EDIT1: 使此代码更好的另一种方法是编写您自己的 printf 版本bytes 到 sdp_string,然后为要添加到字符串的每个不同信息调用该函数一次。

I consider the if/else if statement at the bottom of your code to be pretty ugly because you have copied a lot of code to two different places. You might edit it one place but forget to edit it in another. You should really try to avoid this. One way to do this is to replace the if/else if statement with this:

apr_snprintf(sdp_string,
  MAX_SDP_STRING_LEN,
  "v="V_PROTOCOL_VERSION"\n"
  "%s"
  "s="S_SESSION_NAME"\n"
  "%s"
  "t="T_TIME_DESCRIPTION"\n"
  "%s"
  "a="A_PCMU"\n"
  "a="A_PCMA"\n"
  "a="A_TELEPHONE"\n"
  "%s",
  session_identifier,
  connection_info,
  media_transport,
  reinvite ? "a=inactive\n" : "");

EDIT1: Another way to make this code better would be to write your own version of printf adds bytes to sdp_string, and then call that function once for each different piece of information you want to add to the string.

柠檬 2024-12-20 08:29:38

如果您的代码中存在性能瓶颈,那么这不是 if/else 结构的问题,而是您多次扫描所有字符串的事实。

基本上,您主要使用 snprintf 的变体来连接字符串,这是非常低效的。

切换到一种策略,将字符串一个接一个地写入到位,就像您在文件中使用 fputs 所做的那样:

  • 首先,对于您打印的两个数字,跟踪结果
    通过snprintf的返回给出的字符串长度。
  • 对于所有常量字符串,不要将它们放在 #define 中,而是将它们放在实际数组中,例如 static char const V_PROTOCOL_VERSION = { "0" };。此类字符串的大小是一个编译时常量,您可以通过 (sizeof V_PROTOCOL_VERSION)-1 来获取。
  • 对于输出字符串,保留指向实际位置的指针,
  • 将当前字符串写入该位置并更新指针
    与您编写的字符串的已知长度

这可确保您复制的每个字符恰好接触所有这些常量字符串一次。

If there is a performance bottleneck in your code this is not the if/else structure, but the fact that you scan all your strings several times.

Basically you use your variant of snprintf mostly to concatenate strings, this is very unefficient.

Switch to a strategy that writes the strings in place just one after another, as you would do with fputs if this were a file:

  • first, for the two numbers that you print, keep track of the resulting
    string length which is given through the return of snprintf.
  • for all constant strings instead of placing them in #define put the in a real array such as static char const V_PROTOCOL_VERSION = { "0" };. the size of such an string is a compile time constant that you can optain by (sizeof V_PROTOCOL_VERSION)-1.
  • for the output string, keep a pointer to the actual position to write
  • write the current string into that position and update your pointer
    with the known length of the string that you have written

This ensures that you touch all those constant strings exactly once per character that you copy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文