www.pudn.com > 使用IP网络聊天的VOIP源码.zip > sound.cpp


/* 
   Talker - A small program which utilizes the Layer-3 codec (ACM) in windows for voice-over-IP 
   Copyright (C) 1999 Dino Klein 
 
   This program 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 of the License, or (at your option) any later version.  
 
   This program 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 this 
   program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
   MA 02139, USA. 
 
   email: dinoklein@hotmail.com 
*/ 
 
 
#define  WIN32_LEAN_AND_MEAN 
 
#include  
#include  
#include  
#include  
#include  
#include "defines.h" 
 
 
void ErrB (char*, int=0, HWND=0); 
 
 
extern bool             stereo, use_primary; 
extern HACMSTREAM       has, hasd; 
extern HANDLE           hPlay, hRec[10]; 
extern ACMSTREAMHEADER  ahc, ahd; 
extern WAVEFORMATEX     wfx; 
extern MPEG_WFX         mwfx; 
extern int              input_buffer_size, segments, output_buf_size; 
 
extern char             decomp_buf[44100]; 
extern char             comped_buf[4096]; 
extern char             acmbuf[44100]; 
extern char             output_buffer[4096]; 
 
 
 
 
 
 
LPDIRECTSOUND lpds; 
LPDIRECTSOUNDBUFFER lpdsb; 
LPDIRECTSOUNDNOTIFY lpdsn; 
 
LPDIRECTSOUNDCAPTURE lpdsc; 
LPDIRECTSOUNDCAPTUREBUFFER lpdscb; 
LPDIRECTSOUNDNOTIFY lpdsnc; 
 
 
 
 
 
 
 
