www.pudn.com > exosip.rar > sound-mac.c


/* 
 * josua - Jack's open sip User Agent 
 * 
 * Copyright (C) 2002,2003   Aymeric Moizard  
 * 
 * This 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, 
 * or (at your option) any later version. 
 * 
 * This 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 dpkg; if not, write to the Free Software 
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */ 
 
#include "jcalls.h" 
 
#ifdef UCL_SUPPORT 
#ifdef __APPLE_CC__ 
 
#include  
 
#define USE_PCM 
 
int fd = -1; 
static int min_size = 0; 
 
void 
sdes_print (struct rtp *session, uint32_t ssrc, rtcp_sdes_type stype) 
{ 
  const char *sdes_type_names[] = { 
    "end", "cname", "name", "email", "telephone", 
    "location", "tool", "note", "priv" 
  }; 
  const uint8_t n = sizeof (sdes_type_names) / sizeof (sdes_type_names[0]); 
 
  if (stype > n) 
    { 
      /* Theoretically impossible */ 
      fprintf (stderr, "boo! invalud sdes field %d\n", stype); 
      return; 
    } 
 
  fprintf (stderr, "SSRC 0x%08x reported SDES type %s - ", ssrc, 
           sdes_type_names[stype]); 
 
  if (stype == RTCP_SDES_PRIV) 
    { 
      /* Requires extra-handling, not important for example */ 
      fprintf (stderr, "don't know how to display.\n"); 
  } else 
    { 
      fprintf (stderr, "%s\n", rtp_get_sdes (session, ssrc, stype)); 
    } 
} 
 
void 
packet_print (struct rtp *session, rtp_packet * p) 
{ 
#ifdef USE_PCM 
  char data_in_dec[1280]; 
#endif 
  fprintf (stderr, "Received data (payload %d timestamp %06d size %d)\n", 
           p->pt, p->ts, p->data_len); 
 
#ifdef USE_PCM 
 
  if (p->pt == 8)               /* A-Law */ 
    alaw_dec (p->data, data_in_dec, p->data_len); 
  if (p->pt == 0)               /* Mu-Law */ 
    mulaw_dec (p->data, data_in_dec, p->data_len); 
 
#if 0 
  write (fd, data_in_dec, p->data_len * 2); 
#endif 
 
#else 
#if 0 
  write (fd, p->data, p->data_len); 
#endif 
  OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, 
                          "received %i data written to the audio driver\n", 
                          p->data_len)); 
#endif 
 
  /*Unless filtering is enabled we are likely to see 
     out packets if sending to a multicast group. */ 
  /* 
     if (p->ssrc == rtp_my_ssrc(session)) { 
     fprintf(stderr, "that I just sent.\n"); 
     } else { 
     fprintf(stderr, "from SSRC 0x%08x\n", p->ssrc);  
     }  
   */ 
} 
 
void 
rtp_event_handler (struct rtp *session, rtp_event * e) 
{ 
  rtp_packet *p; 
  rtcp_sdes_item *r; 
 
  switch (e->type) 
    { 
      case RX_RTP: 
        p = (rtp_packet *) e->data; 
        packet_print (session, p); 
        free (p);               /* xfree() is mandatory to release RTP packet data */ 
        break; 
      case RX_SDES: 
        r = (rtcp_sdes_item *) e->data; 
        sdes_print (session, e->ssrc, r->type); 
        break; 
      case RX_BYE: 
        break; 
      case SOURCE_CREATED: 
        fprintf (stderr, "New source created, SSRC = 0x%08x\n", e->ssrc); 
        break; 
      case SOURCE_DELETED: 
        fprintf (stderr, "Source deleted, SSRC = 0x%08x\n", e->ssrc); 
        break; 
      case RX_SR: 
      case RX_RR: 
      case RX_RR_EMPTY: 
      case RX_RTCP_START: 
      case RX_RTCP_FINISH: 
      case RR_TIMEOUT: 
      case RX_APP: 
        break; 
    } 
  fflush (stdout); 
} 
 
#define MULAW_BYTES	160 
#define MULAW_PAYLOAD	0 
#define ALAW_PAYLOAD	8 
#define MULAW_MS	20 
 
void * 
os_sound_start_thread (void *_ca, int port) 
{ 
  int i; 
  call_t *ca = (call_t *) _ca; 
  struct timeval timeout; 
  uint32_t rtp_ts, round; 
  uint8_t mulaw_buffer[MULAW_BYTES * 16]; 
  int mulaw_buffer_pos; 
 
#ifdef USE_PCM 
  char data_out[MULAW_BYTES * 2 * 16]; 
#endif 
 
  fprintf (stderr, "Sending and listening to "); 
  fprintf (stderr, "%s port %d (local SSRC = 0x%08x)\n", 
           rtp_get_addr (ca->rtp_session), 
           rtp_get_rx_port (ca->rtp_session), rtp_my_ssrc (ca->rtp_session)); 
 
  round = 0; 
  mulaw_buffer_pos = 0; 
 
  while (ca->enable_audio != -1) 
    { 
      struct timeval t_beg; 
      struct timeval t_end; 
      struct timeval interval; 
 
      gettimeofday (&t_beg, NULL); 
 
      round++; 
      /* original line rtp_ts = round * MULAW_MS; */ 
      rtp_ts = round * MULAW_BYTES; 
 
 
#if 0 
      if (mulaw_buffer_pos < MULAW_BYTES * 4) 
        { 
          /* Send control packets */ 
          rtp_send_ctrl (ca->rtp_session, rtp_ts, NULL); 
 
          /* Send data packets */ 
#ifdef USE_PCM 
          i = read (fd, data_out, MULAW_BYTES * 4); 
          if (ca->payload == 8) /* A-Law */ 
            alaw_enc (data_out, mulaw_buffer + mulaw_buffer_pos, i); 
          if (ca->payload == 0) /* Mu-Law */ 
            mulaw_enc (data_out, mulaw_buffer + mulaw_buffer_pos, i); 
          i = i / 2; 
          mulaw_buffer_pos = mulaw_buffer_pos + i; 
#else 
          memset (mulaw_buffer + mulaw_buffer_pos, 0, MULAW_BYTES * 2); 
          i = read (fd, mulaw_buffer + mulaw_buffer_pos, MULAW_BYTES * 2);      /* ?? */ 
          mulaw_buffer_pos = mulaw_buffer_pos + i; 
#endif 
          fprintf (stderr, "reading %i stream from sound card\n", i); 
        } 
 
      if (mulaw_buffer_pos >= MULAW_BYTES) 
        { 
          rtp_send_data (ca->rtp_session, rtp_ts, ca->payload, 
                         0, 0, 0, (char *) mulaw_buffer, MULAW_BYTES, 0, 0, 0); 
          memmove (mulaw_buffer, mulaw_buffer + MULAW_BYTES, MULAW_BYTES * 15); 
          mulaw_buffer_pos = mulaw_buffer_pos - MULAW_BYTES; 
        } 
 
      /* Receive control and data packets */ 
      timeout.tv_sec = 0; 
      timeout.tv_usec = 0; 
      rtp_recv (ca->rtp_session, &timeout, rtp_ts); 
 
      /* State maintenance */ 
      rtp_update (ca->rtp_session); 
 
#endif 
 
      gettimeofday (&t_end, NULL); 
 
      /* make a diff between t_beg and t_end */ 
      interval.tv_sec = t_end.tv_sec - t_beg.tv_sec; 
      interval.tv_usec = t_end.tv_usec - t_beg.tv_usec; 
 
      if (interval.tv_usec < 0) 
        { 
          interval.tv_usec += 1000000L; 
          --interval.tv_sec; 
        } 
      interval.tv_usec = (MULAW_MS * 1000 - interval.tv_usec); 
      if (interval.tv_usec < 0) 
        { 
          interval.tv_usec += 1000000L; 
          --interval.tv_sec; 
        } 
 
      select (0, NULL, NULL, NULL, &interval); 
    } 
  return NULL; 
} 
 
int 
os_sound_init () 
{ 
  return 0; 
} 
 
int 
os_sound_start (call_t * ca, int port) 
{ 
#if 0 
  int p, cond; 
  int bits = 16; 
  int stereo = 0;               /* 0 is mono */ 
  int rate = 8000; 
  int blocksize = 512; 
 
  fd = open (AUDIO_DEVICE, O_RDWR | O_NONBLOCK); 
  if (fd < 0) 
    return -EWOULDBLOCK; 
  fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) & ~O_NONBLOCK); 
 
  ioctl (fd, SNDCTL_DSP_RESET, 0); 
 
  p = bits;                     /* 16 bits */ 
  ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &p); 
 
  p = stereo;                   /* number of channels */ 
  ioctl (fd, SNDCTL_DSP_CHANNELS, &p); 
 
#ifdef USE_PCM 
  p = AFMT_S16_NE;              /* choose LE or BE (endian) */ 
  ioctl (fd, SNDCTL_DSP_SETFMT, &p); 
#else 
  if (ca->payload == 0) 
    p = AFMT_MU_LAW; 
  else if (ca->payload == 8) 
    p = AFMT_A_LAW; 
  else if (ca->payload == 110 || ca->payload == 111) 
    p = AFMT_S16_NE;            /* choose LE or BE (endian) */ 
  ioctl (fd, SNDCTL_DSP_SETFMT, &p); 
#endif 
 
  p = rate;                     /* rate in khz */ 
  ioctl (fd, SNDCTL_DSP_SPEED, &p); 
 
  ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &min_size); 
  if (min_size > blocksize) 
    { 
      cond = 1; 
      p = min_size / blocksize; 
      while (cond) 
        { 
          int i = ioctl (fd, SNDCTL_DSP_SUBDIVIDE, &p); 
 
          /* fprintf(stderr, "SUB_DIVIDE said error=%i,errno=%i\n",i,errno); */ 
          if ((i == 0) || (p == 1)) 
            cond = 0; 
          else 
            p = p / 2; 
        } 
    } 
  ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &min_size); 
  if (min_size > blocksize) 
    { 
      fprintf (stderr, "dsp block size set to %i.", min_size); 
      exit (0); 
  } else 
    { 
      /* no need to access the card with less latency than needed */ 
      min_size = blocksize; 
    } 
 
  fprintf (stderr, "blocksize = %i\n", min_size); 
 
#ifdef SPEEX_SUPPORT 
  { 
    float vbr_qual; 
    int value; 
    int quality; 
 
    ca->speex_enc = speex_encoder_init (&speex_nb_mode);        /* 8kHz */ 
    /* 16kHz speex_enc = speex_encoder_init(&speex_wb_mode);   */ 
    /* 32kHz speex_enc = speex_encoder_init(&speex_uwb_mode);  */ 
    ca->speex_dec = speex_decoder_init (&speex_nb_mode); 
    value = 1; 
    speex_decoder_ctl (ca->speex_dec, SPEEX_SET_ENH, &value); 
    quality = 8;                /* 15kb */ 
    speex_encoder_ctl (ca->speex_enc, SPEEX_SET_QUALITY, &quality); 
    /* ou bien le bit rate: 
       value = 15000; // 15kb 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_BITRATE, &value); 
     */ 
    /* silence suppression (VAD) 
       value = 1; // 15kb 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_VAD, &value); 
       Discontinuous transmission (DTX) 
       value = 1; // 15kb 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_DTX, &value); 
 
       Variable Bit Rate (VBR) 
       value = 1; // 15kb 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_VBR, &value); 
       vbr_qual = 5,0; // between 0 and 10 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_VBR_QUALITY, &vbr_qual); 
 
       Average bit rate: (ABR) 
       value = 15000; // 15kb 
       speex_encoder_ctl(ca->speex_enc, SPEEX_SET_ABR, &value); 
     */ 
    speex_encoder_ctl (ca->speex_enc, SPEEX_GET_FRAME_SIZE, &ca->speex_fsize); 
 
    ca->speex_nb_packet = 1; 
    speex_bits_init (&(ca->speex_bits)); 
    speex_bits_init (&(ca->dec_speex_bits)); 
  } 
#endif 
 
#endif 
 
  ca->rtp_session = rtp_init (ca->remote_sdp_audio_ip, 
                              port, 
                              ca->remote_sdp_audio_port, 
                              16, 64000, rtp_event_handler, NULL); 
 
  if (ca->rtp_session) 
    { 
      const char *username = "jack";    /* should be taken from the SDP */ 
      const char *telephone = "0033-MY-NUMBER"; 
      const char *app_name = "josua"; 
      uint32_t my_ssrc = rtp_my_ssrc (ca->rtp_session); 
 
      /* set local participant info */ 
      rtp_set_sdes (ca->rtp_session, my_ssrc, RTCP_SDES_NAME, 
                    username, strlen (username)); 
      rtp_set_sdes (ca->rtp_session, my_ssrc, RTCP_SDES_PHONE, 
                    telephone, strlen (telephone)); 
      rtp_set_sdes (ca->rtp_session, my_ssrc, RTCP_SDES_TOOL, 
                    app_name, strlen (app_name)); 
 
      /* Filter out local packets if requested */ 
      /* rtp_set_option(ca->rtp_session, RTP_OPT_FILTER_MY_PACKETS, filter_me); */ 
      rtp_set_option (ca->rtp_session, RTP_OPT_WEAK_VALIDATION, TRUE); 
 
      ca->audio_thread = osip_thread_create (20000, os_sound_start_thread, ca); 
  } else 
    { 
      fprintf (stderr, "Could not initialize session for %s port %d\n", 
               ca->remote_sdp_audio_ip, ca->remote_sdp_audio_port); 
    } 
 
  return 0; 
} 
 
void 
os_sound_close (call_t * ca) 
{ 
  osip_thread_join (ca->audio_thread); 
  osip_free (ca->audio_thread); 
  /* Say bye-bye */ 
  rtp_send_bye (ca->rtp_session); 
  rtp_done (ca->rtp_session); 
 
#ifdef SPEEX_SUPPORT 
  speex_bits_destroy (&ca->speex_bits); 
  speex_bits_destroy (&ca->dec_speex_bits); 
  speex_encoder_destroy (&ca->speex_enc); 
  speex_decoder_destroy (&ca->speex_dec); 
#endif 
 
#if 0 
  close (fd);                   /* close the sound card */ 
#endif 
} 
 
#endif 
#endif