Commit 85545b2e authored by Ghislain MARY's avatar Ghislain MARY

Implement audio capture for the Windows Audio Session sound card.

parent 82074a14
......@@ -24,40 +24,49 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mssndcard.h"
#include "mswasapi_reader.h"
#include "mswasapi_writer.h"
/**
* Definition of the private data structure of the WASAPI sound capture filter.
*/
typedef struct _MSWASAPIReadData {
int rate;
int nchannels;
} MSWASAPIReadData;
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
/******************************************************************************
* Methods to (de)initialize and run the WASAPI sound capture filter *
*****************************************************************************/
static void ms_wasapi_read_init(MSFilter *f) {
MSWASAPIReadData *d = (MSWASAPIReadData *)ms_new(MSWASAPIReadData, 1);
d->rate = 8000;
d->nchannels = 1;
f->data = d;
MSWASAPIReader *r = new MSWASAPIReader();
f->data = r;
}
static void ms_wasapi_read_preprocess(MSFilter *f) {
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
r->activate();
}
static void ms_wasapi_read_process(MSFilter *f) {
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
if (!r->isStarted()) {
r->start();
}
if (r->isStarted()) {
r->feed(f->outputs[0]);
}
}
static void ms_wasapi_read_postprocess(MSFilter *f) {
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
r->stop();
r->deactivate();
}
static void ms_wasapi_read_uninit(MSFilter *f) {
MSWASAPIReadData *d = (MSWASAPIReadData *)f->data;
ms_free(d);
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
delete r;
}
......@@ -66,16 +75,34 @@ static void ms_wasapi_read_uninit(MSFilter *f) {
*****************************************************************************/
static int ms_wasapi_read_set_sample_rate(MSFilter *f, void *arg) {
return 0;
/* This is not supported: the Audio Client requires to use the native sample rate. */
MS_UNUSED(f), MS_UNUSED(arg);
return -1;
}
static int ms_wasapi_read_get_sample_rate(MSFilter *f, void *arg) {
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
*((int *)arg) = r->getRate();
return 0;
}
static int ms_wasapi_read_set_nchannels(MSFilter *f, void *arg) {
/* This is not supported: the Audio Client requires to use 1 channel. */
MS_UNUSED(f), MS_UNUSED(arg);
return -1;
}
static int ms_wasapi_read_get_nchannels(MSFilter *f, void *arg) {
MSWASAPIReader *r = (MSWASAPIReader *)f->data;
*((int *)arg) = r->getNChannels();
return 0;
}
static MSFilterMethod ms_wasapi_read_methods[] = {
{ MS_FILTER_SET_SAMPLE_RATE, ms_wasapi_read_set_sample_rate },
{ MS_FILTER_GET_SAMPLE_RATE, ms_wasapi_read_get_sample_rate },
{ MS_FILTER_SET_NCHANNELS, ms_wasapi_read_set_nchannels },
{ MS_FILTER_GET_NCHANNELS, ms_wasapi_read_get_nchannels },
{ 0, NULL }
};
......
......@@ -6,14 +6,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "mswasapi\msw
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\mediastreamer2-private\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}"
ProjectSection(ProjectDependencies) = postProject
{D5EC8C11-C1D9-47E3-BB82-A93C300FD902} = {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}
{FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97}
{6BD78980-9C71-4341-8775-AD19E9EC7305} = {6BD78980-9C71-4341-8775-AD19E9EC7305}
{746EA080-5BA9-42C5-9E52-EA421C3F3AFD} = {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\ortp\build\vsx\oRTP\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\gsm\build\windows\gsm\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}"
......@@ -22,6 +14,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\speex\build\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\speex\build\windows\speex\speexdsp\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
......@@ -38,14 +32,6 @@ Global
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.ActiveCfg = Release|Win32
{D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM
{FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32
......@@ -78,6 +64,14 @@ Global
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32
{6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32
{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
This diff is collapsed.
/*
mswasapi_reader.cpp
mediastreamer2 library - modular sound and video processing and streaming
Windows Audio Session API sound card plugin for mediastreamer2
Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/mscommon.h"
#include "mswasapi_reader.h"
#define REFTIMES_PER_SEC 10000000
#define REPORT_ERROR(msg, result) \
if (result != S_OK) { \
ms_error(msg, result); \
goto error; \
}
#define RELEASE_CLIENT(client) \
if (client != NULL) { \
client->Release(); \
client = NULL; \
}
#define FREE_PTR(ptr) \
if (ptr != NULL) { \
CoTaskMemFree((LPVOID)ptr); \
ptr = NULL; \
}
MSWASAPIReader::MSWASAPIReader()
: mAudioClient(NULL), mAudioCaptureClient(NULL), mBufferFrameCount(0), mIsInitialized(false), mIsActivated(false), mIsStarted(false)
{
HRESULT result;
WAVEFORMATEX *pWfx = NULL;
mCaptureId = GetDefaultAudioCaptureId(Communications);
if (mCaptureId == NULL) {
ms_error("Could not get the CaptureId of the MSWASAPI audio input interface");
goto error;
}
result = ActivateAudioInterface(mCaptureId, IID_IAudioClient, (void **)&mAudioClient);
REPORT_ERROR("Could not activate the MSWASAPI audio input interface [%i]", result);
result = mAudioClient->GetMixFormat(&pWfx);
REPORT_ERROR("Could not get the mix format of the MSWASAPI audio input interface [%i]", result);
mRate = pWfx->nSamplesPerSec;
mNChannels = pWfx->nChannels;
FREE_PTR(pWfx);
mIsInitialized = true;
error:
return;
}
MSWASAPIReader::~MSWASAPIReader()
{
RELEASE_CLIENT(mAudioClient);
FREE_PTR(mCaptureId);
}
int MSWASAPIReader::activate()
{
HRESULT result;
REFERENCE_TIME requestedDuration = REFTIMES_PER_SEC;
WAVEFORMATPCMEX proposedWfx;
WAVEFORMATEX *pUsedWfx = NULL;
WAVEFORMATEX *pSupportedWfx = NULL;
if (!mIsInitialized) goto error;
proposedWfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
proposedWfx.Format.nChannels = (WORD)mNChannels;
proposedWfx.Format.nSamplesPerSec = mRate;
proposedWfx.Format.wBitsPerSample = 16;
proposedWfx.Format.nAvgBytesPerSec = mRate * mNChannels * proposedWfx.Format.wBitsPerSample / 8;
proposedWfx.Format.nBlockAlign = (WORD)(proposedWfx.Format.wBitsPerSample * mNChannels / 8);
proposedWfx.Format.cbSize = 22;
proposedWfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
proposedWfx.Samples.wValidBitsPerSample = proposedWfx.Format.wBitsPerSample;
if (mNChannels == 1) {
proposedWfx.dwChannelMask = SPEAKER_FRONT_CENTER;
} else {
proposedWfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
}
result = mAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *)&proposedWfx, &pSupportedWfx);
if (result == S_OK) {
pUsedWfx = (WAVEFORMATEX *)&proposedWfx;
} else if (result == S_FALSE) {
pUsedWfx = pSupportedWfx;
} else {
REPORT_ERROR("Audio format not supported by the MSWASAPI audio input interface [%i]", result);
}
result = mAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, requestedDuration, 0, pUsedWfx, NULL);
REPORT_ERROR("Could not initialize the MSWASAPI audio input interface [%i]", result);
result = mAudioClient->GetBufferSize(&mBufferFrameCount);
REPORT_ERROR("Could not get buffer size for the MSWASAPI audio input interface [%i]", result);
ms_message("MSWASAPI audio input interface buffer size: %i", mBufferFrameCount);
result = mAudioClient->GetService(IID_IAudioCaptureClient, (void **)&mAudioCaptureClient);
REPORT_ERROR("Could not get render service from the MSWASAPI audio input interface [%i]", result);
mIsActivated = true;
return 0;
error:
FREE_PTR(pSupportedWfx);
return -1;
}
int MSWASAPIReader::deactivate()
{
RELEASE_CLIENT(mAudioCaptureClient);
mIsActivated = false;
return 0;
}
void MSWASAPIReader::start()
{
HRESULT result;
if (!isStarted() && mIsActivated) {
mIsStarted = true;
result = mAudioClient->Start();
if (result != S_OK) {
ms_error("Could not start playback on the MSWASAPI audio input interface [%i]", result);
}
}
}
void MSWASAPIReader::stop()
{
HRESULT result;
if (isStarted() && mIsActivated) {
mIsStarted = false;
result = mAudioClient->Stop();
if (result != S_OK) {
ms_error("Could not stop playback on the MSWASAPI audio input interface [%i]", result);
}
}
}
int MSWASAPIReader::feed(MSQueue *output)
{
HRESULT result;
DWORD flags;
BYTE *pData;
UINT32 numFramesInNextPacket;
mblk_t *m;
int bytesPerFrame = (16 * mNChannels / 8);
result = mAudioCaptureClient->GetNextPacketSize(&numFramesInNextPacket);
REPORT_ERROR("Could not get next packet size for the MSWASAPI audio input interface [%i]", result);
if (numFramesInNextPacket > 0) {
m = allocb(numFramesInNextPacket * bytesPerFrame, 0);
result = mAudioCaptureClient->GetBuffer(&pData, &numFramesInNextPacket, &flags, NULL, NULL);
REPORT_ERROR("Could not get buffer from the MSWASAPI audio input interface [%i]", result);
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
memset(m->b_wptr, 0, numFramesInNextPacket * bytesPerFrame);
} else {
memcpy(m->b_wptr, pData, numFramesInNextPacket * bytesPerFrame);
}
m->b_wptr += numFramesInNextPacket * bytesPerFrame;
result = mAudioCaptureClient->ReleaseBuffer(numFramesInNextPacket);
REPORT_ERROR("Could not release buffer of the MSWASAPI audio input interface [%i]", result);
ms_queue_put(output, m);
}
return 0;
error:
return -1;
}
/*
mswasapi_reader.h
mediastreamer2 library - modular sound and video processing and streaming
Windows Audio Session API sound card plugin for mediastreamer2
Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msqueue.h"
#include <objbase.h>
#include <audioclient.h>
#include <phoneaudioclient.h>
class MSWASAPIReader {
public:
MSWASAPIReader();
virtual ~MSWASAPIReader();
int activate();
int deactivate();
bool isStarted() { return mIsStarted; }
void start();
void stop();
int feed(MSQueue *output);
int getRate() { return mRate; }
int getNChannels() { return mNChannels; }
private:
LPCWSTR mCaptureId;
IAudioClient *mAudioClient;
IAudioCaptureClient *mAudioCaptureClient;
UINT32 mBufferFrameCount;
bool mIsInitialized;
bool mIsActivated;
bool mIsStarted;
int mRate;
int mNChannels;
};
......@@ -44,10 +44,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
MSWASAPIWriter::MSWASAPIWriter()
: mAudioClient(NULL), mAudioRenderClient(NULL), mBufferFrameCount(0), mIsInitialized(false), mIsActivated(false), mIsStarted(false)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment