91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++怎么用winapi?socket實現局域網語音通話功能

發布時間:2022-06-20 11:51:13 來源:億速云 閱讀:259 作者:iii 欄目:開發技術

本篇內容主要講解“C++怎么用winapi socket實現局域網語音通話功能”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++怎么用winapi socket實現局域網語音通話功能”吧!

waveIn和WaveOut的Win32API

1.音頻設備的的信息獲取

首先是輸入音頻設備個數的獲取,僅僅通過調用下面的函數就可以了,沒有輸入參數,輸出設備個數獲取的函數調用方式一樣,名稱略有不同。 waveInGetNumDevs(); //獲取輸入音頻設備個數 waveOutGetNumDevs(); //獲取輸出音頻設備個數 然后便是獲取具體的設備信息了,具體調用如下面所示:

	//音頻輸入設備信息的獲取
	tstring sDevText = L"";		//這里用的是unicode的寬字符串的tstring對象
	WAVEINCAPS waveCaps;	//用于獲取設備信息的結構體
	int res = waveInGetDevCaps(dwID, &waveCaps, sizeof(WAVEINCAPS));
	if (res == MMSYSERR_NOERROR)
	{
		sDevText = waveCaps.szPname;	//此處保存的是設備名稱
	}
	//音頻輸出設備信息的獲取,方式和上面類似,只不過函數名稱略有不同
	tstring sDevText = L"";
	WAVEOUTCAPS waveCaps;
	int res = waveOutGetDevCaps(dwID, &waveCaps, sizeof(WAVEOUTCAPS));
	if (res == MMSYSERR_NOERROR)
	{
		sDevText = waveCaps.szPname;
	}

2.音頻設備的初始化

首先是打開音頻設備: waveInOpen函數參數說明: m_hWaveIn 表示的是音頻輸入的設備句柄,參數為該句柄的地址 iWaveInDevID 表示的是音頻輸入設備的ID,ID默認是從0開始的,如果是在不知道音頻ID的話,可以將該參數設置為 WAVE_MAPPER ,即默認選擇。 m_soundFormat 表示的是打開設備的格式,這個就略微復雜一點了,常用的參數有幾個吧: m_soundFormat.wFormatTag = WAVE_FORMAT_PCM; //這個是采樣數據的格式,其他的咱也不懂,就用默認的 PCM 脈沖采樣的格式。 m_soundFormat.nChannels = 1; //通道數 m_soundFormat.nSamplesPerSec = 11025; //采樣率,常用的有11.025 kHz、22.05 kHz和44.1 kHz,其他的不建議設一些不規則的數。 m_soundFormat.nAvgBytesPerSec = 11025; //不懂,和采樣率一般設置為一樣的數 m_soundFormat.wBitsPerSample = 8; //表示的是數據位數,8或者16位 m_soundFormat.cbSize = 0; //一般為0 hWnd 這個是用于接收錄音通知消息的句柄,填做主窗口句柄就行,注意一個類型轉換。 0L 它的名字是 dwInstance,不太懂,沒什么關系其實 CALLBACK_WINDOW 表示的是 dwCallback(也就是hWnd) 是個窗口句柄,指定的是 dwCallback(也就是hWnd) 參數是什么東西。給大家看一下原版的英文解釋,這個有好多種內容,不想看的可以跳過了,看起來挺晦澀的:

fdwOpen: Flags for opening the device. The following values are defined: CALLBACK_EVENT The dwCallback parameter is an event handle. CALLBACK_FUNCTION The dwCallback parameter is a callback procedure address. CALLBACK_NULL No callback mechanism. This is the default setting. CALLBACK_THREAD The dwCallback parameter is a thread identifier. CALLBACK_WINDOW The dwCallback parameter is a window handle. WAVE_FORMAT_DIRECT If this flag is specified, the ACM driver does not perform conversions on the audio data. WAVE_FORMAT_QUERY The function queries the device to determine whether it supports the given format, but it does not open the device. WAVE_MAPPED The uDeviceID parameter specifies a waveform-audio device to be mapped to by the wave mapper.

