将 Opus 与 PortAudio 结合使用

Using Opus with PortAudio

本文关键字:结合 PortAudio Opus      更新时间:2023-10-16

我在将作品与端口音频一起使用时遇到了麻烦。我需要使用 PortAudio 从流中读取数据音频、编码数据、解码数据和写入数据。如果我只是阅读和写作,一切都很好。但是在编码和解码时,我只能听到雪,背景是我的声音。这是我代码的一部分:

I/O 流标头:

#define NUM_CHANNELS    (2)
#define PA_SAMPLE_TYPE  paInt24
#define SAMPLE_RATE  (48000)
#define FRAMES_PER_BUFFER (1024)
#define SAMPLE_SIZE (3)
#define FRAME_SIZE (960)
class                           SoundSystem
{
 private:
  PaStream                      *_stream;
  int                           _readBufferSize;
  PaStreamParameters            _inputParam;
  PaStreamParameters            _outputParam;
  unsigned char                         *_readBuffer;
 public:
  SoundSystem();
  ~SoundSystem();
  // Init Stream                                           
  bool                          initPa();
  bool                          openStream();
  bool                          startStream();
  bool                          initStream();
  // Init params stream                                    
  bool                          initParams() const;
  bool                          initInputParams();
  bool                          initOutputParams();
  bool                          initParams();
  // I/O                                                   
  bool                          writeOnStream(unsigned cha
r *buff);
  bool                          readFromStream();
  // Utils                                                 
  void                          cleanReadBuffer();
  int                           getReadBufferSize() const;
  unsigned char                 *getReadBuffer() const;
};

I/O 流.cpp:

SoundSystem::SoundSystem()
{
  _stream = NULL;
  _readBufferSize = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE;
  _readBuffer= new unsigned char [_readBufferSize];
}
SoundSystem::~SoundSystem()
{
}
bool            SoundSystem::initPa()
{
  if ((Pa_Initialize()) != paNoError)
    return (false);
  return (true);
}
bool            SoundSystem::openStream()
{
  if ((Pa_OpenStream(&_stream, &_inputParam, &_outputParam, SAMPLE_RATE,
                     FRAMES_PER_BUFFER, paClipOff, NULL, NULL)) != paNoError)
    return (false);
  return (true);
}
bool            SoundSystem::startStream()
{
  if ((Pa_StartStream(_stream)) != paNoError)
    return (false);
  return (true);
}
bool            SoundSystem::initStream()
{
  if ((openStream()) == false)
    std::cerr << "can not open stream" << std::endl;
  if ((startStream()) == false)
    std::cerr << "cannot start stream" <<std::endl;
  return (true);
}
bool            SoundSystem::initParams()
{
  if ((initPa()) == false)
    std::cerr << "can not ijnit PA" << std::endl;
  initInputParams();
  initOutputParams();
  return (true);
}
bool            SoundSystem::initInputParams()
{
  if ((_inputParam.device = Pa_GetDefaultInputDevice()) == paNoDevice)
    return (false);
  _inputParam.channelCount = 2;
  _inputParam.sampleFormat = PA_SAMPLE_TYPE;
  _inputParam.suggestedLatency = Pa_GetDeviceInfo(_inputParam.device)->defaultLowInputLatency;
  _inputParam.hostApiSpecificStreamInfo = NULL;
  return (true);
}
bool            SoundSystem::initOutputParams()
{
  if ((_outputParam.device = Pa_GetDefaultInputDevice()) == paNoDevice)
    return (false);
  _outputParam.channelCount = 2;
  _outputParam.sampleFormat = PA_SAMPLE_TYPE;
  _outputParam.suggestedLatency = Pa_GetDeviceInfo(_outputParam.device)->defaultLowInputLatency;
  _outputParam.hostApiSpecificStreamInfo = NULL;
  return (true);
}
bool            SoundSystem::writeOnStream(unsigned char *buff)
{
  if ((Pa_WriteStream(_stream, buff, FRAMES_PER_BUFFER)) != paNoError)
    {
      std::cout << "FAIL WRITE" <<std::endl;
      return (false);
    }
  return (true);
}
bool            SoundSystem::readFromStream()
{
  if ((Pa_ReadStream(_stream, _readBuffer, FRAMES_PER_BUFFER)) != paNoError)
    return (false);
  return (true);
}
void            SoundSystem::cleanReadBuffer()
{
  for (int i = 0; i != _readBufferSize; i++)
    _readBuffer[i] = 0;
}
int             SoundSystem::getReadBufferSize() const
{enter code here
  return (_readBufferSize);
}
unsigned char*          SoundSystem::getReadBuffer() const { return (_readBuffer); }

