2014-10-16 6 views
2

현재 VOIP 애플리케이션을 개발 중입니다. 이를 위해 PortAudio 라이브러리를 사용하여 사운드를 검색 및 재생하고, Opus 라이브러리를 사용하여 사운드 패킷을 인코딩 및 디코딩합니다.Portaudio + Opus : 끔찍한 음질

지금은 성공적으로 PortAudio를 사용했습니다. 내 프로그램은 단순히 수행

  1. 사운드 음질이 절대적으로 좋은

을 재생 마이크

  • 에서 사운드를 가져옵니다.

    이제 사운드 패킷을 인코딩하고 디코딩하려고합니다. 나는 지금 그것을 내 프로그램을 수행하기 위해 EncodeManagerClass 코딩했습니다

    1. 마이크
    2. 인코딩 사운드
    3. 가 디코드는
    4. 다시

    을 플레이에서 사운드를 얻기하지만 이제 음질은 절대적으로 끔찍합니다 (그리고 VOIP 애플리케이션에서는 문제가 많습니다).

    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; 
    
    01 여기
    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; 
    } 
    

    내 주요입니다 : 여기
    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 클래스

    opus 인코더를 opus_encode_ctl (대역폭, 비트 전송률, VBR)으로 구성하려고했으나 전혀 작동하지 않습니다. 음질은 여전히 ​​엿 같습니다.

    나는 SAMPLE_RATE 또는 FRAME_PER_BUFFER을 변경하더라도 음질이 개선되지는 ...

    나는 PortAudio/오푸스 관련된 뭔가를 놓친 적이 있습니까?

  • 답변

    3

    마지막으로 해결책을 찾았습니다.

    문제는 작품에서 그러나 주에서 오지 않는다 ... 여기

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

    , 내 출력 스트림에 지역 변수를 전달합니다. 그러나 출력 스트림은 비동기 적으로 작동합니다. 따라서 압축 된 사운드가 재생되기 전에 변수가 파괴되었습니다.

    포인터를 사용하면 문제를 해결하는 가장 간단한 방법입니다. 필자는 개인적으로 코드를 조금 리팩토링하기로 결정했습니다.