Delphi / MCI Эксклюзивное управление микрофоном
Поэтому я записываю аудио с Delphi, используя MCISendString. Код работает нормально с одним исключением. Я позволяю пользователю устанавливать параметры, каналы, биты, частоту, и в Windows 7 это работало нормально. Теперь в Windows 10 я получаю mcierr_wave_inputsinuse.
Если я уменьшу параметры до 1 канала, 8 бит, 8 кГц, запись будет прекрасной. Что-нибудь выше этого и MCI отказывается от этого. По моему устройству должно идти 1 канал, 16 бит, 48к.
Я предполагаю, что микрофон используется совместно. Кто-нибудь знает, как заставить программу Delphi получить эксклюзивный контроль, чтобы она могла использовать все возможности устройства?
Я хорошо покопался и не нашел ничего полезного.
Спасибо
Вот код, который я использую.
MRet := mciSendString(PChar('RECORD mysound'), NIL, 0, Handle);
Он возвращает код результата 322. Я пробовал с и без преобразования в PChar.
Похоже, это связано с Кортаной. Но так как нет способа полностью отключить Cortana, получение эксклюзивного контроля представляется единственно возможным решением.
1 ответ
Вы можете найти пример простого приложения 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