bool zero_output_buffer (void) 
{ 
   HRESULT  hr; 
   LPVOID   pv1, pv2; 
   DWORD    cb1, cb2; 
 
 
   hr = lpdsb->Lock(0, 0, &pv1, &cb1, &pv2, &cb2, DSBLOCK_ENTIREBUFFER); 
   if (hr==DS_OK) 
   { 
      memset(pv1, 0, cb1); 
      if (pv2) memset(pv2, 0, cb2); 
      lpdsb->Unlock(pv1, cb1, pv2, cb2); 
   } 
   return (hr==DS_OK); 
} 
 
 
bool set_capture_events (int segs) 
{ 
   DSBPOSITIONNOTIFY  dsbnn[10]; 
   HRESULT            hr; 
   int                i; 
 
   for (i=0; iSetNotificationPositions(segs, dsbnn); 
   return (hr==DS_OK); 
} 
 
 
 
bool init_primary_buffer (void) 
{ 
   HRESULT  hr; 
   DSBUFFERDESC  dsbd; 
 
 
   dsbd.dwSize = sizeof(dsbd); 
   dsbd.dwFlags = DSBCAPS_STICKYFOCUS|DSBCAPS_PRIMARYBUFFER; 
   dsbd.dwBufferBytes = 0; 
   dsbd.dwReserved = 0; 
   dsbd.lpwfxFormat = 0; 
   hr = lpds->CreateSoundBuffer(&dsbd, &lpdsb, 0); 
   if (hr==DS_OK) 
   { 
      hr = lpdsb->SetFormat(&wfx); 
      if (hr==DS_OK) 
      { 
         DSBCAPS  dsbc; 
 
 
         dsbc.dwSize = sizeof(dsbc); 
         lpdsb->GetCaps(&dsbc); 
         output_buf_size = dsbc.dwBufferBytes; 
         return true; 
      } 
      lpdsb->Release(); 
   } 
   lpdsb = 0; 
   return false; 
} 
 
 
 
bool set_primary_buffer_format (void) 
{ 
   LPDIRECTSOUNDBUFFER  primary; 
   DSBUFFERDESC         dsbd; 
   HRESULT              hr; 
 
 
   dsbd.dwSize = sizeof(dsbd); 
   dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; 
   dsbd.dwBufferBytes = 0; 
   dsbd.dwReserved = 0; 
   dsbd.lpwfxFormat = 0; 
   hr = lpds->CreateSoundBuffer(&dsbd, &primary, 0); 
   if (hr==DS_OK) 
   { 
      hr = primary->SetFormat(&wfx); 
      primary->Release(); 
   } 
   return (hr==DS_OK); 
} 
 
 
bool init_secondary_buffer (void) 
{ 
#define BUFFER_SIZE 20*1024 
   HRESULT  hr; 
   DSBUFFERDESC  dsbd; 
 
 
   if (set_primary_buffer_format()) 
   { 
      dsbd.dwSize = sizeof(dsbd); 
      dsbd.dwFlags = DSBCAPS_GLOBALFOCUS|DSBCAPS_STICKYFOCUS|DSBCAPS_GETCURRENTPOSITION2; 
      dsbd.dwBufferBytes = BUFFER_SIZE; 
      dsbd.dwReserved = 0; 
      dsbd.lpwfxFormat = &wfx; 
      hr = lpds->CreateSoundBuffer(&dsbd, &lpdsb, 0); 
      if (hr==DS_OK) 
      { 
         output_buf_size = BUFFER_SIZE; 
         //zero_output_buffer(); 
 
         DSBCAPS  dsbc; 
 
 
         dsbc.dwSize = sizeof(dsbc); 
         lpdsb->GetCaps(&dsbc); 
         //lpdsb->Play(0, 0, DSBPLAY_LOOPING); 
         return true; 
      } 
   } 
   lpdsb = 0; 
   return false; 
#undef BUFFER_SIZE 
} 
 
 
 
 
bool init_wave_out_ds (HWND hwnd) 
{ 
   HRESULT  hr; 
 
 
   hr = DirectSoundCreate(0, &lpds, 0); 
   if (hr==DS_OK) 
   { 
      ShowWindow(hwnd, SW_SHOW); 
      hr = lpds->SetCooperativeLevel(hwnd, (use_primary)?DSSCL_WRITEPRIMARY:DSSCL_PRIORITY); 
      if (hr==DS_OK) 
      { 
         if (use_primary) 
         if (init_primary_buffer()) return true; 
         else MessageBox(hwnd, "err init using primary buf", 0, 0); 
         else if (init_secondary_buffer()) return true; 
              else MessageBox(hwnd, "err using secondary buffer", 0, 0); 
      } 
      else MessageBox(hwnd, "unable to set cooperative level", 0, 0); 
      lpds->Release(); 
   } 
   else MessageBox(hwnd, "open sound device failed", 0, 0); 
   lpdsb=0; 
   lpds=0; 
   return false; 
} 
 
 
void close_wave_out_ds (void) 
{ 
   if (lpdsb) lpdsb->Release(); 
   if (lpds) lpds->Release(); 
   lpdsb = 0; 
   lpds = 0; 
} 
 
 
 
bool init_wave_in_ds (HWND hwnd) 
{ 
   HRESULT  hr; 
 
 
   hr = DirectSoundCaptureCreate(0, &lpdsc, 0); 
   if (hr==DS_OK) 
   { 
      DSCBUFFERDESC  dsbcd; 
 
 
      dsbcd.dwSize = sizeof(dsbcd); 
      dsbcd.dwFlags = 0; 
      dsbcd.dwBufferBytes = input_buffer_size; 
      dsbcd.dwReserved = 0; 
      dsbcd.lpwfxFormat = &wfx; 
      hr = lpdsc->CreateCaptureBuffer(&dsbcd, &lpdscb, 0); 
      if (hr==DS_OK) 
      { 
         lpdscb->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&lpdsnc); 
         if (hr==S_OK) 
         { 
            if (set_capture_events(segments)) return true; 
            else ErrB("err setting points", hr, hwnd); 
            lpdsnc->Release(); 
         } 
         else ErrB("query notify", hr, hwnd); 
         lpdscb->Release(); 
      } 
      else ErrB("capture buffer", hr, hwnd); 
      lpdsc->Release(); 
   } 
   else ErrB("capture device", hr, hwnd); 
 
   lpdsnc = 0; 
   lpdscb = 0; 
   lpdsc = 0;    
   return false; 
} 
 
 
void close_wave_in_ds (void) 
{ 
   if (lpdscb) 
   { 
      lpdscb->Stop(); 
      lpdscb->Release(); 
   } 
   if (lpdsnc) lpdsnc->Release(); 
   if (lpdsc) lpdsc->Release(); 
 
   lpdscb = 0; 
   lpdsnc = 0; 
   lpdsc = 0; 
} 
 
 
char init_acm_stream (void) 
{ 
   long  r; 
 
 
   r = acmStreamOpen (&has, NULL, &wfx, &mwfx.wfx, 0, 0, 0, 0); 
   if (!r) 
   { 
 
      memset (&ahc, 0, sizeof (ACMSTREAMHEADER)); 
      ahc.cbStruct = sizeof (ACMSTREAMHEADER); 
      ahc.pbSrc = (BYTE *) acmbuf; 
      ahc.cbSrcLength = 44100; 
      ahc.pbDst = (BYTE *) output_buffer; 
      ahc.cbDstLength = 4096; 
      r = acmStreamPrepareHeader (has, &ahc, 0); 
      if (!r) return 1; 
 
      acmStreamClose (has, 0); 
   } 
 
   return (0); 
} 
 
 
void close_acm_stream (void) 
{ 
   ahc.cbSrcLength =  44100; 
   ahc.cbDstLength = 4096; 
   acmStreamUnprepareHeader (has, &ahc, 0); 
   acmStreamClose (has, 0); 
} 
 
 
char init_acm_stream_decomp (void) 
{ 
   long  r; 
 
 
   r = acmStreamOpen (&hasd, NULL, &mwfx.wfx, &wfx, 0, 0, 0, 0); 
   if (!r) 
   { 
 
      memset (&ahd, 0, sizeof (ACMSTREAMHEADER)); 
      ahd.cbStruct = sizeof (ACMSTREAMHEADER); 
      ahd.pbSrc = (BYTE *) comped_buf; 
      ahd.cbSrcLength = 4096; 
      ahd.pbDst = (BYTE *) decomp_buf; 
      ahd.cbDstLength = 44100; 
      r = acmStreamPrepareHeader (hasd, &ahd, 0); 
      if (!r) return 1; 
 
      acmStreamClose (hasd, 0); 
   } 
 
   return (0); 
} 
 
void close_acm_stream_decomp (void) 
{ 
   ahd.cbSrcLength = 4096; 
   ahd.cbDstLength = 44100; 
   acmStreamUnprepareHeader (hasd, &ahd, 0); 
   acmStreamClose (hasd, 0); 
} 
 
 
void close_sound (void) 
{ 
   close_acm_stream_decomp(); 
   close_acm_stream (); 
   close_wave_in_ds (); 
   close_wave_out_ds (); 
} 
 
 
 
char init_sound (void) 
{ 
   if (init_acm_stream_decomp ()) 
   { 
      if (init_acm_stream()) return (1); 
      else ErrB("init acm decomp stream"); 
      close_acm_stream_decomp(); 
   } 
   else ErrB ("error initializing acm stream"); 
   return (0); 
}