2013-04-17 1 views
0

Я пытаюсь использовать аудиосистему XAudio2 для асинхронного воспроизведения цикла. Он работает, но когда DLL выгружается (код здесь находится внутри DLL, загруженного другой программой), я получаю исключение нарушения доступа в родительском приложении.XAudio2 Нарушение прав доступа при выгрузке

Я заметил, что я не получаю ошибку, пока не добавлю в нее микс, но я не знаю, что я могу с ним делать.

код ниже:

В soundengine.h

#include <Windows.h> 
#include <xaudio2.h> 
#include <fstream> 
#define SAFE_DELETE(p) if(p) {delete p; p = NULL;} 
#define SAFE_DELETE_ARRAY(p) if(p) {delete[] p; p = NULL;} 
#define DXTRACE_ERR(str,hr) DXTrace(__FILE__,(DWORD)__LINE__,hr,str, FALSE) 
using namespace std; 

#define XA2SE_PLAY_LOOP 1 
#define XA2SE_PLAY_STD 0 
#define XA2SE_ERROR_NOTPLAYING -1 
#define XA2SE_ERROR_COULD_NOT_OPEN_FILE -2 
#define XA2SE_ERROR_NOT_WAVE_FILE -3 
#define XA2SE_ERROR_COULD_NOT_SEEK -4 
#define XA2SE_ERROR_COULD_NOT_DESCEND -5 
#define XA2SE_ERROR_COULD_NOT_RESET -6 
#define XA2SE_ERROR_RIFF_ERROR -7 
#define XA2SE_ERROR_SIZE_ERROR -8 
#define XA2SE_ERROR_COULD_NOT_READ -9 
#define XA2SE_ERROR_UNEXPECTED_NULL_VALUE -10 
#define XA2SE_ERROR_COULD_NOT_ASCEND -11 
#define XA2SE_ERROR_COULD_NOT_GET_INFO -12 
#define XA2SE_ERROR_COULD_NOT_ADVANCE -13 
#define XA2SE_ERROR_COULD_NOT_READEND -14 
#define XA2SE_ERROR_COULD_NOT_SET_INFO -15 
#define XA2SE_ERROR_COULD_NOT_CREATE_VOICE -16 
#define XA2SE_COULD_NOT_SUBMIT_BUFFER -17 
#define WAVEFILE_READ 0x001 

class XA2SoundEngine { 
public: 
    IXAudio2MasteringVoice* mv; 
    IXAudio2SourceVoice* sv; 
    IXAudio2* pXA2; 
    XA2SoundEngine(); 
    ~XA2SoundEngine(); 
    BOOL Play(LPWSTR file, int mode); 
}; 

class WaveFile { 
public: 
    WAVEFORMATEX* m_pwfx;  // Pointer to WAVEFORMATEX structure 
    HMMIO m_hmmio;  // MM I/O handle for the WAVE 
    MMCKINFO m_ck;   // Multimedia RIFF chunk 
    MMCKINFO m_ckRiff;  // Use in opening a WAVE file 
    DWORD m_dwSize;  // The size of the wave file 
    MMIOINFO m_mmioinfoOut;  
    BYTE* m_pbData; 
    BYTE* m_pbDataCur; 
    ULONG m_ulDataSize; 
    CHAR* m_pResourceBuffer; 

protected: 
    HRESULT ReadMMIO(); 
    HRESULT WriteMMIO(WAVEFORMATEX* pwfxDest); 

public: 
      WaveFile(); 
      ~WaveFile(); 

    HRESULT Open(LPWSTR strFileName);  
    HRESULT Close(); 

    HRESULT Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead); 
    HRESULT Write(UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote); 

    DWORD GetSize(); 
    HRESULT ResetFile(); 
    WAVEFORMATEX* GetFormat() { 
     return m_pwfx; 
    }; 
}; 

extern XA2SoundEngine* soundengine; 

В soundengine.cpp

#include "soundengine.h" 
struct async_play_params { 
    LPWSTR file;   
    int mode; 
}; 
DWORD _stdcall async_play_routine(void* param); 

XA2SoundEngine::XA2SoundEngine() {  
    HRESULT hr; 
    CoInitializeEx(NULL,COINIT_MULTITHREADED); 
    pXA2 = NULL;  
    sv = NULL; 
    if(FAILED(hr = XAudio2Create(&pXA2))) { 
     MessageBoxW(NULL,L"The TFDi 737 Extreme Sound system failed to initialize the XAudio2 engine.\r\n\r\nError: FAILED(hr = XAudio2Create(&pXA2, flags))",L"TFDi 737XS Sound Error",MB_OK + MB_ICONERROR); 
     return; 
    } 
    if(FAILED(hr = pXA2->CreateMasteringVoice(&mv))) { 
     MessageBoxW(NULL,L"The TFDi 737 Extreme Sound system failed to initialize the XAudio2 mastering voice.\r\n\r\nError: FAILED(hr = pXA2->CreateMasteringVoice(&mv))",L"TFDi 737XS Sound Error",MB_OK + MB_ICONERROR); 
     return; 
    } 
} 

XA2SoundEngine::~XA2SoundEngine() { 
    if(sv) 
     sv->DestroyVoice(); 
    if(mv) 
     mv->DestroyVoice(); 
    if(pXA2) 
     pXA2->Release(); 
    CoUninitialize(); 
} 

BOOL XA2SoundEngine::Play(LPWSTR file, int mode) { 
     HRESULT hr; 
     WaveFile wf; 
     if(FAILED(hr = wf.Open(file))) 
      return XA2SE_ERROR_COULD_NOT_OPEN_FILE; 
     WAVEFORMATEX* pwfx = wf.GetFormat(); 
     DWORD wavesize = wf.GetSize(); 
     BYTE* wavedata = new BYTE[wavesize];  
     if(FAILED(hr = wf.Read(wavedata, wavesize, &wavesize))) 
      return XA2SE_ERROR_COULD_NOT_READ; 
     if(soundengine->sv != NULL) { 
      soundengine->sv->FlushSourceBuffers(); 
      soundengine->sv->DestroyVoice();    

     } 

     if(FAILED(hr = soundengine->pXA2->CreateSourceVoice(&soundengine->sv,pwfx))) { 
      SAFE_DELETE(wavedata); 
      return XA2SE_ERROR_COULD_NOT_CREATE_VOICE; 
     } 


     XAUDIO2_BUFFER buffer = {0}; 
     buffer.pAudioData = wavedata; 
     buffer.Flags = XAUDIO2_END_OF_STREAM; 
     buffer.AudioBytes = wavesize; 
     buffer.LoopBegin = 0; 
     double nos = (double)wavesize/((pwfx->wBitsPerSample * pwfx->nChannels)/pwfx->nSamplesPerSec); 
     buffer.LoopLength = (unsigned int)nos; 


     buffer.LoopLength = 0; 

     buffer.LoopCount = (mode == XA2SE_PLAY_LOOP ? XAUDIO2_LOOP_INFINITE : 0); 

     if(FAILED(hr = soundengine->sv->SubmitSourceBuffer(&buffer))) {      
      SAFE_DELETE_ARRAY(wavedata); 
      return XA2SE_COULD_NOT_SUBMIT_BUFFER; 
     } 

     hr = soundengine->sv->Start(0);  
     //SAFE_DELETE_ARRAY(wavedata); 
    return TRUE; 
} 

WaveFile::WaveFile() { 
    m_pwfx = NULL; 
    m_hmmio = NULL; 
    m_pResourceBuffer = NULL; 
    m_dwSize = 0;  
} 
WaveFile::~WaveFile() { 
    Close(); 
    SAFE_DELETE_ARRAY(m_pwfx); 
} 

