📄 acmcodec.cxx
字号:
/* * acmcodec.cxx * * Microsoft Windows Audio Compression Manager codec interface * * Open H323 Library * * Copyright (c) 1999-2000 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Open H323 Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: acmcodec.cxx,v $ * Revision 1.13 2000/06/22 00:25:14 robertj * Fixed problems with G.723.1 packet sizes. * * Revision 1.12 2000/05/10 04:05:33 robertj * Changed capabilities so has a function to get name of codec, instead of relying on PrintOn. * * Revision 1.11 2000/05/02 04:32:26 robertj * Fixed copyright notice comment. * * Revision 1.10 2000/03/21 03:06:48 robertj * Changes to make RTP TX of exact numbers of frames in some codecs. * * Revision 1.9 1999/12/31 00:05:36 robertj * Added Microsoft ACM G.723.1 codec capability. * * Revision 1.8 1999/11/19 08:08:21 robertj * Removed MS G.723.1 codec as cannot be used by other applications. * * Revision 1.7 1999/10/14 12:01:42 robertj * Fixed error in transmit packet size, far too large! * * Revision 1.6 1999/10/08 09:59:02 robertj * Rewrite of capability for sending multiple audio frames * * Revision 1.5 1999/10/08 04:58:37 robertj * Added capability for sending multiple audio frames in single RTP packet * * Revision 1.4 1999/09/23 07:25:12 robertj * Added open audio and video function to connection and started multi-frame codec send functionality. * * Revision 1.3 1999/09/23 07:06:35 robertj * More attempts at accessing G.723.1 codec via ACM * * Revision 1.2 1999/09/22 04:15:50 robertj * Fixed incorrect bandwidth requirement * * Revision 1.1 1999/09/21 14:24:07 robertj * Added Windows ACM support. * */#include <ptlib.h>#include "acmcodec.h"#include "h245.h"#include "rtp.h"struct EnumCallbackParameter{ EnumCallbackParameter(unsigned formatTag = WAVE_FORMAT_UNKNOWN); UINT searchFormatTag; HACMDRIVERID driverId; POrdinalToString codecNames; PWaveFormat waveFormat;};#define new PNEW///////////////////////////////////////////////////////////////////////////////EnumCallbackParameter::EnumCallbackParameter(unsigned formatTag){ searchFormatTag = formatTag; driverId = NULL; DWORD maxWaveFormatSize = 0; acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxWaveFormatSize); if (maxWaveFormatSize < sizeof(WAVEFORMATEX)) maxWaveFormatSize = sizeof(WAVEFORMATEX); // for MS-PCM waveFormat.SetSize(maxWaveFormatSize);}static BOOL GetFormatName(unsigned dwFormatTag, POrdinalToString & codecNames){ if (codecNames.Contains(dwFormatTag)) return TRUE; ACMFORMATTAGDETAILS aftd; memset(&aftd, 0, sizeof(aftd)); aftd.cbStruct = sizeof(aftd); aftd.dwFormatTag = dwFormatTag; MMRESULT result = acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG); if (result != 0) { PTRACE(1, "ACM\tError in ACM format details: error=" << result); return FALSE; } codecNames.SetAt(dwFormatTag, aftd.szFormatTag); return TRUE;}static BOOL CALLBACK FormatEnumCallback(HACMDRIVERID hDriverId, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD /*fdwSupport*/){ EnumCallbackParameter & param = *(EnumCallbackParameter *)dwInstance; if (param.searchFormatTag == 0) { // Are just getting all the format names available. PTRACE(4, "ACM\tEnumerated tag: " << pafd->dwFormatTag << " WAVEFORMAT=" << param.waveFormat); return GetFormatName(pafd->dwFormatTag, param.codecNames); } if (param.searchFormatTag != pafd->dwFormatTag) // Is format we are looking for? return TRUE; GetFormatName(pafd->dwFormatTag, param.codecNames); param.driverId = hDriverId; return FALSE; // Stop searching}static BOOL CALLBACK DriverEnumCallback(HACMDRIVERID hDriverId, DWORD dwInstance, DWORD fdwSupport){ if ((fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) == 0) return TRUE; // Open the driver. HACMDRIVER hDriver = NULL; MMRESULT result = acmDriverOpen(&hDriver, hDriverId, 0); if (result != 0) { PTRACE(1, "ACM\tError opening ACM driver: error=" << result); return FALSE; }#if PTRACING ACMDRIVERDETAILS add; memset(&add, 0, sizeof(add)); add.cbStruct = sizeof(add); result = acmDriverDetails(hDriverId, &add, 0); if (result != 0) { PTRACE(1, "ACM\tError in ACM driver details: error=" << result); return FALSE; } PTRACE(4, "ACM\tEnumerated driver: " << hDriverId << ", \"" << add.szLongName << "\", fdwSupport=0x" << hex << add.fdwSupport << dec << ", cFormatTags=" << add.cFormatTags << ", \"" << add.szFeatures << '"');#endif EnumCallbackParameter & param = *(EnumCallbackParameter *)dwInstance; ACMFORMATDETAILS afd; memset(&afd, 0, sizeof(afd)); afd.cbStruct = sizeof(afd); afd.pwfx = param.waveFormat; afd.pwfx->wFormatTag = (WORD)param.searchFormatTag; afd.cbwfx = param.waveFormat.GetSize(); afd.dwFormatTag = param.searchFormatTag; result = acmFormatEnum(hDriver, &afd, FormatEnumCallback, dwInstance, 0);#if PTRACING if (result != 0) PTRACE(1, "ACM\tError in ACM format enumeration: error=" << result);#endif acmDriverClose(hDriver, 0); return param.driverId == NULL;}///////////////////////////////////////////////////////////////////////////////H323_ACMCapability::H323_ACMCapability(H323EndPoint & endpoint, unsigned tag) : H323NonStandardAudioCapability(256, 256, endpoint, NULL, 0){ formatTag = tag; EnumCallbackParameter param(formatTag); MMRESULT result = acmDriverEnum(DriverEnumCallback, (DWORD)¶m, 0); if (result != 0) { PTRACE(1, "ACM\tError enumerating ACM drivers: error=" << result); return; } if (param.driverId != NULL) formatName = param.codecNames(formatTag); rtpPayloadType = RTP_DataFrame::DynamicBase;}PObject * H323_ACMCapability::Clone() const{ return new H323_ACMCapability(*this);}PString H323_ACMCapability::GetFormatName() const{ return "Windows ACM " + formatName;}H323Codec * H323_ACMCapability::CreateCodec(H323Codec::Direction direction) const{ EnumCallbackParameter param(formatTag); MMRESULT result = acmDriverEnum(DriverEnumCallback, (DWORD)¶m, 0); if (result != 0) { PTRACE(1, "Codec\tCould not find Windows ACM format " << formatTag << ": error=" << result); return NULL; } return new H323_ACMCodec(direction, param.waveFormat, rtpPayloadType);}BOOL H323_ACMCapability::IsValid() const{ return !formatName;}PStringArray H323_ACMCapability::GetCodecNames(){ PStringArray nameArray; EnumCallbackParameter param; MMRESULT result = acmDriverEnum(DriverEnumCallback, (DWORD)¶m, 0); if (result != 0) PTRACE(1, "ACM\tError enumerating ACM drivers: error=" << result); else { PSortedStringList sorted; PINDEX i; for (i = 0; i < param.codecNames.GetSize(); i++) sorted.AppendString(psprintf("%5u: %s", (PINDEX)param.codecNames.GetKeyAt(i), (const char *)param.codecNames.GetDataAt(i))); nameArray.SetSize(sorted.GetSize()); for (i = 0; i < sorted.GetSize(); i++) nameArray[i] = sorted[i]; } return nameArray;}/////////////////////////////////////////////////////////////////////////////H323_ACMG7231Capability::H323_ACMG7231Capability() : H323AudioCapability(8, 3){ maxFrameSize = 24;}PObject * H323_ACMG7231Capability::Clone() const{ return new H323_ACMG7231Capability();}PString H323_ACMG7231Capability::GetFormatName() const{ return "Microsoft ACM G.723.1";}unsigned H323_ACMG7231Capability::GetSubType() const{ return H245_AudioCapability::e_g7231;}H323Codec * H323_ACMG7231Capability::CreateCodec(H323Codec::Direction direction) const{ static const struct { WAVEFORMATEX wf; BYTE extra[10]; } g7231format = { { 66, 1, 8000, 800, 24, 0, 10 }, { 2, 0, 0xce, 0x9a, 0x32, 0xf7, 0xa2, 0xae, 0xde, 0xac } }; PWaveFormat waveFormat; waveFormat.SetFormat(&g7231format, sizeof(g7231format)); return new H323_ACMCodec(direction, waveFormat, RTP_DataFrame::G7231);}BOOL H323_ACMG7231Capability::OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const{ pdu.SetTag(H245_AudioCapability::e_g7231); H245_AudioCapability_g7231 & g7231 = pdu; g7231.m_maxAl_sduAudioFrames = packetSize; g7231.m_silenceSuppression = TRUE; return TRUE;}BOOL H323_ACMG7231Capability::OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize){ if (pdu.GetTag() != H245_AudioCapability::e_g7231) return FALSE; const H245_AudioCapability_g7231 & g7231 = pdu; packetSize = g7231.m_maxAl_sduAudioFrames; return TRUE;}BOOL H323_ACMG7231Capability::IsValid() const{ EnumCallbackParameter param(66); return acmDriverEnum(DriverEnumCallback, (DWORD)¶m, 0) == 0 && param.codecNames.GetSize() > 0;}/////////////////////////////////////////////////////////////////////////////H323_ACMCodec::H323_ACMCodec(Direction dir, const PWaveFormat & fmt, RTP_DataFrame::PayloadTypes rtpType) : H323FramedAudioCodec(dir, 240, fmt->nBlockAlign), waveFormat(fmt){ rtpPayloadType = rtpType; hStream = NULL; PTRACE(3, "Codec\tWindows ACM " << (dir == Encoder ? "en" : "de") << "coder created: wFormatTag=" << waveFormat->wFormatTag);}H323_ACMCodec::~H323_ACMCodec(){ if (hStream != NULL) acmStreamClose(hStream, 0);}BOOL H323_ACMCodec::Open(H323Connection & connection){ PWaveFormat srcFormat, dstFormat; if (direction == Encoder) { srcFormat.SetFormat(1, 8000, 16); dstFormat = waveFormat; } else { srcFormat = waveFormat; dstFormat.SetFormat(1, 8000, 16); } MMRESULT result = acmStreamOpen(&hStream, NULL, // driver srcFormat, // source format dstFormat, // destination format NULL, // no filter NULL, // no callback 0, // instance data (not used) 0); // flags if (result != 0) { PTRACE(1, "Codec\tCould not open Windows ACM stream: error=" << result); return FALSE; } return H323FramedAudioCodec::Open(connection);}static const unsigned G7231PacketSizes[4] = { 24, 20, 4, 1 };BOOL H323_ACMCodec::EncodeFrame(BYTE * buffer, unsigned & length){ if (hStream == NULL) return FALSE; ACMSTREAMHEADER header; memset(&header, 0, sizeof(header)); header.cbStruct = sizeof(header); header.pbSrc = (BYTE *)sampleBuffer.GetPointer(); header.cbSrcLength = samplesPerFrame*2; header.pbDst = buffer; header.cbDstLength = bytesPerFrame; // prep the header MMRESULT result = acmStreamPrepareHeader(hStream, &header, 0); if (result != 0) { PTRACE(1, "Codec\tError in encode acmStreamPrepareHeader: error=" << result); return FALSE; } result = acmStreamConvert(hStream, &header, 0); if (result != 0) { PTRACE(1, "Codec\tError in encode acmStreamConvert: error=" << result); return FALSE; } if (rtpPayloadType != RTP_DataFrame::G7231) length = bytesPerFrame; else length = G7231PacketSizes[buffer[0]&3]; return TRUE;}BOOL H323_ACMCodec::DecodeFrame(const BYTE * buffer, unsigned length, unsigned & written){ if (hStream == NULL) return FALSE; ACMSTREAMHEADER header; memset(&header, 0, sizeof(header)); header.cbStruct = sizeof(header); header.pbSrc = (BYTE *)buffer; if (rtpPayloadType != RTP_DataFrame::G7231) header.cbSrcLength = bytesPerFrame; else header.cbSrcLength = G7231PacketSizes[buffer[0]&3]; if (header.cbSrcLength > length) header.cbSrcLength = length; header.pbDst = (BYTE *)sampleBuffer.GetPointer(); header.cbDstLength = samplesPerFrame*2; // prep the header MMRESULT result = acmStreamPrepareHeader(hStream, &header, 0); if (result != 0) { PTRACE(1, "Codec\tError in decode acmStreamPrepareHeader: error=" << result); return FALSE; } result = acmStreamConvert(hStream, &header, 0); if (result != 0) { PTRACE(1, "Codec\tError in decode acmStreamConvert: error=" << result); return FALSE; } written = header.cbSrcLength; return TRUE;}/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -