построение строки с различными параметрами, которая является масштабируемой - PullRequest
1 голос
/ 02 ноября 2011
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
    c89

Просто интересно, есть ли лучший способ сделать это с помощью кода, который я предоставил ниже.

Я строю строку sdp (протокол описания сеанса) из некоторых параметров.

Однако мне может понадобиться расширить sdp, чтобы включить другие параметры, например, видеокодеки.

Тем не менее, я на самом деле не хочу иметь другой, если еще построить полную строку, которую я сделал ниже.

Мне просто интересно, достаточно ли это масштабируемо? Могу ли я использовать какую-либо технику, которая лучше, чем та, которую я сделал?

Я только что скопировал функцию, которая делает сборку 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);
    }
}

Ответы [ 3 ]

2 голосов
/ 11 ноября 2011

Если вы хотите что-то более общее, посмотрите на это:

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 */
}

Таким образом, легко добавить что-либо в строку, которую вы уже создали.

2 голосов
/ 02 ноября 2011

Я считаю оператор 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.байт sdp_string, а затем вызовите эту функцию один раз для каждого отдельного фрагмента информации, который вы хотите добавить в строку.

1 голос
/ 07 ноября 2011

Если в вашем коде есть узкое место в производительности, это не структура if/else, а тот факт, что вы сканируете все свои строки несколько раз.

В основном вы используете свой вариант snprintf в основном дляобъединять строки, это очень неэффективно.

Переключитесь на стратегию, в которой строки записываются на месте только одна за другой, как если бы это был файл fputs, если бы это был файл:

  • сначала для двух чиселчто вы печатаете, следите за результирующей длиной строки, которая дается через возвращение snprintf.
  • для всех константных строк, вместо того, чтобы помещать их в #define, помещая их в реальный массив, такой как static char const V_PROTOCOL_VERSION = { "0" };.размер такой строки - это постоянная времени компиляции, которую вы можете получить с помощью (sizeof V_PROTOCOL_VERSION)-1.
  • для выходной строки, сохраняя указатель на фактическую позицию для записи
  • для записи текущей строкив эту позицию и обновите указатель с известной длиной написанной вами строки

Это гарантирует, что вы касаетесь всех этих константных строк ровно один раз для каждого символа, который вы копируете.

...