www.pudn.com > 使用IP网络聊天的VOIP源码.zip > main.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 #include "defines.h" #include "resource.h" // external functions char init_sockets (void); void close_sockets (void); char init_sound (void); void close_sound (void); DWORD WINAPI sender (LPVOID); DWORD WINAPI receiver (LPVOID); DWORD WINAPI player (LPVOID); BOOL CALLBACK addr_dialog (HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK talk_dialog (HWND, UINT, WPARAM, LPARAM); int queue_size; sound_sec sqq[MAX_QUEUE]; int index_put, index_take; bool dbl; HANDLE heap; // maybe will use this for allocating memory dynamically for the ACM int band; // stupid name bool stereo, use_primary; bool blocks_got[16]; unsigned char total_blocks; char acmbuf[44100]; char output_buffer[4096]; char decomp_buf[44100]; char comped_buf[4096]; CRITICAL_SECTION cs; char my_addr_txt [16], dst_addr_txt [16]; unsigned long my_addr, dst_addr; unsigned short next_send_id, next_receive_id; SOCKET ssin, sout; HACMSTREAM has, hasd; HANDLE hPlay, hRec[10], hTerminate, hData; int segments, lock_size, input_buffer_size, output_buf_size; HANDLE Thread [3]; DWORD id [3]; ACMSTREAMHEADER ahc, ahd; WAVEFORMATEX wfx; MPEG_WFX mwfx; char listen_mode; HWND talker_dlg; void ErrB (char *msg, int x=0, HWND hwnd=0) { char str[128]; if (x) sprintf(str, "%s, code: %X", msg, x); else sprintf(str, "%s", msg); MessageBox(hwnd, str, 0, 0); } void release_vars (void) { DeleteCriticalSection (&cs); CloseHandle (hPlay); CloseHandle (hTerminate); CloseHandle (hData); } char init_vars (void) { hPlay = CreateEvent (0, 0, 0, 0); if (hPlay) { for (int i=0;i<10;i++) hRec[i] = CreateEvent (0, 0, 0, 0); if (hRec[0]&&hRec[1]&&hRec[2]&&hRec[3]&&hRec[4]&&hRec[5]&&hRec[6]&&hRec[7]&&hRec[8]&&hRec[9]) { hTerminate = CreateEvent (0, 1, 0, 0); if (hTerminate) { hData = CreateSemaphore(0, 0, 63, 0); if (hData) { next_receive_id = 0; next_send_id = 1; my_addr = 0; memset (&mwfx, 0, sizeof (MPEG_WFX)); mwfx.wfx.wFormatTag = 85; mwfx.wfx.nChannels = (stereo) ? 2 : 1; mwfx.wfx.nSamplesPerSec = 11025; mwfx.wfx.nAvgBytesPerSec = (band==0) ? 1000 : ((band==1) ? 2000 : 2500); mwfx.wfx.nBlockAlign = 1; mwfx.wfx.wBitsPerSample = 0; mwfx.wfx.cbSize = 12; // only 11025hz; adjust channels for number of channels // for 20kbit: data[6]=4,data[7]=1,data[8]=2, avgbytespersec=2500 // THE 18kbit is not good since it requires 5 packets which is exactly as the 20kbit which is better // for 18kbit: data[6]=0xD4,data[7]=1,data[8]=4,avg=2250 // for 16kbit: data[6]=0x68,avg=2000 // for 8kbit: data[6]=0x34,data[8]=1, avg=1000 mwfx.data[0] = 1; mwfx.data[2] = 2; mwfx.data[10] = 0x71; mwfx.data[11] = 5; switch (band) { case 0: mwfx.data[6] = 0x34; mwfx.data[8] = 1; break; case 1: mwfx.data[6] = 0x68; mwfx.data[8] = 1; break; case 2: mwfx.data[6] = 4; mwfx.data[7] = 1; mwfx.data[8] = 2; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = (stereo) ? 2 : 1; wfx.nSamplesPerSec = 11025; wfx.nAvgBytesPerSec = (stereo) ? 44100 : 22050; wfx.nBlockAlign = (stereo) ? 4 : 2; wfx.wBitsPerSample = 16; wfx.cbSize = 0; InitializeCriticalSection (&cs); index_put = 0; index_take = -1; queue_size = 0; dbl = false; segments = 4; input_buffer_size = (stereo)?44100:22050; lock_size = (stereo)?11024:5512; return (1); } //CloseHandle (hTerminate); } //CloseHandle (hRec); } //CloseHandle (hPlay); } return (0); } char init_threads (void) { Thread[0] = CreateThread (0, 0, sender, 0, 0, &id[0]); if (Thread[0]) { Thread[1] = CreateThread (0, 0, player, 0, CREATE_SUSPENDED, &id[1]); if (Thread[1]) { Thread[2] = CreateThread (0, 0, receiver, 0, CREATE_SUSPENDED, &id[2]); if (Thread[2]) return (1); } } SetEvent (hTerminate); return (0); } void close_threads (void) { SetEvent (hTerminate); ResumeThread (Thread[1]); ResumeThread (Thread[2]); WaitForMultipleObjects (3, Thread, 1, INFINITE); } char init_all (void) { if (init_vars ()) { if (init_sound ()) { if (init_sockets ()) { if (init_threads ()) return (1); } else ErrB ("socket problem"); close_sound (); } else ErrB ("sound problem"); release_vars (); } else ErrB ("varialbe problem"); return (0); } void close_all (void) { close_threads (); close_sound (); close_sockets (); } int WINAPI WinMain (HINSTANCE h1, HINSTANCE h2, LPSTR cmd, int show) { int r; // after much thought, it seems just right to give ourselves a boost // and anyway, we don't waste that much cycles SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); band = 0; r = DialogBox (h1, MAKEINTRESOURCE (IDD_ADDRESS), 0, (DLGPROC) addr_dialog); switch (r) { case 0 : ErrB ("operation canceled"); break; case 1: if (init_all ()) { r = DialogBox (h1, MAKEINTRESOURCE (IDD_TALK), 0, (DLGPROC) talk_dialog); if (r) ErrB ("failed to create dialog box, aborting"); close_all (); } else ErrB ("init failed"); break; case -1 : ErrB ("failed to create first dialog box, aborting"); break; } ExitProcess (0); return (0); }