www.pudn.com > exosip.rar > sound-win32.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" 
#include  
 
#ifdef WIN32 
 
 
#include  
#include  
#include  
#include  
 
 
WAVEFORMATEX wfx; 
 
#define MAX_IN_BUFFERS 32 
#define USED_IN_BUFFERS 6 
#define MAX_OUT_BUFFERS 32 
#define USED_OUT_BUFFERS 32 
 
 
unsigned int waveoutDeviceID = WAVE_MAPPER; 
WAVEHDR waveHdrOut[MAX_OUT_BUFFERS]; 
HWAVEOUT hWaveOut; 
char dataBufferOut[MAX_OUT_BUFFERS][3200]; 
 
unsigned int waveinDeviceID = WAVE_MAPPER; 
HWAVEIN hWaveIn; 
WAVEHDR waveHdrIn[MAX_IN_BUFFERS]; 
char dataBufferIn[MAX_IN_BUFFERS][3200]; 
 
call_t *current_call = NULL; 
 
static void CALLBACK 
SpeakerCallback (HWAVEOUT _hWaveOut, UINT uMsg, DWORD dwInstance, 
                 DWORD dwParam1, DWORD dwParam2) 
{ 
  WAVEHDR *wHdr; 
 
  switch (uMsg) 
    { 
      case WOM_OPEN: 
        fprintf (stderr, "SpeakerCallback : WOM_OPEN\n"); 
        break; 
      case WOM_CLOSE: 
        fprintf (stderr, "SpeakerCallback : WOM_CLOSE\n"); 
        break; 
      case WOM_DONE: 
        fprintf (stderr, "SpeakerCallback : WOM_DONE\n"); 
        wHdr = (WAVEHDR *) dwParam1; 
 
        break; 
      default: 
        break; 
    } 
} 
 
 
static void CALLBACK 
WaveInCallback (HWAVEIN hWaveIn, UINT uMsg, DWORD dwInstance, DWORD dwParam1, 
                DWORD dwParam2) 
{ 
  WAVEHDR *wHdr; 
  MMRESULT mr = NOERROR; 
 
  switch (uMsg) 
    { 
      case WIM_OPEN: 
/*	!	fprintf(stderr, "WaveInCallback : WIM_OPEN\n"); */ 
        break; 
      case WIM_CLOSE: 
/*	!	fprintf(stderr, "WaveInCallback : WIM_CLOSE\n"); */ 
        break; 
      case WIM_DATA: 
        wHdr = (WAVEHDR *) dwParam1; 
/* !	fprintf(stderr, "WaveInCallback : WIM_DATA\n"); */ 
        if (current_call == NULL) 
          return; 
        /* fprintf(stderr, received DATA from MIC: %s\n", wHdr->lpData); */ 
/* !		fprintf(stderr, "wHdr->dwBytesRecorded: %i\n", wHdr->dwBytesRecorded); */ 
/* !		fprintf(stderr, "wHdr->dwUser         : %i\n", wHdr->dwUser); */ 
        mr = 
          waveInAddBuffer (hWaveIn, &(waveHdrIn[wHdr->dwUser]), 
                           sizeof (waveHdrIn[wHdr->dwUser])); 
        if (mr != MMSYSERR_NOERROR) 
          { 
/* !			fprintf(stderr, "__call_free: waveInAddBuffer: 0x%i\n", mr); */ 
            /* exit(-1); */ 
        } else 
          { 
            static int timestamp = 0; 
 
            if (current_call) 
              { 
                rtp_session_send_with_ts (current_call->rtp_session, 
                                          wHdr->lpData, wHdr->dwBytesRecorded, 
                                          timestamp); 
                timestamp += wHdr->dwBytesRecorded; 
              } 
          } 
        break; 
      default: 
        break; 
    } 
} 
 
LPGSM610WAVEFORMAT gsmformat; 
 
int g_g723Drivers = 0; 
int g_gsmDrivers = 0; 
 
BOOL CALLBACK 
acmDriverEnumCallback (HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport) 
{ 
  MMRESULT mmr; 
  HACMDRIVER driver; 
  int i; 
 
  ACMDRIVERDETAILS details; 
 
  details.cbStruct = sizeof (ACMDRIVERDETAILS); 
  mmr = acmDriverDetails (hadid, &details, 0); 
 
  mmr = acmDriverOpen (&driver, hadid, 0); 
 
  for (i = 0; i < details.cFormatTags; i++) 
    { 
      ACMFORMATTAGDETAILS fmtDetails; 
 
      ZeroMemory (&fmtDetails, sizeof (fmtDetails)); 
      fmtDetails.cbStruct = sizeof (ACMFORMATTAGDETAILS); 
      fmtDetails.dwFormatTagIndex = i; 
      mmr = acmFormatTagDetails (driver, &fmtDetails, ACM_FORMATTAGDETAILSF_INDEX); 
      if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) 
        { 
          /* fprintf(stderr, "supported codec: %s\n" ,details.szLongName ); */ 
          if (fmtDetails.dwFormatTag == WAVE_FORMAT_MSG723) 
            { 
              g_g723Drivers = /* 1 */ 0; 
/*	!		  fprintf(stderr, "Find Codec  %s\n" ,details.szLongName ); */ 
#if 0 
              fprintf (stderr, "G723 cFormatTags %i\n", details.cFormatTags); 
              fprintf (stderr, "G723 cFilterTags %i\n", details.cFilterTags); 
#endif 
              return -1; 
          } else if (fmtDetails.dwFormatTag == WAVE_FORMAT_GSM610) 
            { 
              g_gsmDrivers = 1; 
/* !			  fprintf(stderr, "Find Codec  %s\n" ,details.szLongName ); */ 
              return -1; 
            } 
      } else 
        { 
/* !		  fprintf(stderr, "Unsupported codec: %s\n" ,details.szLongName ); */ 
        } 
    } 
  mmr = acmDriverClose (driver, 0); 
  return -1; 
} 
 
int 
os_sound_init () 
{ 
  ortp_init (); 
  ortp_scheduler_init (); 
  ortp_set_debug_file ("oRTP", NULL); 
 
  eXosip_sdp_negotiation_remove_audio_payloads (); 
 
  g_g723Drivers = 0; 
  g_gsmDrivers = 0; 
  acmDriverEnum (acmDriverEnumCallback, 0, ACM_DRIVERENUMF_DISABLED); 
 
 
  if (g_g723Drivers == 0) 
    { 
    } 
/* !    fprintf(stderr, "No G723 decoders found!\n" ); */ 
  else 
    { 
#if 0 
      eXosip_sdp_negotiation_add_codec (osip_strdup ("4"), 
                                        NULL, 
                                        osip_strdup ("RTP/AVP"), 
                                        NULL, NULL, NULL, 
                                        NULL, NULL, osip_strdup ("4 G723/8000")); 
#endif 
    } 
 
  if (g_gsmDrivers == 0) 
    { 
      /* !   fprintf(stderr, "No GSM decoders found!\n" ); */ 
  } else 
    { 
      eXosip_sdp_negotiation_add_codec (osip_strdup ("3"), 
                                        NULL, 
                                        osip_strdup ("RTP/AVP"), 
                                        NULL, NULL, NULL, 
                                        NULL, NULL, osip_strdup ("3 GSM/8000")); 
    } 
 
  /* add A-Law & Mu-Law */ 
  eXosip_sdp_negotiation_add_codec (osip_strdup ("0"), 
                                    NULL, 
                                    osip_strdup ("RTP/AVP"), 
                                    NULL, NULL, NULL, 
                                    NULL, NULL, osip_strdup ("0 PCMU/8000")); 
 
  eXosip_sdp_negotiation_add_codec (osip_strdup ("8"), 
                                    NULL, 
                                    osip_strdup ("RTP/AVP"), 
                                    NULL, NULL, NULL, 
                                    NULL, NULL, osip_strdup ("8 PCMA/8000")); 
  return 0; 
} 
 
#if 0 
for (i = 0; i < USED_IN_BUFFERS /* number of frame */ ; i++) 
  { 
    result = 
      waveOutUnprepareHeader (hWaveOut, &(waveHdrIn[i]), sizeof (waveHdrIn[i])); 
    if (result != MMSYSERR_NOERROR) 
      { 
        fprintf (stderr, "__call_free: waveOutUnprepareHeader: 0x%i\n", result); 
      } 
  } 
 