编码标头:

#define FRAME_SIZE (960)
#define SAMPLE_RATE (48000)
#define CHANNELS (2)
#define APPLICATION OPUS_APPLICATION_VOIP
#define MAX_FRAME_SIZE (6*960)
class                           EncoderSystem
{
 private:
  OpusEncoder                   *_encode;
  OpusDecoder                   *_decode;
  opus_int16                    _in[FRAME_SIZE*CHANNELS];
  opus_int16                    _out[MAX_FRAME_SIZE*CHANNELS];
  int                           _nbBytes;

 public:
  EncoderSystem();
  ~EncoderSystem();
  bool                          encoderCreate();
  bool                          decoderCreate();
  unsigned char*                encode(unsigned char *, int);
  unsigned char*                decode(unsigned char *, int);
  int                           getEncodeLen() const;
};

编码.cpp:

EncoderSystem::EncoderSystem()
{
}
EncoderSystem::~EncoderSystem()
{
}
bool            EncoderSystem::encoderCreate()
{
  int           error;
  if ((_encode = opus_encoder_create(SAMPLE_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &error)) == NU
LL)
    {
      std::cerr << "Can not create encode" <<std::endl;
      return (false);
    }
  return (true);
}
bool            EncoderSystem::decoderCreate()
{
  int           error;
  if ((_decode = opus_decoder_create(SAMPLE_RATE, CHANNELS, &error)) == NULL)
    {
      std::cerr << "Can not create decoder" <<std::endl;
      return (false);
    }
  return (true);
}
unsigned char*          EncoderSystem::encode(unsigned char *data, int size)
{
  unsigned char         *c_bits = new unsigned char [size];
  memcpy(_in, data, size);
  /* Encode the frame. */
  _nbBytes = opus_encode(_encode, _in, FRAME_SIZE, c_bits, size);
  if (_nbBytes<0)
    {
      std::cerr << "cannot decode" << std::endl;
      return NULL;
    }
  return (c_bits);
}
unsigned char*          EncoderSystem::decode(unsigned char *data, int size)
{
  int   frame_size = opus_decode(_decode, data, size, _out,
                                 MAX_FRAME_SIZE * CHANNELS * 2, 0);
  unsigned char         *pcm_bytes = new unsigned char [MAX_FRAME_SIZE * CHANNELS * 2];
  if (frame_size<0)
    {
      std::cerr << "cannot decode" << std::endl;
      return (NULL);
    }
memcpy(pcm_bytes, _out, size);
  return (pcm_bytes);
}
int             EncoderSystem::getEncodeLen() const { return (this->_nbBytes); }

真的需要你,非常感谢你花时间帮助我。

#define PA_SAMPLE_TYPE paInt24

这可能是你的问题。据我所知,标准 OPUS 编解码器采用 16 位整数或 32 位浮点样本。这些对应于 PortAudio 样本类型 paInt16 和 paFloat32。

我建议正确选择所有样品缓冲液的类型。对格式化的示例数据使用无符号字符*会带来麻烦。您需要了解 PortAudio 函数和 OPUS 编解码器函数所需的数据类型。