将Opus与PortAudio一起使用

时间:2013-12-20 17:30:00

标签: c++ c portaudio opus

我在使用带端口音频的opus时遇到了麻烦。 我需要使用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); }

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

1 个答案:

答案 0 :(得分:0)

  

#define PA_SAMPLE_TYPE paInt24

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

我建议您正确获取所有样本缓冲区的类型。对格式化的样本数据使用unsigned char *会遇到麻烦。您需要了解PortAudio函数和OPUS编解码器函数所期望的数据类型。