result = waveOutClose (hWaveOut); 
if (result != MMSYSERR_NOERROR) 
  { 
    fprintf (stderr, "__call_free: waveOutClose: 0x%i\n", result); 
  } 
#endif 
 
int 
open_sndcard (int format) 
{ 
  MMRESULT mr = NOERROR; 
 
  switch (format) 
    { 
      case WAVE_FORMAT_MULAW: 
        wfx.wFormatTag = WAVE_FORMAT_MULAW; 
        wfx.cbSize = 0; 
        wfx.nAvgBytesPerSec = 8000; 
        wfx.nBlockAlign = 1; 
        wfx.nChannels = 1; 
        wfx.nSamplesPerSec = 8000; 
        wfx.wBitsPerSample = 8; 
        break; 
      case WAVE_FORMAT_ALAW: 
        wfx.wFormatTag = WAVE_FORMAT_ALAW; 
        wfx.cbSize = 0; 
        wfx.nAvgBytesPerSec = 8000; 
        wfx.nBlockAlign = 1; 
        wfx.nChannels = 1; 
        wfx.nSamplesPerSec = 8000; 
        wfx.wBitsPerSample = 8; 
        break; 
      case WAVE_FORMAT_GSM610: 
        gsmformat = 
          GlobalAlloc (GMEM_MOVEABLE, (UINT) (sizeof (GSM610WAVEFORMAT))); 
        gsmformat = (LPGSM610WAVEFORMAT) GlobalLock (gsmformat); 
 
        gsmformat->wfx.wFormatTag = WAVE_FORMAT_GSM610; 
        gsmformat->wfx.nChannels = 1; 
        gsmformat->wfx.nSamplesPerSec = 8000; 
        gsmformat->wfx.nAvgBytesPerSec = 1625; 
        gsmformat->wfx.nBlockAlign = 65; 
        gsmformat->wfx.wBitsPerSample = 0; 
        gsmformat->wfx.cbSize = 2; 
        gsmformat->wSamplesPerBlock = 320; 
        break; 
      case WAVE_FORMAT_MSG723: 
#if 0 
        g723format = (LPWAVEFORMATEX) LocalAlloc (LPTR, maxFormatSize); 
        g723format->wFormatTag = WAVE_FORMAT_MSG723; 
        g723format->cbSize = 0; 
        g723format->nAvgBytesPerSec = 800; 
        g723format->nBlockAlign = 1; 
        g723format->nChannels = 1; 
        g723format->nSamplesPerSec = 8000; 
        g723format->wBitsPerSample = 8; 
#endif 
        wfx.wFormatTag = WAVE_FORMAT_MSG723; 
        wfx.cbSize = 0; 
        wfx.nAvgBytesPerSec = 800; 
        wfx.nBlockAlign = 1; 
        wfx.nChannels = 1; 
        wfx.nSamplesPerSec = 8000; 
        wfx.wBitsPerSample = 8; 
        break; 
        /* 
           case WAVE_FORMAT_PCM: 
           wfx.wFormatTag = WAVE_FORMAT_PCM; 
           wfx.cbSize = 0; 
           wfx.nAvgBytesPerSec = 16000; 
           wfx.nBlockAlign = 2; 
           wfx.nChannels = 1; 
           wfx.nSamplesPerSec = 8000; 
           wfx.wBitsPerSample = 16; 
           break; 
         */ 
      default: 
        break; 
    } 
 
  if (gsmformat != NULL) 
    mr = 
      waveOutOpen (&hWaveOut, waveoutDeviceID, 
                   (LPWAVEFORMATEX) & (gsmformat->wfx), 
                   (DWORD) 0 /* SpeakerCallback */ , 0 /* arg */ , 
                   CALLBACK_NULL /* CALLBACK_FUNCTION */ ); 
  else 
    mr = 
      waveOutOpen (&hWaveOut, waveoutDeviceID, &wfx, 
                   (DWORD) 0 /* SpeakerCallback */ , 0 /* arg */ , 
                   CALLBACK_NULL /* CALLBACK_FUNCTION */ ); 
  if (mr != NOERROR) 
    { 
/* !		fprintf(stderr, "__call_free: waveOutOpen: 0x%i\n", mr); */ 
      exit (-1); 
      return -1; 
  } else 
    { 
      int i; 
 
      for (i = 0; i < USED_OUT_BUFFERS; i++) 
        { 
          memset (&(waveHdrOut[i]), 0, sizeof (waveHdrOut[i])); 
          waveHdrOut[i].lpData = dataBufferOut[i]; 
          if (format == WAVE_FORMAT_GSM610) 
            waveHdrOut[i].dwBufferLength = 65;  /* frameSize */ 
          else 
            waveHdrOut[i].dwBufferLength = 320; /* frameSize */ 
          waveHdrOut[i].dwFlags = 0; 
          waveHdrOut[i].dwUser = i; 
 
          mr = 
            waveOutPrepareHeader (hWaveOut, &(waveHdrOut[i]), 
                                  sizeof (waveHdrOut[i])); 
          if (mr != MMSYSERR_NOERROR) 
            { 
/* !				fprintf(stderr, "__call_free: waveOutPrepareHeader: 0x%i\n", mr); */ 
              exit (-1); 
          } else 
            { 
            } 
        } 
    } 
 
  if (gsmformat != NULL) 
    mr = 
      waveInOpen (&hWaveIn, waveinDeviceID, 
                  (LPWAVEFORMATEX) & (gsmformat->wfx), (DWORD) WaveInCallback, 
                  0, CALLBACK_FUNCTION); 
  else 
    mr = 
      waveInOpen (&hWaveIn, waveinDeviceID, &wfx, (DWORD) WaveInCallback, 0, 
                  CALLBACK_FUNCTION); 
  if (mr != MMSYSERR_NOERROR) 
    { 
/* !		fprintf(stderr, "__call_free: waveInOpen: 0x%i\n", mr); */ 
      exit (-1); 
      return -1; 
  } else 
    { 
      int i; 
 
      for (i = 0; i < MAX_IN_BUFFERS; i++) 
        { 
          waveHdrIn[i].lpData = dataBufferIn[i]; 
          waveHdrIn[i].dwBufferLength = 320;    /* frameSize */ 
          waveHdrIn[i].dwFlags = 0; 
          waveHdrIn[i].dwUser = i; 
          mr = 
            waveInPrepareHeader (hWaveIn, &(waveHdrIn[i]), sizeof (waveHdrIn[i])); 
          if (mr == MMSYSERR_NOERROR) 
            { 
              mr = 
                waveInAddBuffer (hWaveIn, &(waveHdrIn[i]), sizeof (waveHdrIn[i])); 
              if (mr == MMSYSERR_NOERROR) 
                { 
/* !					fprintf(stderr, "__call_free: waveInAddBuffer: 0x%i\n", mr); */ 
                  /* return -1; */ 
                } 
          } else 
            { 
/* !				fprintf(stderr, "__call_free: waveInPrepareHeader: 0x%i\n", mr); */ 
              exit (-1); 
              return -1; 
            } 
        } 
      mr = waveInStart (hWaveIn); 
      if (mr != MMSYSERR_NOERROR) 
        { 
/* !			fprintf(stderr, "__call_free: waveInStart: 0x%i\n", mr); */ 
          exit (-1); 
          return -1; 
        } 
    } 
  return 0; 
} 
 
