2017-12-27 2 views
1

저는 자체 C++ API를 사용하여 마이크 배열 시스템에서 원시 오디오를 읽거나 처리하거나 재생하는 C++ 프로젝트 작업을하고 있습니다. QT를 사용하여 소프트웨어를 프로그래밍하고 있습니다.QT C++ QAudioOutput을 사용한 실시간 스트리밍

Real Time Streaming With QAudioOutput (QT)에 대한이 게시물에서 Raw 오디오 데이터가 처리를 위해 약 1000ms (1 초)가 소요되는 함수 호출에서 오는 경우 어떻게해야하는지에 대한 조언을 구하고 싶습니다. 실시간 오디오 재생을 어떻게 계속 유지할 수 있습니까?

QIODevice :: QAudioFormat-> start();에 쓸 때 읽었 기 때문에 처리하는 데 약 1 초가 걸립니다. 버퍼 언더런/오버런을 방지하려면 바이트 단위의 바이트를 사용하는 것이 좋습니다. http://cell0907.blogspot.sg/2012/10/qt-audio-output.html

QByteArray 및 QDataStream을 설정하여 함수 호출에서 수신 한 데이터를 스트리밍했습니다.

  • API는 마이크로폰 어레이는 32 개 비트 정수 32 개 비트 정수
  • , 24 비트의 해상도, 8 비트 LSB 패딩 제로의 배열을 반환로부터 데이터를 판독 CcmXXX()
  • 이다.
  • 블록 크기 (1024 샘플로 설정) x 마이크 40 개
  • 각 청크는 기록 된 바이트 수가 기간 크기/여유 공간 크기에 거의 도달 할 때까지 약 1 블록을 기록합니다.

테스트 됨 : 내 슬롯을 약 50ms의 알림에 연결하여 한 기간 가치를 기록합니다. 원형 버퍼 스타일의 QByteArray. 읽기/쓰기 부분에 뮤텍스 잠금/잠금 해제를 추가했습니다.

결과 : 실제 오디오 재생시 매우 짧은 스플릿 ms, 많은 지터 및 녹음되지 않은 사운드.

코드 개선 방법에 대한 의견을 보내주십시오.

void MainWindow::slot_writedata(){ 
    QMutex mutex; 
    mutex.lock(); 
    read_frames(); 
    mutex.unlock(); 
} 
:

void MainWindow::init_audio_output(){ 
    m_bytearray.resize(65536); 
    mstream = new QDataStream(&m_bytearray,QIODevice::ReadWrite); 
    mstream->setByteOrder(QDataStream::LittleEndian); 
    audio = new QAudioOutput(m_device,m_format,this); 
    audio->setBufferSize(131072); 
    audio->setNotifyInterval(50); 
    m_audiodevice = audio->start(); 
    connect(audio,SIGNAL(notify()),this,SLOT(slot_writedata())); 
    read_frames(); 
} 

슬롯

QAudioFormat

void MainWindow::init_audio_format(){ 
      m_format.setSampleRate(48000); //(8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000 
      m_format.setByteOrder(QAudioFormat::LittleEndian); 
      m_format.setChannelCount(1); 
      m_format.setCodec("audio/pcm"); 
      m_format.setSampleSize(32); //(8, 16, 24, 32, 48, 64) 
      m_format.setSampleType(QAudioFormat::SignedInt); //(SignedInt, UnSignedInt, Float) 

      m_device = QAudioDeviceInfo::defaultOutputDevice(); 
      QAudioDeviceInfo info(m_device); 
      if (!info.isFormatSupported(m_format)) { 
       qWarning() << "Raw audio format not supported by backend, cannot play audio."; 
       return; 
      } 
} 

초기화하는 오디오 설정 및 QByteArray/데이터 스트림 0

는 프레임을 읽으려면 :

