2016-03-14 6 views
0

Итак, я записываю звук с помощью Delphi с помощью MCISendString. Код работает отлично с одним исключением. Я разрешаю пользователю задавать параметры, каналы, бит, частоту, а в Windows 7 это работает нормально. Теперь в Windows 10 я получаю файл mcierr_wave_inputsinuse.Delphi/MCI Эксклюзивное управление микрофоном

Если я уменьшу параметры до 1 канала, 8 бит, 8 кГц, он записывается штрафом. Все, что выше этого, и MCI отказывается от него. По моему устройству он должен идти 1 канал, 16 бит, 48k.

Я предполагаю, что микрофон используется. Кто-нибудь знает, как заставить программу Delphi взять эксклюзивный контроль, чтобы он мог использовать все возможности устройства?

Я немного поработал и не придумал ничего полезного.

Thanks

Вот код, который я использую.

MRet := mciSendString(PChar('RECORD mysound'), NIL, 0, Handle); 

Он возвращает код результата 322. Я пробовал его с и без преобразования на PChar.

Похоже, что это связано с Cortana. Но поскольку нет возможности полностью отключить Cortana, получение эксклюзивного контроля является единственным возможным решением.

+0

Я думаю, это Кортанно. Попробуйте отключить его. Вы не можете взять эксклюзивный контроль, если что-то еще уже контролирует. – Dsm

+0

Это ... было одно удивительное предположение. Кажется, вы хотя бы частично правы. Я убил Cortana через диспетчера задач, и у меня не было жалоб, когда я увеличил настройки и попытался записать. Однако, похоже, я получаю другую ошибку mci в другом месте, которую мне придется исследовать. Нажатие на запись работает, но это всего лишь сохранение 44-байтового файла, что и было сделано до того, как я добавил начальные проверки ошибок mci. – uPrompt

+0

Спасибо. Я бы выключил Cortana, нажав на Cortana и выключив его в настройках. Убить его менеджером задач может только временно - вы знаете, что такое Microsoft! – Dsm

ответ

0

Вы можете найти пример простого приложения Delphi с использованием WASAPI здесь:

https://web.archive.org/web/20130403023149/http://4coder.org/delphi-source-code/547/

Обратите внимание, что оригинальный сайт уже давно пошли вниз, но Вайбак до сих пор весь код.

Кода для фактической записи здесь:

// http://msdn.microsoft.com/en-us/library/ms678709(VS.85).aspx 
procedure TInputRecordThread.Execute; 
const 
    REFTIMES_PER_SEC = 10000000; 
    REFTIMES_PER_MILLISEC = 10000; 
var 
    MMDev: IMMDevice; 
    MMDevEnum: IMMDeviceEnumerator; 
    AudioClient: IAudioClient; 
    CaptureClient: IAudioCaptureClient; 
    PropVar: ^tag_inner_PROPVARIANT; 
    hnsRequestedDuration, hnsActualDuration: Int64; 
    pWfx, pCloseWfx: PWaveFormatEx; 
    BufferFrameCount, NumFramesAvailable, Flags, StreamFlags, PacketLength, FrameSize: Cardinal; 
    pData: PByte; 
    uDummy: UInt64; 
    Returned: HRESULT; 
    Wave: TWaveImage; 
    Empty: array of byte; 
    pEx: PWaveFormatExtensible; 
