2017-10-19 21 views
0

少しのコンテキストを提供します。私は私のC#アプリケーションでカメラからライブオーディオを出力しようとしています。いくつかの研究をした後、それはC++の管理されたdllでそれを行うことはかなり明らかです。ダイナミックオーディオコンテンツを実装して使用するのはかなり簡単であるはずなので、私はXAudio2 APIを選択しました。XAudio2 - ダイナミックバッファを使用した場合のクラッキング出力

したがって、空のバッファを使用して、C++でXAudioデバイスを作成し、C#コード側からオーディオをプッシュすることです。オーディオチャンクは50msごとにプッシュされます。できるだけレイテンシを小さくしたいからです。

// SampleRate = 44100; Channels = 2; BitPerSample = 16; 
var blockAlign = (Channels * BitsPerSample)/8; 
var avgBytesPerSecond = SampleRate * blockAlign; 
var avgBytesPerMillisecond = avgBytesPerSecond/1000; 
var bufferSize = avgBytesPerMillisecond * Time; 
_sampleBuffer = new byte[bufferSize]; 

毎回タイマーが、それは、オーディオバッファのポインタを取得した音声からデータを読み込み、ポインタにコピーしたデータをとPushAudioメソッドを呼び出して実行します。 また、ストップウォッチを使用して、処理に要した時間を確認し、タイマーが処理時間を含むように再度間隔を計算します。

private void PushAudioChunk(object sender, ElapsedEventArgs e) 
{ 
    unsafe 
    { 
     _pushAudioStopWatch.Reset(); 
     _pushAudioStopWatch.Start(); 

     var audioBufferPtr = Output.AudioCapturerBuffer(); 
     FillBuffer(_sampleBuffer); 
     Marshal.Copy(_sampleBuffer, 0, (IntPtr)audioBufferPtr, _sampleBuffer.Length); 

     Output.PushAudio(); 

     _pushTimer.Interval = Time - _pushAudioStopWatch.ElapsedMilliseconds; 
     _pushAudioStopWatch.Stop(); 
     DIX.Log.WriteLine("Push audio took: {0}ms", _pushAudioStopWatch.ElapsedMilliseconds);     
    } 
} 

これはC++パートの実装です。

msdnのドキュメントに関して、私はXAudio2デバイスを作成し、MasterVoiceとSourceVoiceを追加しました。 c#の部分がオーディオデータをプッシュする責任があるので、バッファは最初は空です。

namespace Audio 
{ 
    using namespace System; 

    template <class T> void SafeRelease(T **ppT) 
    { 
     if (*ppT) 
     { 
      (*ppT)->Release(); 
      *ppT = NULL; 
     } 
    } 

    WAVEFORMATEXTENSIBLE wFormat; 

    XAUDIO2_BUFFER buffer = { 0 }; 

    IXAudio2* pXAudio2 = NULL; 
    IXAudio2MasteringVoice* pMasterVoice = NULL; 
    IXAudio2SourceVoice* pSourceVoice = NULL;   

    WaveOut::WaveOut(int bufferSize) 
    { 
     audioBuffer = new Byte[bufferSize]; 

     wFormat.Format.wFormatTag = WAVE_FORMAT_PCM; 
     wFormat.Format.nChannels = 2; 
     wFormat.Format.nSamplesPerSec = 44100; 
     wFormat.Format.wBitsPerSample = 16; 
     wFormat.Format.nBlockAlign = (wFormat.Format.nChannels * wFormat.Format.wBitsPerSample)/8; 
     wFormat.Format.nAvgBytesPerSec = wFormat.Format.nSamplesPerSec * wFormat.Format.nBlockAlign; 
     wFormat.Format.cbSize = 0; 
     wFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 

     HRESULT hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR); 

     if (SUCCEEDED(hr)) 
     { 
      hr = pXAudio2->CreateMasteringVoice(&pMasterVoice); 
     } 