void MainWindow::read_frames(){ 
     qint32* buffer; 
     int frameSize, byteCount=0; 
     DWORD tdFrames, fdFrames; 
     float fvalue = 0; 
     qint32 q32value; 

     frameSize = 40 * mBlockSize; //40 mics 
     buffer = new int[frameSize]; 
     int periodBytes = audio->periodSize(); 
     int freeBytes = audio->bytesFree(); 
     int chunks = qMin(periodBytes/mBlockSize,freeBytes/mBlockSize); 

     CcmStartInput(); 

     while(chunks){ 
      CcmReadFrames(buffer,NULL,frameSize,0,&tdFrames,&fdFrames,NULL,CCM_WAIT); 
      if(tdFrames==0){ 
       break; 
      } 
      int diffBytes = periodBytes - byteCount; 

      if(diffBytes>=(int)sizeof(q32value)*mBlockSize){ 
       for(int x=0;x<mBlockSize;x++){ 
        q32value = (quint32)buffer[x]/256; 
        *mstream << (qint32)fvalue; 
        byteCount+=sizeof(q32value); 
       } 
      } 
      else{ 
       for(int x=0;x<(diffBytes/(int)sizeof(q32value));x++){ 
        q32value = (quint32)buffer[x]/256; 
        *mstream << (qint32) fvalue; 
        byteCount+=sizeof(q32value); 
       } 
      } 
      --chunks; 
     } 
     CcmStopInput(); 
     mPosEnd = mPos + byteCount; 
     write_frames(); 
     mPos += byteCount; 
     if(mPos >= m_bytearray.length()){ 
       mPos = 0; 
       mstream->device()->seek(0); //change mstream pointer back to bytearray start 
     } 
    } 

이 프레임을 작성하려면 : Qt는에

void MainWindow::write_frames() 
{ 
    int len = m_bytearray.length() - mPos; 
    int bytesWritten = mPosEnd - mPos; 

    if(len>=audio->periodSize()){ 
     m_audiodevice->write(m_bytearray.data()+mPos, bytesWritten); 
    } 
    else{ 

     w_data.replace(0,qAbs(len),m_bytearray.data()+mPos); 
     w_data.replace(qAbs(len),audio->periodSize()-abs(len),m_bytearray.data()); 
     m_audiodevice->write(w_data.data(),audio->periodSize()); 
    } 
} 

답변

3

오디오 지원은 실제로는 매우 초보입니다. 목표는 가능한 가장 낮은 구현 및 유지 관리 비용으로 미디어를 재생하는 것입니다. 상황은 윈도우에서 특히 나쁘다. 고대 MME API가 여전히 오디오 재생에 사용된다고 생각한다.

결과적으로 Qt 오디오 API는 실시간과 매우 거리가 멀어 이러한 응용 프로그램에 특히 적합하지 않습니다.portaudio 또는 rtaudio를 사용하는 것이 좋습니다. Qt 스타일의 IO 장치로 포장 할 수도 있습니다. 이를 통해보다 우수한 성능의 플랫폼 오디오 API에 액세스 할 수 있으며 매우 낮은 대기 시간에서도 훨씬 우수한 재생 성능을 얻을 수 있습니다.

+0

예, 물론입니다. Qt에서 관련된 모든 비디오/오디오는 불행히도 초보적입니다. QMediaPlayer조차도 FFmpeg와 같은 무언가를 사용하는 대신 OS의 재생 기능 (!!!)을 사용하여 모든 종류의 문제를 일으 킵니다. 특수 라이브러리 (GUI 용 Qt와 혼합)를 사용하는 것이 더 나을 것입니다. – TheSHEEEP

+0

의견 및 제안에 감사드립니다. 나는 그 도서관을 시험 할 것이다! 건배! – MrS05

+0

안녕하십니까, TheSHEEEP, 다른 API에 대해 더 궁금해합니다. 나는 rtaudio API를 추가하려고 시도했다. http://www.music.mcgill.ca/~gary/rtaudio/에서 파일을 다운로드했습니다. 그런 다음 CMake make 파일을 생성하여 DLL을 생성 한 다음 mingw64 make를 실행하여 rtaudio DLL 또는 lib 파일을 생성하는 파일을 만들어야합니까? – MrS05