HRESULT WaveFile::Open(LPWSTR strFileName) 
{ 
    HRESULT hr; 

    if(strFileName == NULL) 
     return E_INVALIDARG; 
    SAFE_DELETE_ARRAY(m_pwfx); 

    m_hmmio = mmioOpenW(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ); 

    if(NULL == m_hmmio) { 
     return XA2SE_ERROR_COULD_NOT_OPEN_FILE; 
    } 

    if(FAILED(hr = ReadMMIO())) { 
     // ReadMMIO will fail if its an not a wave file 
     mmioClose(m_hmmio, 0); 
     return XA2SE_ERROR_NOT_WAVE_FILE; 
    } 

    if(FAILED(hr = ResetFile())) 
     return XA2SE_ERROR_COULD_NOT_RESET; 

    // After the reset, the size of the wav file is m_ck.cksize so store it now 
    m_dwSize = m_ck.cksize; 

    return hr; 
} 
HRESULT WaveFile::ReadMMIO() 
{ 
    MMCKINFO ckIn;   // chunk info. for general use. 
    PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. 

    memset(&ckIn, 0, sizeof(ckIn)); 

    m_pwfx = NULL; 

    if((0 != mmioDescend(m_hmmio,&m_ckRiff,NULL,0))) 
     return XA2SE_ERROR_COULD_NOT_DESCEND; 

    // Check to make sure this is a valid wave file 
    if((m_ckRiff.ckid != FOURCC_RIFF) || (m_ckRiff.fccType != mmioFOURCC('W','A','V','E'))) 
     return XA2SE_ERROR_RIFF_ERROR; 

    // Search the input file for for the 'fmt ' chunk. 
    ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); 
    if(0 != mmioDescend(m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK)) 
     return XA2SE_ERROR_COULD_NOT_DESCEND; 

    // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; 
    // if there are extra parameters at the end, we'll ignore them 
    if(ckIn.cksize < (LONG)sizeof(PCMWAVEFORMAT)) 
     return XA2SE_ERROR_SIZE_ERROR; 

    // Read the 'fmt ' chunk into <pcmWaveFormat>. 
    if(mmioRead(m_hmmio, (HPSTR)&pcmWaveFormat, 
     sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat)) 
     return XA2SE_ERROR_COULD_NOT_READ; 

    // Allocate the waveformatex, but if its not pcm format, read the next 
    // word, and thats how many extra bytes to allocate. 
    if(pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) 
    { 
     m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ]; 
     if(NULL == m_pwfx) 
      return XA2SE_ERROR_UNEXPECTED_NULL_VALUE; 

     // Copy the bytes from the pcm structure to the waveformatex structure 
     memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat)); 
     m_pwfx->cbSize = 0; 
    } 
    else 
    { 
     // Read in length of extra bytes. 
     WORD cbExtraBytes = 0L; 
     if(mmioRead(m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD)) 
      return XA2SE_ERROR_COULD_NOT_READ; 

     m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ]; 
     if(NULL == m_pwfx) 
      return XA2SE_ERROR_UNEXPECTED_NULL_VALUE; 

     // Copy the bytes from the pcm structure to the waveformatex structure 
     memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat)); 
     m_pwfx->cbSize = cbExtraBytes; 

     // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. 
     if(mmioRead(m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize)) + sizeof(WORD)), 
      cbExtraBytes) != cbExtraBytes) 
     { 
      SAFE_DELETE(m_pwfx); 
      return XA2SE_ERROR_COULD_NOT_READ; 
     } 
    } 

    // Ascend the input file out of the 'fmt ' chunk. 
    if(0 != mmioAscend(m_hmmio, &ckIn, 0)) 
    { 
     SAFE_DELETE(m_pwfx); 
     return XA2SE_ERROR_COULD_NOT_ASCEND; 
    } 

    return S_OK; 
} 

DWORD WaveFile::GetSize() { 
    return m_dwSize; 
} 
HRESULT WaveFile::ResetFile() { 
    if(m_hmmio == NULL) 
     return CO_E_NOTINITIALIZED; 
    // Seek to the data 
    if(-1 == mmioSeek(m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC), 
     SEEK_SET)) 
     return XA2SE_ERROR_COULD_NOT_SEEK; 

    // Search the input file for the 'data' chunk. 
    m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); 
    if(0 != mmioDescend(m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK)) 
     return XA2SE_ERROR_COULD_NOT_DESCEND; 

     return S_OK; 
} 

HRESULT WaveFile::Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead) { 

    MMIOINFO mmioinfoIn; // current status of m_hmmio 

    if(m_hmmio == NULL) 
     return CO_E_NOTINITIALIZED; 
    if(pBuffer == NULL || pdwSizeRead == NULL) 
     return E_INVALIDARG; 

    *pdwSizeRead = 0; 

    if(0 != mmioGetInfo(m_hmmio, &mmioinfoIn, 0)) 
     return XA2SE_ERROR_COULD_NOT_GET_INFO; 

    UINT cbDataIn = dwSizeToRead; 
    if(cbDataIn > m_ck.cksize) 
     cbDataIn = m_ck.cksize; 

    m_ck.cksize -= cbDataIn; 

    for(DWORD cT = 0; cT < cbDataIn; cT++) 
    { 
     // Copy the bytes from the io to the buffer. 
     if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) 
     { 
      if(0 != mmioAdvance(m_hmmio, &mmioinfoIn, MMIO_READ)) 
       return XA2SE_ERROR_COULD_NOT_ADVANCE; 

      if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) 
       return XA2SE_ERROR_COULD_NOT_READEND; 
     } 

     // Actual copy. 
     *((BYTE*)pBuffer + cT) = *((BYTE*)mmioinfoIn.pchNext); 
     mmioinfoIn.pchNext++; 
    } 

    if(0 != mmioSetInfo(m_hmmio, &mmioinfoIn, 0)) 
     return XA2SE_ERROR_COULD_NOT_SET_INFO; 

    *pdwSizeRead = cbDataIn; 

    return S_OK; 

} 

