我目前正在开发VOIP应用程序。为此,我使用PortAudio库检索和播放声音,并使用Opus库对声音数据包进行编码和解码。

现在,我成功地使用了PortAudio。我的程序只是这样做:

  • 从麦克风获取声音
  • 播放声音

  • 音质绝对好。

    我现在正在尝试对声音数据包进行编码和解码。我已经编码了一个EncodeManagerClass来做到这一点,而我的程序现在可以做到:
  • 从麦克风获取声音
  • 编码声音
  • 解码
  • 播放

  • 但是现在,声音质量绝对可怕(在VOIP应用程序中,这显然是个问题)。

    这是我的EncodeManager类:
    class EncodeManager {
    
        // ctor - dtor
        public:
            EncodeManager(void);
            ~EncodeManager(void);
    
        // coplien form
        private:
            EncodeManager(const EncodeManager &) {}
            const EncodeManager &operator=(const EncodeManager &) { return *this; }
    
        // encode - decode
        public:
            Sound::Encoded  encode(const Sound::Decoded &sound);
            Sound::Decoded  decode(const Sound::Encoded &sound);
    
        // attributes
        private:
            OpusEncoder *mEncoder;
            OpusDecoder *mDecoder;
    
    };
    

    这是源文件:
    EncodeManager::EncodeManager(void) {
        int error;
    
        mEncoder = opus_encoder_create(Sound::SAMPLE_RATE, Sound::NB_CHANNELS, OPUS_APPLICATION_VOIP, &error);
        if (error != OPUS_OK)
            throw new SoundException("fail opus_encoder_create");
    
        mDecoder = opus_decoder_create(Sound::SAMPLE_RATE, Sound::NB_CHANNELS, &error);
        if (error != OPUS_OK)
            throw new SoundException("fail opus_decoder_create");
    }
    
    EncodeManager::~EncodeManager(void) {
        if (mEncoder)
            opus_encoder_destroy(mEncoder);
    
        if (mDecoder)
            opus_decoder_destroy(mDecoder);
    }
    
    Sound::Encoded  EncodeManager::encode(const Sound::Decoded &sound) {
        Sound::Encoded encoded;
    
        encoded.buffer = new unsigned char[sound.size];
        encoded.size = opus_encode_float(mEncoder, sound.buffer, Sound::FRAMES_PER_BUFFER, encoded.buffer, sound.size);
    
        if (encoded.size < 0)
            throw new SoundException("fail opus_encode_float");
    
        return encoded;
    }
    
    Sound::Decoded  EncodeManager::decode(const Sound::Encoded &sound) {
        Sound::Decoded decoded;
    
        decoded.buffer = new float[Sound::FRAMES_PER_BUFFER * Sound::NB_CHANNELS];
        decoded.size = opus_decode_float(mDecoder, sound.buffer, sound.size, decoded.buffer, Sound::FRAMES_PER_BUFFER, 0);
    
        if (decoded.size < 0)
            throw new SoundException("fail opus_decode_float");
    
        return decoded;
    }
    

    这是我的主要内容:
    int main(void) {
        SoundInputDevice input;
        SoundOutputDevice output;
        EncodeManager encodeManager;
    
        input.startStream();
        output.startStream();
    
        while (true) {
            Sound::Decoded *sound;
    
            input >> sound;
            if (sound) {
                Sound::Encoded encodedSound = encodeManager.encode(*sound);
                Sound::Decoded decodedSound = encodeManager.decode(encodedSound);
                output << &decodedSound;
            }
        }
    
        return 0;
    }
    

    附加信息:
    const int   SAMPLE_RATE = 48000;
    const int   NB_CHANNELS = 2;
    const int   FRAMES_PER_BUFFER = 480;
    

    我尝试使用opus_encode_ctl(带宽,比特率,VBR)配置opus编码器,但它根本不起作用:声音质量仍然很差。

    即使我更改SAMPLE_RATE或FRAME_PER_BUFFER,声音质量也无法改善...

    我是否错过了有关PortAudio/Opus的东西?

    最佳答案

    我终于找到了解决方案。

    问题不是来自Opus,而是主要...

    if (sound) {
      Sound::Encoded encodedSound = encodeManager.encode(*sound);
      Sound::Decoded decodedSound = encodeManager.decode(encodedSound);
      output << &decodedSound;
     }
    

    在这里,我将一个局部变量传递给我的输出流。但是输出流异步工作:因此在播放打包的声音之前,我的变量已被销毁。

    使用指针是解决问题的最简单方法。我个人决定重构我的代码。

    10-07 19:44
    查看更多