返回值為 MMSYSERR_NOERROR 表示失敗了,然后這里對返回值做一個判斷。

	HWAVEIN m_hWaveIn;							//音頻輸入的句柄
	//打開錄音設備,采用窗口方式接收音頻消息
	int res = waveInOpen(&m_hWaveIn, iWaveInDevID, &m_soundFormat, (DWORD)hWnd, 0L, CALLBACK_WINDOW);
	if (res != MMSYSERR_NOERROR)
		return false;

輸出設備的打開啊方式類似,此處也不做過多解釋了,大家看一下就差不多能懂了,相信能認認真真看這篇博客的應該都是很棒的人。 (注意:此處的 m_hWaveOut 類型是 HWAVEOUT,和上面的那個不一樣,注意區分哦)

	//======================== 播放 ==========================
	res = waveOutOpen(&m_hWaveOut, iWaveOutDevID, &m_soundFormat, (DWORD)hWnd,
		0L, CALLBACK_WINDOW);
	if (res != MMSYSERR_NOERROR)
		return false;

3.輸入輸出設備緩沖區的準備和添加

老樣子了,先從音頻輸入設備講起: MAX_BUFFER_SIZE 是自己設置的一個宏定義,給大家一個大概的數量大小參考吧,10240 或者 20480 都可以的,這個其實是一個平衡,如果緩沖區過大,那么通話延遲比較高,如果比較少,則通話的連續性質量不高,自己看著試試就行 m_pWaveHdrIn.dwBytesRecorded 表示的是在準備這個緩沖區的時候,里面的初始數據占多少字節,填個 0 就行。 m_pWaveHdrIn.dwFlags 參數有好多內容,有興趣的可以看看下面的參考內容:

方法

提供緩沖區信息的標志。定義了以下值: WHDR_BEGINLOOP 這個緩沖區是循環中的第一個緩沖區。該標志僅用于輸出緩沖區。 WHDR_DONE 由設備驅動程序設置,表示緩沖區已用完,正在將其返回給應用程序。 WHDR_ENDLOOP 這個緩沖區是循環中的最后一個緩沖區。該標志僅用于輸出緩沖區。 WHDR_INQUEUE 由窗口設置,表示緩沖區已排隊等待回放。 WHDR_PREPARED 由窗口設置,表示緩沖區已用波形預預熱器或波形輸出預預熱器功能準備好。

waveInPrepareHeader 函數主要是準備音頻輸入設備的緩沖區(其實翻譯一下看名字大概就能猜出來),大概參數介紹: m_hWaveIn 音頻輸入設備的句柄 m_pWaveHdrIn 緩沖區的地址 sizeof(WAVEHDR) 這個參數么,不用多說了哈哈