void * 
os_sound_start_thread (void *_ca) 
{ 
  int pos_whdr = 0; 
  call_t *ca = (call_t *) _ca; 
  char data_in[3000]; 
  int have_more; 
  int timestamp = 0; 
  int i; 
 
  current_call = ca; 
 
  while (ca->enable_audio != -1) 
    { 
      int length; 
      static int sound_played = 0; 
      static int cpt = 0; 
 
      memset (data_in, 0, 3000); 
      if (ca->payload == 3) 
        length = 260;           /* 280 ?? */ 
      else 
        length = 160; 
 
      i = 
        rtp_session_recv_with_ts (ca->rtp_session, data_in, length, timestamp, 
                                  &have_more); 
      if (i > 0) 
        { 
          MMRESULT mr = NOERROR; 
 
          memset (waveHdrOut[pos_whdr].lpData, 0, length); 
          memcpy (waveHdrOut[pos_whdr].lpData, data_in, i); 
          waveHdrOut[pos_whdr].dwBufferLength = i; 
          mr = 
            waveOutWrite (hWaveOut, &waveHdrOut[pos_whdr], 
                          sizeof (waveHdrOut[pos_whdr])); 
 
          pos_whdr++; 
          if (pos_whdr == USED_OUT_BUFFERS) 
            { 
              pos_whdr = 0;     /* loop over the prepared blocks */ 
            } 
          if (mr != MMSYSERR_NOERROR) 
            switch (mr) 
              { 
                case MMSYSERR_INVALHANDLE: 
                  fprintf (stderr, 
                           "__call_free: waveOutWrite: 0x%i MMSYSERR_INVALHANDLE\n", 
                           mr); 
                  break; 
                case MMSYSERR_NODRIVER: 
                  fprintf (stderr, 
                           "__call_free: waveOutWrite: 0x%i MMSYSERR_NODRIVER\n", 
                           mr); 
                  break; 
                case MMSYSERR_NOMEM: 
                  fprintf (stderr, 
                           "__call_free: waveOutWrite: 0x%i MMSYSERR_NOMEM\n", mr); 
                  break; 
                case WAVERR_UNPREPARED: 
                  fprintf (stderr, 
                           "__call_free: waveOutWrite: 0x%i WAVERR_UNPREPARED\n", 
                           mr); 
                  break; 
                case WAVERR_STILLPLAYING: 
                  fprintf (stderr, 
                           "__call_free: waveOutWrite: 0x%i WAVERR_STILLPLAYING\n", 
                           mr); 
                default: 
                  fprintf (stderr, "__call_free: waveOutWrite: 0x%i\n", mr); 
          } else 
            ++sound_played; 
          fprintf (stderr, "sound played = %i\n", sound_played); 
          fprintf (stderr, "cpt = %i\n", ++cpt); 
        } 
      timestamp += length; 
    } 
  current_call = NULL; 
  return NULL; 
} 
 
