jvoipsoundcardoutput.cpp
来自「使用VOIP进行网络传输声音的类库」· C++ 代码 · 共 523 行
CPP
523 行
/* This file is a part of JVOIPLIB, a library designed to facilitate the use of Voice over IP (VoIP). Copyright (C) 2000-2004 Jori Liesenborgs (jori@lumumba.luc.ac.be) This library (JVOIPLIB) is based upon work done for my thesis at the School for Knowledge Technology (Belgium/The Netherlands) The full GNU Library General Public License can be found in the file LICENSE.LGPL which is included in the source code archive. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "jvoipconfig.h"#include "jvoipsoundcardoutput.h"#include "jvoipsounddevice.h"#include "jvoiperrors.h"#include "jvoipsoundcardparams.h"#include "jvoipsounddeviceblock.h"#include <stdio.h>// TODO: for debugging//#include <sys/types.h>//#include <sys/stat.h>//#include <fcntl.h>//#include <stdlib.h>//#include <unistd.h>#include "debugnew.h"#define JVOIPSOUNDCARDOUTPUT_TOTALBUFFERTIME 10000#define JVOIPSOUNDCARDOUTPUT_EXTRABLOCKSIZE 32JVOIPSoundcardOutput::JVOIPSoundcardOutput(JVOIPSession *sess):JVOIPVoiceOutput(sess){ init = false; sounddev = NULL;}JVOIPSoundcardOutput::~JVOIPSoundcardOutput(){ Cleanup();}int JVOIPSoundcardOutput::Init(int sampinterval,int outputsamprate,int outputbytespersample,bool stereo,const JVOIPComponentParams *componentparams){ JVOIPSoundcardParams defparams,*usrparams; int status; if (init) return ERR_JVOIPLIB_GENERAL_COMPONENTALREADYINIT; // Get the soundcard parameters if (componentparams == NULL) usrparams = &defparams; else if ((usrparams = dynamic_cast<JVOIPSoundcardParams *>(const_cast<JVOIPComponentParams *>(componentparams))) == NULL) usrparams = &defparams; multiplyfactor = usrparams->GetMultiplyFactor(); if (multiplyfactor < 1 || multiplyfactor > 256) return ERR_JVOIPLIB_SOUNDCARDIO_ILLEGALMULTIPLYFACTOR; status = JVOIPSoundDevice::OpenDevice(&sounddev,usrparams->GetSoundDeviceName(),false,outputsamprate); if (status < 0) return status; sampleinterval = sampinterval; samprate = outputsamprate; bytespersample = outputbytespersample; needstereo = stereo; sounddev->RequestSamplingRate(samprate); if ((status = InitBuffers()) < 0) { delete sounddev; return status; } InitSampleConverter(); init = true; firsttime = true; // TODO: for debugging!// char tmpname[1024];// strcpy(tmpname,"jvoiplib-raw-output-XXXXXX");// //debugfile = open("/tmp/jvoiplib_output_stream.raw",O_WRONLY | O_CREAT,S_IRUSR|S_IWUSR);// debugfile = mkstemp(tmpname);// printf("Using file %s\n",tmpname); return 0;}int JVOIPSoundcardOutput::Cleanup(){ if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; delete sounddev; ClearBuffers(); init = false; // TODO: for debugging// close(debugfile); return 0;}int JVOIPSoundcardOutput::Play(VoIPFramework::VoiceBlock *vb){ bool playsilence; unsigned char *data; double diff; int numsamp,size; int status; if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; playsilence = false; if ((data = vb->GetSamples(false)) == NULL) playsilence = true; if (vb->IsStereo() != needstereo) playsilence = true; else if (vb->GetBytesPerSample() != bytespersample) playsilence = true; if ((int)vb->GetSampleRate() != samprate) playsilence = true; if (firsttime) { firsttime = false; blockpos = 0; wantedplaytime = 0; playtime = 0; } wantedplaytime += (double)sampleinterval; diff = wantedplaytime-playtime; diff /= 1000.0; // convert to seconds numsamp = (int)(diff*(double)drvsamprate+0.5); size = numsamp*drvstereo*drvbytespersample; playtime += ((double)numsamp)/((double)drvsamprate)*1000.0; if (playsilence) { // Here, we got to deliver samples to the driver, so the endianness // and signedness have to be taken into account if (drvbytespersample == 1) { if (!sounddev->IsSampleSigned()) memset(sampleblocks[blockpos].data,127,size); else memset(sampleblocks[blockpos].data,0,size); } else // two bytes per sample { if (!sounddev->IsSampleSigned()) { if (!sounddev->IsSampleLittleEndian()) // big endian { for (int i = 0 ; i < size ; i += 2) { sampleblocks[blockpos].data[i] = 127; sampleblocks[blockpos].data[i+1] = 255; } } else // little endian { for (int i = 0 ; i < size ; i += 2) { sampleblocks[blockpos].data[i] = 255; sampleblocks[blockpos].data[i+1] = 127; } } } else // signed ! memset(sampleblocks[blockpos].data,0,size); } } else { int actualsize; actualsize = sampconvert.Convert(data,vb->GetNumBytes(),sampleblocks[blockpos].data,size); if (actualsize < size) { if (drvstereo == 1) { if (drvbytespersample == 1) { unsigned char b; b = sampleblocks[blockpos].data[actualsize-1]; for ( ; actualsize < size ; actualsize++) sampleblocks[blockpos].data[actualsize] = b; } else // two bytes per sample { unsigned char b1,b2; b1 = sampleblocks[blockpos].data[actualsize-2]; b2 = sampleblocks[blockpos].data[actualsize-1]; for ( ; actualsize < size ; actualsize += 2) { sampleblocks[blockpos].data[actualsize] = b1; sampleblocks[blockpos].data[actualsize+1] = b2; } } } else // stereo { if (drvbytespersample == 1) { unsigned char b1,b2; b1 = sampleblocks[blockpos].data[actualsize-2]; b2 = sampleblocks[blockpos].data[actualsize-1]; for ( ; actualsize < size ; actualsize += 2) { sampleblocks[blockpos].data[actualsize] = b1; sampleblocks[blockpos].data[actualsize+1] = b2; } } else // two bytes per sample { unsigned char b1,b2,b3,b4; b1 = sampleblocks[blockpos].data[actualsize-4]; b2 = sampleblocks[blockpos].data[actualsize-3]; b3 = sampleblocks[blockpos].data[actualsize-2]; b4 = sampleblocks[blockpos].data[actualsize-1]; for ( ; actualsize < size ; actualsize += 4) { sampleblocks[blockpos].data[actualsize] = b1; sampleblocks[blockpos].data[actualsize+1] = b2; sampleblocks[blockpos].data[actualsize+2] = b3; sampleblocks[blockpos].data[actualsize+3] = b4; } } } } } // TODO: for debugging// write(debugfile,sampleblocks[blockpos].data,size); sampleblocks[blockpos].datalen = size; if ((status = sounddev->AddBuffer(&sampleblocks[blockpos])) < 0) return status; blockpos++; if (blockpos >= numblocks) blockpos = 0; return 0;}void JVOIPSoundcardOutput::ResetDevice(){ if (!init) return; sounddev->Reset(); firsttime = true;}void JVOIPSoundcardOutput::Reset(){ int status; if (!init) return; sounddev->Reset(); firsttime = true; ClearBuffers(); if ((status = InitBuffers()) < 0) { delete sounddev; init = false; std::cerr << "JVOIPSoundcardOutput: couldn't init buffers during Reset, device closed" << std::endl; return; } InitSampleConverter(); }bool JVOIPSoundcardOutput::SupportsSampleInterval(int ival){ return true;}bool JVOIPSoundcardOutput::SupportsOutputSamplingRate(int orate){ return true;}bool JVOIPSoundcardOutput::SupportsOutputBytesPerSample(int outputbytespersample){ return true;}int JVOIPSoundcardOutput::SetSampleInterval(int ival){ int status; if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; if (ival == sampleinterval) return 0; sampleinterval = ival; ResetDevice(); ClearBuffers(); if ((status = InitBuffers()) < 0) { delete sounddev; init = false; return status; } InitSampleConverter(); return 0;}int JVOIPSoundcardOutput::SetOutputSamplingRate(int orate){ int status; if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; if (orate == samprate) return 0; samprate = orate; ResetDevice(); ClearBuffers(); if ((status = InitBuffers()) < 0) { delete sounddev; init = false; return status; } InitSampleConverter(); return 0;}int JVOIPSoundcardOutput::SetOutputBytesPerSample(int outputbytespersample){ int status; if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; if (outputbytespersample == bytespersample) return 0; bytespersample = outputbytespersample; ResetDevice(); ClearBuffers(); if ((status = InitBuffers()) < 0) { delete sounddev; init = false; return status; } InitSampleConverter(); return 0;}int JVOIPSoundcardOutput::SetStereo(bool s){ int status; if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; if (s == needstereo) return 0; needstereo = s; ResetDevice(); ClearBuffers(); if ((status = InitBuffers()) < 0) { delete sounddev; init = false; return status; } InitSampleConverter(); return 0;}int JVOIPSoundcardOutput::GetComponentState(JVOIPComponentState **compstate){ if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; *compstate = NULL; return 0;}int JVOIPSoundcardOutput::SetComponentState(JVOIPComponentState *compstate){ if (!init) return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT; // NOTE: Nothing needs to be done here return 0;}std::string JVOIPSoundcardOutput::GetComponentName(){ return std::string("JVOIPSoundcardOutput");}std::string JVOIPSoundcardOutput::GetComponentDescription(){ return std::string("JVOIPLIB Internal soundcard output module (OSS version)");}std::vector<JVOIPCompParamInfo> *JVOIPSoundcardOutput::GetComponentParameters() throw (JVOIPException){ std::vector<JVOIPCompParamInfo> *paraminfo; paraminfo = new std::vector<JVOIPCompParamInfo>(2); if (paraminfo == NULL) throw JVOIPException(ERR_JVOIPLIB_GENERAL_OUTOFMEM); (*paraminfo)[0].SetParameterName(std::string("Device")); if (sounddev == NULL) (*paraminfo)[0].SetParameterValue(std::string("None")); else (*paraminfo)[0].SetParameterValue(sounddev->GetDeviceName()); char val[256]; sprintf(val,"%d",multiplyfactor); (*paraminfo)[1].SetParameterName(std::string("Multiply Factor")); (*paraminfo)[1].SetParameterValue(std::string(val)); return paraminfo;}void JVOIPSoundcardOutput::InitSampleConverter(){ int srcrate,srcbytespersample,dstrate,dstbytespersample; bool srcstereo,srcsigned,srcLE,dststereo,dstsigned,dstLE; dstrate = sounddev->GetSamplingRate(); dstbytespersample = sounddev->GetBytesPerSample(); dststereo = sounddev->IsStereo(); dstsigned = sounddev->IsSampleSigned(); dstLE = sounddev->IsSampleLittleEndian(); srcrate = samprate; srcbytespersample = bytespersample; srcstereo = needstereo; srcsigned = false; srcLE = false; sampconvert.SetConversionParams(srcrate,srcstereo,srcbytespersample,srcsigned,srcLE, dstrate,dststereo,dstbytespersample,dstsigned,dstLE, multiplyfactor);}int JVOIPSoundcardOutput::InitBuffers(){ int i; // Request the most appropriate sampling rate sounddev->RequestSamplingRate(samprate); // allocate buffers for the sounddevice drvsamprate = sounddev->GetSamplingRate(); drvbytespersample = sounddev->GetBytesPerSample(); drvstereo = (sounddev->IsStereo())?2:1; numblocks = (int)(((double)JVOIPSOUNDCARDOUTPUT_TOTALBUFFERTIME)/((double)sampleinterval)+0.5); blocksize = (int)((((double)drvsamprate*(double)sampleinterval)/1000.0)*(double)drvbytespersample*(double)drvstereo+0.5); blocksize += JVOIPSOUNDCARDOUTPUT_EXTRABLOCKSIZE; sampleblocks = new JVOIPSoundDeviceBlock [numblocks]; if (sampleblocks == NULL) return ERR_JVOIPLIB_GENERAL_OUTOFMEM; for (i = 0 ; i < numblocks ; i++) { sampleblocks[i].data = new unsigned char[blocksize]; if (sampleblocks[i].data == NULL) { for (int j = 0 ; j < i ; j++) delete [] sampleblocks[j].data; delete [] sampleblocks; return ERR_JVOIPLIB_GENERAL_OUTOFMEM; } } return 0;}void JVOIPSoundcardOutput::ClearBuffers(){ for (int i = 0 ; i < numblocks ; i++) delete [] sampleblocks[i].data; delete [] sampleblocks;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?