HRESULT WaveFile::Close() { 

    if (m_hmmio != NULL) { 
     mmioClose(m_hmmio, 0); 
     m_hmmio = NULL; 
    } 
    SAFE_DELETE_ARRAY(m_pResourceBuffer); 

    return S_OK; 
} 

ответ

0

я случайно использовать XAudio для определенных вещей, и я проверил мой код , Как ни странно, у меня был комментарий, говорящий о том, чтобы не использовать CoUninitialize(); в самом деструкторе AudioDevice, и я вспомнил, почему:

Вы инициализируете COM CoInitializeEx(NULL, COINIT_MULTITHREADED);. Это означает, что другие приложения (в частности, другие потоки XAudio) работают помимо вашего приложения частично из-под вашего контроля. Когда вы используете CoUninitialize() в деструкторе вашего XA2SoundEngine, этот поток, возможно, не вышел или не завершил очистку своих ресурсов. По сути, вы просите COM сделать некоторые убийства, которые, вероятно, не готовы сделать (это мое лучшее предположение, потому что я все время сам получал нарушения доступа).

Путь, который я установил, был не с CoUninitialize(). Microsoft в новых версиях XAudio2 осознала, насколько глупо было говорить вам, когда нити, которые он использовал, порождались или умирали, и поэтому XAudio2 (2.8, я считаю, в Windows 8) сделал для вас CoInitializeEx и CoUninitialize. Если вы находитесь в этом env, вы не должны называть эти методы в первую очередь.

Если это происходит в DLL, вы можете безопасно позвонить в CoUninitialize и CoInitializeEx, когда ваша DLL присоединяется. Он будет работать без ошибок:

BOOL APIENTRY DllMain (HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { 

    switch (dwReason) { 

    case DLL_PROCESS_ATTACH: 
     CoInitializeEx(NULL, COINIT_MULTITHREADED); 
     break; 
    case DLL_THREAD_ATTACH: 
     CoInitializeEx(NULL, COINIT_MULTITHREADED); 
     break; 
    case DLL_THREAD_DETACH: 
     CoUninitialize(); 
     break; 
    case DLL_PROCESS_DETACH: 
     CoUninitialize(); 
     break; 
    default: 
     // Wat... 
     break; 
    } 

    return TRUE; 

} 

Возможно COM эксперт может сказать мне, если я делаю это неправильно, но до сих пор выше работает для меня.

Удачи вам!

+0

Я реализовал ваше решение, однако, у меня все еще такая же авария. DLL загружается Flight Simulator X, и кажется, что sim что-то делает с этим. Я тестировал библиотеку вне среды симулятора полета, и ничего плохого не было. –

+0

Я добавил проверку, которая гарантирует, что функция CoUninitialize не может быть нажата до тех пор, пока деструктор не будет вызван, и он никогда не дошел до него. Кажется, что он висит где-то в конце и никогда не может ударить деструктора или закончить работу, следовательно, ошибка. –

+0

@CollinBiedenkapp Не знаете, почему деструктор никогда не попадает. Вам придется отлаживать это для вашего Flight Simulator.В целом, деструктор должен всегда вызываться до того, как DLL будет выгружена (вот как это должно работать), поэтому, возможно, вы не удаляете объект в первую очередь. Постарайтесь тщательно изучить некоторые вещи. – 2013-04-17 06:10:20

0

Проблема закончилась тем, что была связана с тем, что я использовал версию XAudio2 для Windows 8 в среде на основе DirectX9, мое неправильное использование функций CoInitialize() и тот факт, что я никогда явно не называл " delete soundengine '. С тех пор я немного изменил класс, и теперь он отлично работает.

Спасибо, ребята!