int 
os_sound_start (call_t * ca, int port) 
{ 
  int format = WAVE_FORMAT_MULAW; 
  char localip[128]; 
 
  eXosip_guess_localip (AF_INET, localip, 128); 
 
  if (ca->payload == 0) 
    format = WAVE_FORMAT_MULAW; 
  else if (ca->payload == 8) 
    format = WAVE_FORMAT_ALAW; 
  else if (ca->payload == 18) 
    format = WAVE_FORMAT_G729A; 
  else if (ca->payload == 4) 
    format = WAVE_FORMAT_GSM610 /* WAVE_FORMAT_MSG723 */ ; 
  else if (ca->payload == 3) 
    format = WAVE_FORMAT_GSM610; 
  else 
    return -1;                  /* not supported codec?? */ 
 
  if (open_sndcard (format) != 0) 
    return -1; 
 
  ca->rtp_session = rtp_session_new (RTP_SESSION_SENDRECV); 
  rtp_session_set_scheduling_mode (ca->rtp_session, 1); /* yes */ 
  rtp_session_set_blocking_mode (ca->rtp_session, 1); 
 
  rtp_session_set_profile (ca->rtp_session, &av_profile); 
  rtp_session_set_jitter_compensation (ca->rtp_session, 60); 
  rtp_session_set_local_addr (ca->rtp_session, localip, port); 
  rtp_session_set_remote_addr (ca->rtp_session, 
                               ca->remote_sdp_audio_ip, ca->remote_sdp_audio_port); 
  rtp_session_set_payload_type (ca->rtp_session, ca->payload); 
  rtp_session_signal_connect (ca->rtp_session, "telephone-event", 
                              (RtpCallback) rcv_telephone_event, ca); 
 
  /* enter a loop (thread?) to send AUDIO data with 
     rtp_session_send_with_ts(ca->rtp_session, data, data_length, timestamp); 
   */ 
  ca->audio_thread = osip_thread_create (20000, os_sound_start_thread, ca); 
  return 0; 
} 
 
void 
os_sound_close (call_t * ca) 
{ 
  osip_thread_join (ca->audio_thread); 
  osip_free (ca->audio_thread); 
  rtp_session_signal_disconnect_by_callback (ca->rtp_session, 
                                             "telephone-event", 
                                             (RtpCallback) rcv_telephone_event); 
  rtp_session_destroy (ca->rtp_session); 
 
  waveInReset (hWaveIn); 
  waveInClose (hWaveIn); 
  waveOutReset (hWaveOut); 
  waveOutClose (hWaveOut); 
} 
 
#endif