<commit_before>/*
 * iemrtp: RTP support for Pd (common functionality)
 *
 * (c) 2013 <NAME>, institute of electronic music and acoustics (iem)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include "iemrtp.h"
#include <string.h>

STATIC_INLINE u_int32 iemrtp_rtpheadersize(t_rtpheader*rtpheader) {
  return rtpheader?(12 + 4*rtpheader->cc):12;
}

u_int32 iemrtp_rtpheader2atoms(t_rtpheader*rtpheader, t_atom*ap0) {
  t_atom*ap=ap0;
  u_int8 b;
  u_int32 c, cc=rtpheader->cc;
  b=(rtpheader->version << 6) | (rtpheader->p << 5) | (rtpheader->x << 4) | (rtpheader->cc << 0);
  ap++->a_w.w_float=b;

  b=(rtpheader->m << 7) | (rtpheader->pt << 0);
  ap++->a_w.w_float=b;

  ap+=atombytes_setU16(rtpheader->seq, ap);
  ap+=atombytes_setU32(rtpheader->ts , ap);
  ap+=atombytes_setU32(rtpheader->ssrc,ap);
  for(c=0; c < cc; c++) {
    ap+=atombytes_setU32(rtpheader->csrc[c], ap);
  }
  return (12+cc*4);
}


void iemrtp_rtpheader_freemembers(t_rtpheader*rtpheader) {
 if(rtpheader->csrc)free(rtpheader->csrc);
 rtpheader->csrc=NULL;
 rtpheader->cc=0;
}
int iemrtp_rtpheader_ensureCSRC(t_rtpheader*rtpheader, int size) {
  u_int32*csrc = NULL;
  int i;
  if(size>0x0F || size < 0)return 0; /* invalid size */
  if(size<=rtpheader->cc  )return size; /* already large enough */
  csrc = calloc(size, sizeof(u_int32));
  if(!csrc)return 0;

  for(i=0; i<rtpheader->cc; i++) {
    csrc[i]=rtpheader->csrc[i];
  }
  iemrtp_rtpheader_freemembers(rtpheader);
  rtpheader->csrc = csrc;
  rtpheader->cc   = size;
  return rtpheader->cc;
}


int iemrtp_atoms2rtpheader(int argc, t_atom*argv, t_rtpheader*rtpheader) {
  u_int8  b;
  u_int8 cc;
  int retval=12;

  if(!argc) {
    return -retval;
  }

  b=atom_getint(argv+0);
  cc=(b >> 0) & 0x0F;
  retval=12+cc*4;
  if(argc<retval) {
    return -retval;
  }
  iemrtp_rtpheader_freemembers(rtpheader);
  rtpheader->csrc=malloc(cc * sizeof(u_int32));

  rtpheader->version = (b >> 6) & 0x03;
  rtpheader->p       = (b >> 5) & 0x01;
  rtpheader->x       = (b >> 4) & 0x01;
  rtpheader->cc      = cc;

  b=atom_getint(argv+1);
  rtpheader->m       = (b >> 7) & 0x01;
  rtpheader->pt      = (b >> 0) & 0x7F;

  rtpheader->seq  =atombytes_getU16(argv+2);
  rtpheader->ts   =atombytes_getU32(argv+4);
  rtpheader->ssrc =atombytes_getU32(argv+8);

  for(b=0; b<cc; b++) {
    rtpheader->csrc[b]=atombytes_getU32(argv+12+4*b);
  }
  return retval;
}

/* ======================================================== */