begin 
    FreeOnTerminate := True; 
    pCloseWfx := nil; 
    uDummy := 0; 
    PropVar := nil; 

    CoInitializeEx(nil, COINIT_APARTMENTTHREADED); 
    CoCreateInstance(CLASS_MMDeviceEnumerator, 
    nil, 
    CLSCTX_ALL, 
    IID_IMMDeviceEnumerator, 
    MMDevEnum); 

    if FLoopback then 
    Returned := MMDevEnum.GetDefaultAudioEndpoint(eRender, eConsole, MMDev) 
    else 
    Returned := MMDevEnum.GetDefaultAudioEndpoint(eCapture, eConsole, MMDev); 

    if Returned <> S_OK then 
    begin 
    OleCheck(Returned); 
    Exit; 
    end; 

    Returned := MMDev.Activate(IID_IAudioClient, CLSCTX_ALL, PropVar^, Pointer(AudioClient)); 
    if Returned <> S_OK then 
    begin 
    OleCheck(Returned); 
    Exit; 
    end; 

    AudioClient.GetMixFormat(pWfx); 

    // http://www.ambisonic.net/mulchaud.html 
    case pWfx.wFormatTag of 
    WAVE_FORMAT_IEEE_FLOAT: 
     begin 
     pWfx.wFormatTag := WAVE_FORMAT_PCM; 
     pWfx.wBitsPerSample := 16; 
     pWfx.nBlockAlign := pWfx.nChannels * pWfx.wBitsPerSample div 8; 
     pWfx.nAvgBytesPerSec := pWfx.nBlockAlign * pWfx.nSamplesPerSec; 
     end; 
    WAVE_FORMAT_EXTENSIBLE: 
     begin 
     pEx := PWaveFormatExtensible(pWfx); 
     if not IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx.SubFormat) then 
     begin 
      Exit; 
     end; 

     pEx.SubFormat := KSDATAFORMAT_SUBTYPE_PCM; 
     pEx.ValidBitsPerSample := 16; 
     pWfx.wBitsPerSample := 16; 
     pWfx.nBlockAlign := pWfx.nChannels * pWfx.wBitsPerSample div 8; 
     pWfx.nAvgBytesPerSec := pWfx.nBlockAlign * pWfx.nSamplesPerSec; 
     end; 
    else Exit; 
    end; 

    if AudioClient.IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, pWfx, pCloseWfx) <> S_OK then 
    begin 
    Exit; 
    end; 

    // Äŕçěĺđ ôđýéěŕ. 
    FrameSize := pWfx.wBitsPerSample * pWfx.nChannels div 8; 

    hnsRequestedDuration := REFTIMES_PER_SEC; 
    if FLoopback then 
    StreamFlags := AUDCLNT_STREAMFLAGS_LOOPBACK 
    else 
    StreamFlags := 0; 
    Returned := AudioClient.Initialize(AUDCLNT_SHAREMODE_SHARED, 
    StreamFlags, 
    hnsRequestedDuration, 
    0, 
    pWfx, 
    nil); 
    if Returned <> S_OK then 
    begin 
    Exit; 
    end; 

    AudioClient.GetBufferSize(BufferFrameCount); 

    Returned := AudioClient.GetService(IID_IAudioCaptureClient, Pointer(CaptureClient)); 
    if Returned <> S_OK then 
    begin 
    Exit; 
    end; 

    // Calculate the actual duration of the allocated buffer. 
    hnsActualDuration := REFTIMES_PER_SEC * BufferFrameCount div pWfx.nSamplesPerSec; 

    // Start recording. 
    AudioClient.Start(); 

    Wave := TWaveImage.Create(FData); 
    try 
    Wave.InitHeader(pWfx^); 

    // Each loop fills about half of the shared buffer. 
    while not Terminated do 
    begin 
     // Sleep for half the buffer duration. 
     Sleep(hnsActualDuration div REFTIMES_PER_MILLISEC div 2); 

     CaptureClient.GetNextPacketSize(PacketLength); 

     while PacketLength <> 0 do 
     begin 
     // Get the available data in the shared buffer. 
     pData := nil; 
     Returned := CaptureClient.GetBuffer(pData, 
      NumFramesAvailable, 
      Flags, 
      uDummy, 
      uDummy); 

     if Returned <> S_OK then 
     begin 
      Exit; 
     end; 

     if (Flags or Cardinal(AUDCLNT_BUFFERFLAGS_SILENT)) = Flags then 
     begin 
      pData := nil; // Tell CopyData to write silence. 
     end; 

     if pData = nil then 
     begin 
      SetLength(Empty, NumFramesAvailable * FrameSize); 
      FillChar(Empty[0], Length(Empty), 0); 
      FData.Write(Empty[0], Length(Empty)); 
     end 
     else 
     begin 
      // Ĺîőđŕí˙ĺě äŕííűĺ. 
      FData.Write(pData^, NumFramesAvailable * FrameSize); 
     end; 

     CaptureClient.ReleaseBuffer(NumFramesAvailable); 
     CaptureClient.GetNextPacketSize(PacketLength); 
     end; 
    end; 

    // ĂŽĹ„Ĺŕíŕâëčâŕĺě çŕďčńü. 
    AudioClient.Stop(); 

    // ĂŽĹęîđđĺĹčđóĺě çŕÄîëîâîę. 
    Wave.CorretHeader; 
    FData.Position := 0; 
    finally 
    Wave.Free; 

    if pWfx <> nil then 
     CoTaskMemFree(pWfx); 
    end; 
end; 

Вы также можете проверить: http://torry.net/pages.php?id=167&sort=ID