下一個函數 waveInAddBuffer 也簡單,不多說了,相信大家的實力。

	char m_cBufferIn[MAX_BUFFER_SIZE];	//這個是實際的緩沖區空間
	WAVEHDR m_pWaveHdrIn;				//這是一個結構體,用于函數調用參數的一個內容
	
	//準備內存塊錄音
	m_pWaveHdrIn.lpData = m_cBufferIn;
	m_pWaveHdrIn.dwBufferLength = MAX_BUFFER_SIZE; 
	m_pWaveHdrIn.dwBytesRecorded = 0;
	m_pWaveHdrIn.dwFlags = 0;
	res = waveInPrepareHeader(m_hWaveIn, &m_pWaveHdrIn, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;
	//增加內存塊
	res = waveInAddBuffer(m_hWaveIn, &m_pWaveHdrIn, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;

音頻輸出設備的緩沖區準備和添加類似,參考下面代碼:

	//準備內存塊播放
	m_pWaveHdrout.lpData = m_cBufferout;
	m_pWaveHdrout.dwBufferLength = MAX_BUFFER_SIZE;
	m_pWaveHdrout.dwBytesRecorded = 0;
	m_pWaveHdrout.dwFlags = 0;
	res = waveOutPrepareHeader(m_hWaveOut, &m_pWaveHdrout, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;
	//指定數據塊到音頻播放緩沖區
	res = waveOutWrite(m_hWaveOut, &m_pWaveHdrout, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;

4.播放和錄音的開始和終止

先寫這幾個比較簡單的操作: 開始錄音:waveInStart(m_hWaveIn); 停止錄音:waveInStop(m_hWaveIn); 停止播放:waveOutReset(m_hWaveOut); 然后播放錄音的操作略微復雜一點,需要把數據放到播放緩沖區,緩沖區的內容會自動播放: m_cBufferout 播放緩沖區的首地址 pData 要播放的聲音數據流首地址 dwDataLen 聲音數據流的長度

memcpy(m_cBufferout, pData, dwDataLen); (函數不唯一啊,這個windows有好多,例如CopyMemory也可以實現這個功能,這里用的是 memcpy 函數)

5.錄音通知消息的獲取和處理

開始錄音后,緩沖區不斷地增加捕獲到的音頻數據,當音頻數據接受滿了之后,就會向前文說的那個窗口句柄的窗口發送通知消息 MM_WIM_DATA ,收到這個消息之后程序就要對這些數據進行處理,處理完畢后最最重要一件事是清空緩沖區,windows并不會自己清理緩沖區內容。 清理緩沖區用到的函數是 waveInUnprepareHeader 這個參數其實差不多,

waveInPrepareHeader函數清理由WaveInPrepareHeader函數執行的準備。該函數必須在設備驅動程序填充緩沖區并將其返回給應用程序后調用。在釋放緩沖區之前,您必須調用此函數。

這個是官方的解釋,感覺這個挺詳細的,放在這里大家看看。清空緩沖區之后,重新準備緩沖區,和上面的操作一樣。

	int res = waveInUnprepareHeader(m_hWaveIn, &m_pWaveHdrIn, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;
		
	//準備內存塊錄音
	m_pWaveHdrIn.lpData = m_cBufferIn;
	m_pWaveHdrIn.dwBufferLength = MAX_BUFFER_SIZE;
	m_pWaveHdrIn.dwFlags = 0;
	res = waveInPrepareHeader(m_hWaveIn, &m_pWaveHdrIn, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;
	//增加內存塊
	res = waveInAddBuffer(m_hWaveIn, &m_pWaveHdrIn, sizeof(WAVEHDR));
	if (res != MMSYSERR_NOERROR)
		return false;

清空輸出緩沖區的函數(程序結束,記得清空緩沖區內容):

int res = waveOutUnprepareHeader(m_hWaveOut, &m_pWaveHdrout[0], sizeof(WAVEHDR));

6.關閉音頻輸入和輸出設備

調用兩個特別簡單的函數實現最終的收尾工作,哦耶!

	if (m_hWaveIn)
	{
		waveInClose(m_hWaveIn);
		m_hWaveIn = NULL;
	}
	if (m_hWaveOut)
	{
		waveOutClose(m_hWaveOut);
		m_hWaveOut = NULL;
	}

通信數據包的設計以及客戶端服務器邏輯

這個怎么說呢,感覺就要從實際出發了,這里簡單的說一下思路吧。

 功能分析: 

1.客戶端登陸ID分配以及其他客戶端的廣播 可以用靜態變量++來為客戶端賦值ID,以此保證每個用戶ID不重復,然后廣播就遍歷所有的客戶端。包括登陸包,反饋包,廣播包。

2.撥打電話提示 這個就是撥打電話請求包和撥打電話的回復包兩個是吧。

3.聲音數據的傳輸 必須指定誰的語音信息發到哪個客戶端,所以語音包必須包含發送用戶的ID和接收用戶的ID。

4.掛斷通知 需要掛斷包對吧。用戶掛斷情況可能是主動掛斷,或者是程序異常關閉,所以掛斷包可以添加一點掛斷信息等等。

到此,相信大家對“C++怎么用winapi socket實現局域網語音通話功能”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿坝| 尼木县| 新余市| 常宁市| 上虞市| 扶余县| 读书| 保靖县| 德令哈市| 西平县| 确山县| 沙湾县| 昌黎县| 延庆县| 榆树市| 龙井市| 万源市| 耒阳市| 旌德县| 虹口区| 区。| 伽师县| 仁寿县| 阿坝县| 上虞市| 临城县| 兰州市| 新兴县| 嘉兴市| 康马县| 泗阳县| 永昌县| 胶南市| 横山县| 济南市| 唐山市| 高密市| 宣威市| 沙湾县| 舟山市| 洛扎县|