void iemrtp_rtcp_freemembers(rtcp_t*x) {
  switch(x->common.pt) {
  case(RTCP_SR  ):
    if(x->r.sr.rr)freebytes(x->r.sr.rr, x->r.sr.rr_count*sizeof(rtcp_rr_t));
    x->r.sr.rr=NULL;  x->r.sr.rr_count=0;
    break;
  case(RTCP_RR  ):
    if(x->r.rr.rr)freebytes(x->r.rr.rr, x->r.rr.rr_count*sizeof(rtcp_rr_t));
    x->r.rr.rr=NULL;  x->r.rr.rr_count=0;
    break;
  case(RTCP_SDES):
    if(x->r.sdes.item) {
      u_int32 i;
      for(i=0; i<x->r.sdes.item_count; i++) {
        rtcp_sdes_item_t*item=x->r.sdes.item+i;
        free(item->data);
        item->data=NULL; item->length=0; item->type=0;
      }
      freebytes(x->r.sdes.item, x->r.sdes.item_count*sizeof(rtcp_sdes_item_t));
    }
    x->r.sdes.item=NULL; x->r.sdes.item_count=0;
    break;
  case(RTCP_BYE ):
    if(x->r.bye.src)freebytes(x->r.bye.src, x->r.bye.src_count*sizeof(u_int32));
    x->r.bye.src=NULL;  x->r.bye.src_count=0;
    break;
  case(RTCP_APP ):
    if(x->r.sr.rr)freebytes(x->r.sr.rr, x->r.sr.rr_count*sizeof(rtcp_rr_t));
    x->r.sr.rr=NULL;  x->r.sr.rr_count=0;
    break;
  case(RTCP_RTPFB ):
    switch(x->common.count) {
    case RTCP_RTPFB_NACK:
      if(x->r.rtpfb.nack.nack)
        freebytes(x->r.rtpfb.nack.nack,
                  x->r.rtpfb.nack.nack_count*sizeof(rtcp_rtpfb_nack_t));
      x->r.rtpfb.nack.nack=NULL; x->r.rtpfb.nack.nack_count=0;
      break;
    default: break;
    }
    break;
  case(RTCP_PSFB ):
    switch(x->common.count) {
    case RTCP_PSFB_PLI : break;
    case RTCP_PSFB_SLI :
      if(x->r.psfb.psfb.sli.sli)
        freebytes(x->r.psfb.psfb.sli.sli,
                  x->r.psfb.psfb.sli.sli_count*sizeof(rtcp_psfb_sli_t));
      x->r.psfb.psfb.sli.sli=NULL; x->r.psfb.psfb.sli.sli_count=0;
      break;
    case RTCP_PSFB_RPSI:
      if(x->r.psfb.psfb.rpsi.data)
        freebytes(x->r.psfb.psfb.rpsi.data,
                  x->r.psfb.psfb.rpsi.data_count*sizeof(rtcp_psfb_rpsi_t));
      x->r.psfb.psfb.rpsi.data=NULL; x->r.psfb.psfb.rpsi.data_count=0;
    case RTCP_PSFB_AFB : /* ??? */
      error("hmm, how to free PSFB/AFB ???");
    default: break;
    }
  }
}
rtcp_psfb_type_t  iemrtp_rtcp_atom2psfbtype (t_atom ap[1]) {
  if(A_SYMBOL == ap->a_type) {
    t_symbol*s=atom_getsymbol(ap);
    if (SELECTOR_RTCP_RTPFB_NACK==s) { return RTCP_RTPFB_NACK; }
  } else if (A_FLOAT == ap->a_type) {
    int i=atom_getint(ap);
    switch(i) {
    case RTCP_RTPFB_NACK:
      return i;
    default:
      break;<commit_msg>make freemembers for fb subpackets a separate function<commit_after>/*
 * iemrtp: RTP support for Pd (common functionality)
 *
 * (c) 2013 <NAME>, institute of electronic music and acoustics (iem)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#include "iemrtp.h"
#include <string.h>

STATIC_INLINE u_int32 iemrtp_rtpheadersize(t_rtpheader*rtpheader) {
  return rtpheader?(12 + 4*rtpheader->cc):12;
}

u_int32 iemrtp_rtpheader2atoms(t_rtpheader*rtpheader, t_atom*ap0) {
  t_atom*ap=ap0;
  u_int8 b;
  u_int32 c, cc=rtpheader->cc;
  b=(rtpheader->version << 6) | (rtpheader->p << 5) | (rtpheader->x << 4) | (rtpheader->cc << 0);
  ap++->a_w.w_float=b;

  b=(rtpheader->m << 7) | (rtpheader->pt << 0);
  ap++->a_w.w_float=b;

  ap+=atombytes_setU16(rtpheader->seq, ap);
  ap+=atombytes_setU32(rtpheader->ts , ap);
  ap+=atombytes_setU32(rtpheader->ssrc,ap);
  for(c=0; c < cc; c++) {
    ap+=atombytes_setU32(rtpheader->csrc[c], ap);
  }
  return (12+cc*4);
}


void iemrtp_rtpheader_freemembers(t_rtpheader*rtpheader) {
 if(rtpheader->csrc)free(rtpheader->csrc);
 rtpheader->csrc=NULL;
 rtpheader->cc=0;
}
int iemrtp_rtpheader_ensureCSRC(t_rtpheader*rtpheader, int size) {
  u_int32*csrc = NULL;
  int i;
  if(size>0x0F || size < 0)return 0; /* invalid size */
  if(size<=rtpheader->cc  )return size; /* already large enough */
  csrc = calloc(size, sizeof(u_int32));
  if(!csrc)return 0;

  for(i=0; i<rtpheader->cc; i++) {
    csrc[i]=rtpheader->csrc[i];
  }
  iemrtp_rtpheader_freemembers(rtpheader);
  rtpheader->csrc = csrc;
  rtpheader->cc   = size;
  return rtpheader->cc;
}


int iemrtp_atoms2rtpheader(int argc, t_atom*argv, t_rtpheader*rtpheader) {
  u_int8  b;
  u_int8 cc;
  int retval=12;

  if(!argc) {
    return -retval;
  }

  b=atom_getint(argv+0);
  cc=(b >> 0) & 0x0F;
  retval=12+cc*4;
  if(argc<retval) {
    return -retval;
  }
  iemrtp_rtpheader_freemembers(rtpheader);
  rtpheader->csrc=malloc(cc * sizeof(u_int32));

  rtpheader->version = (b >> 6) & 0x03;
  rtpheader->p       = (b >> 5) & 0x01;
  rtpheader->x       = (b >> 4) & 0x01;
  rtpheader->cc      = cc;

  b=atom_getint(argv+1);
  rtpheader->m       = (b >> 7) & 0x01;
  rtpheader->pt      = (b >> 0) & 0x7F;

  rtpheader->seq  =atombytes_getU16(argv+2);
  rtpheader->ts   =atombytes_getU32(argv+4);
  rtpheader->ssrc =atombytes_getU32(argv+8);

  for(b=0; b<cc; b++) {
    rtpheader->csrc[b]=atombytes_getU32(argv+12+4*b);
  }
  return retval;
}

/* ======================================================== */
static void iemrtp_rtcp_rtpfb_freemembers(rtcp_t*x) {
  if(x->common.pt != RTCP_RTPFB)return;
  switch(x->common.count) {
  case RTCP_RTPFB_NACK:
    if(x->r.rtpfb.nack.nack)
      freebytes(x->r.rtpfb.nack.nack,
                x->r.rtpfb.nack.nack_count*sizeof(rtcp_rtpfb_nack_t));
    x->r.rtpfb.nack.nack=NULL; x->r.rtpfb.nack.nack_count=0;
    break;
  default: break;
  }
}
static void iemrtp_rtcp_psfb_freemembers(rtcp_t*x) {
  if(x->common.pt != RTCP_PSFB)return;
  switch(x->common.count) {
  case RTCP_PSFB_PLI : break;
  case RTCP_PSFB_SLI :
    if(x->r.psfb.psfb.sli.sli)
      freebytes(x->r.psfb.psfb.sli.sli,
                x->r.psfb.psfb.sli.sli_count*sizeof(rtcp_psfb_sli_t));
    x->r.psfb.psfb.sli.sli=NULL; x->r.psfb.psfb.sli.sli_count=0;
    break;
  case RTCP_PSFB_RPSI:
    if(x->r.psfb.psfb.rpsi.data)
      freebytes(x->r.psfb.psfb.rpsi.data,
                x->r.psfb.psfb.rpsi.data_count*sizeof(rtcp_psfb_rpsi_t));
    x->r.psfb.psfb.rpsi.data=NULL; x->r.psfb.psfb.rpsi.data_count=0;
  case RTCP_PSFB_AFB : /* ??? */
    error("hmm, how to free PSFB/AFB ???");
  default: break;
  }
}
void iemrtp_rtcp_freemembers(rtcp_t*x) {
  switch(x->common.pt) {
  case(RTCP_SR  ):
    if(x->r.sr.rr)freebytes(x->r.sr.rr, x->r.sr.rr_count*sizeof(rtcp_rr_t));
    x->r.sr.rr=NULL;  x->r.sr.rr_count=0;
    break;
  case(RTCP_RR  ):
    if(x->r.rr.rr)freebytes(x->r.rr.rr, x->r.rr.rr_count*sizeof(rtcp_rr_t));
    x->r.rr.rr=NULL;  x->r.rr.rr_count=0;
    break;
  case(RTCP_SDES):
    if(x->r.sdes.item) {
      u_int32 i;
      for(i=0; i<x->r.sdes.item_count; i++) {
        rtcp_sdes_item_t*item=x->r.sdes.item+i;
        free(item->data);
        item->data=NULL; item->length=0; item->type=0;
      }
      freebytes(x->r.sdes.item, x->r.sdes.item_count*sizeof(rtcp_sdes_item_t));
    }
    x->r.sdes.item=NULL; x->r.sdes.item_count=0;
    break;
  case(RTCP_BYE ):
    if(x->r.bye.src)freebytes(x->r.bye.src, x->r.bye.src_count*sizeof(u_int32));
    x->r.bye.src=NULL;  x->r.bye.src_count=0;
    break;
  case(RTCP_APP ):
    if(x->r.sr.rr)freebytes(x->r.sr.rr, x->r.sr.rr_count*sizeof(rtcp_rr_t));
    x->r.sr.rr=NULL;  x->r.sr.rr_count=0;
    break;
  case(RTCP_RTPFB ):
    iemrtp_rtcp_rtpfb_freemembers(x);
    break;
  case(RTCP_PSFB ):
    iemrtp_rtcp_psfb_freemembers(x);
    break;
  }
}
rtcp_psfb_type_t  iemrtp_rtcp_atom2psfbtype (t_atom ap[1]) {
  if(A_SYMBOL == ap->a_type) {
    t_symbol*s=atom_getsymbol(ap);
    if (SELECTOR_RTCP_RTPFB_NACK==s) { return RTCP_RTPFB_NACK; }
  } else if (A_FLOAT == ap->a_type) {
    int i=atom_getint(ap);
    switch(i) {
    case RTCP_RTPFB_NACK:
      return i;
    default:
      break;
{'fraction_non_alphanumeric': 0.17247401973626758, 'fraction_numerical': 0.020260239280412193, 'mean_word_length': 3.443927046953822, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 209, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4385144', 'n_tokens_mistral': 5179, 'n_tokens_neox': 5025, 'n_words': 797}