     if (SUCCEEDED(hr)) 
     { 
      hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wFormat, 
       0, XAUDIO2_DEFAULT_FREQ_RATIO, NULL, NULL, NULL); 
     } 

     buffer.pAudioData = (BYTE*)audioBuffer; 
     buffer.AudioBytes = bufferSize; 
     buffer.Flags = 0; 

     if (SUCCEEDED(hr)) 
     { 
      hr = pSourceVoice->Start(0); 
     } 
    } 

    WaveOut::~WaveOut() 
    { 

    } 

    WaveOut^ WaveOut::CreateWaveOut(int bufferSize) 
    { 
     return gcnew WaveOut(bufferSize); 
    } 

    uint8_t* WaveOut::AudioCapturerBuffer() 
    { 
     if (!audioBuffer) 
     { 
      throw gcnew Exception("Audio buffer is not initialized. Did you forget to set up the audio container?"); 
     } 

     return (BYTE*)audioBuffer; 
    } 

    int WaveOut::PushAudio() 
    { 
     HRESULT hr = pSourceVoice->SubmitSourceBuffer(&buffer); 

     if (FAILED(hr)) 
     { 
      return -1; 
     } 

     return 0; 
    } 
} 

私が直面している問題は、出力には常に亀裂があります。私はタイマーの間隔を増やそうとしたり、バッファーサイズを少し増やしたりしました。毎回同じ結果になります。

私は間違っていますか?

更新:

私はXAudioエンジンが通過することができます3つのバッファを作成しました。ひび割れがなくなった。欠落している部分は、同じデータを持つバッファを避けるために、適切な時刻にバッファをc#部分から埋めることです。

void Render(void* param) 
{ 
    std::vector<byte> audioBuffers[BUFFER_COUNT]; 
    size_t currentBuffer = 0; 

    // Get the current state of the source voice 
    while (BackgroundThreadRunning && pSourceVoice) 
    { 
     if (pSourceVoice) 
     { 
      pSourceVoice->GetState(&state); 
     } 

     while (state.BuffersQueued < BUFFER_COUNT) 
     { 
      std::vector<byte> resultData; 
      resultData.resize(DATA_SIZE); 
      CopyMemory(&resultData[0], pAudioBuffer, DATA_SIZE); 

      // Retreive the next buffer to stream from MF Music Streamer 
      audioBuffers[currentBuffer] = resultData; 

      // Submit the new buffer 
      XAUDIO2_BUFFER buf = { 0 }; 
      buf.AudioBytes = static_cast<UINT32>(audioBuffers[currentBuffer].size()); 
      buf.pAudioData = &audioBuffers[currentBuffer][0]; 

      pSourceVoice->SubmitSourceBuffer(&buf); 

      // Advance the buffer index 
      currentBuffer = ++currentBuffer % BUFFER_COUNT; 

      // Get the updated state 
      pSourceVoice->GetState(&state); 
     } 

     Sleep(30); 
    } 
} 
+0

暗いところで野生の刺し傷 - あなたはバッファを無効にしようとしましたか? – BugFinder

+0

こんにちは。いいえ、私はしていません。私はどうしたらいいですか?私は新しいオーディオチャンクを押す前に? – datoml

+0

あなたがそれを定義した後は、各バイトを0 – BugFinder

答えて

1

XAudio2はないは、あなたがSubmitSourceBuffer経由で提出する際に、ソース・データ・バッファをコピーしません。 XAudio2がデータを処理するためにXAudio2が読み出す必要がある時間の間、そのデータ(アプリケーションメモリ内にある)が有効であり、バッファが割り当てられている必要があります。これは余分なコピーを必要としない効率性のために行われますが、再生が完了するまでメモリを使用可能にするというマルチスレッドの負担がかかります。つまり、再生バッファを変更することはできません。

あなたの現在のコードは、再生中にデータを変更すると、ポップアップを引き起こしている同じバッファを再利用するだけです。これを解決するには、2つまたは3つのバッファを回転させる必要があります。 XAudio2ソースボイスには、バッファの再生が終了した時点を判断するためのステータス情報があります。また、バッファが使用されなくなったことを示す明示的なコールバックに登録することもできます。

XAudio2の使用例については、DirectX Tool Kit for Audioおよびclassic XAudio2 samplesを参照してください。

+0

この情報ありがとう!私はこの種の解決策を最後に実行しました。私は上記の質問を更新して、多分何かが間違っているかどうか見てみることができます。 – datoml

関連する問題