int audioStreamer_ds::Open(int iswrite, int srate, int nch, int bps, int sleep, int nbufs, int bufsize, GUID *device)
{
  // todo: use device
  m_sleep = sleep >= 0 ? sleep : 0;

  GUID zero={0,};
  if (!memcmp(device,&zero,sizeof(zero))) device=NULL;

  m_nch = nch;
  m_srate=srate;
  m_bps=bps;

  int fmt_align=(bps>>3)*nch;
  int fmt_mul=fmt_align*srate;
  WAVEFORMATEX wfx={
		WAVE_FORMAT_PCM,
		nch,
		srate,
		fmt_mul,
		fmt_align,
		bps,
		0
	};
  m_totalbufsize=nbufs*bufsize;

  if (iswrite)
  {
      DirectSoundCreate(device,&m_lpds,NULL);

      if (m_lpds)
      {
        HWND hWnd = GetForegroundWindow();
        if (hWnd == NULL) hWnd = GetDesktopWindow();
        m_lpds->SetCooperativeLevel(hWnd,DSSCL_PRIORITY);

        // create a secondary buffer for now
        DSBUFFERDESC ds={sizeof(ds),DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS,m_totalbufsize,0,&wfx, };
        m_lpds->CreateSoundBuffer(&ds,&m_outbuf,NULL);
        
      }

  }
  else
  {
    DirectSoundCaptureCreate(device,&m_lpcap,NULL);
    if (m_lpcap)
    {
      DSCBUFFERDESC ds={sizeof(ds),0,m_totalbufsize,0,&wfx, };
      m_lpcap->CreateCaptureBuffer(&ds,&m_inbuf,NULL);
    }
  }

  m_bufsize=bufsize;


  return 0;
}
nuiAudioDevice_DirectSound::nuiAudioDevice_DirectSound(GUID IGuid, GUID OGuid, const nglString& rInName, const nglString& rOutName, const nglString& rInModule, const nglString& rOutModule)
: nuiAudioDevice()
{
  mInName = rInName;
  mOutName = rOutName;
  if (rOutName.IsEmpty())
    mName = rInName;
  else
    mName = rOutName;

  mManufacturer = rOutModule;
  mIsPresent = false;
  mHasInput = false;
  mHasOutput = false;

  mIDeviceID = IGuid;
  mODeviceID = OGuid;

  mpDirectSound = NULL;
  mpDirectSoundCapture = NULL;

  mAPIName = API_NAME;

  mpRingBuffer = NULL;
  mpInputBuffer = NULL;
  mpOutputBuffer = NULL;

  mpProcessingTh = NULL;
  mpOutputTh = NULL;

  mNotifInputEvent[0] = NULL;
  mNotifInputEvent[1] = NULL;
  mNotifOutputEvent[0] = NULL;
  mNotifOutputEvent[1] = NULL;

  HRESULT hr;
  // Get Input device caps:
  hr = DirectSoundCaptureCreate(&mIDeviceID, &mpDirectSoundCapture, NULL);
  if (hr != S_OK || !mpDirectSoundCapture)
  {
    NGL_LOG(_T("nuiAudioDevice_DirectSound"), NGL_LOG_INFO, _T("constructor ERROR : could not create DirectSoundCapture object!\n"));
  }

  // Get Output device caps:
  hr = DirectSoundCreate(&mODeviceID, &mpDirectSound, NULL);
  if (hr != S_OK || !mpDirectSound)
  {
    NGL_LOG(_T("nuiAudioDevice_DirectSound"), NGL_LOG_ERROR, _T("constructor ERROR : could not create DirectSound object!\n")); // if there is no output, consider the device as not valid
    return;
  }


  Init();
}
示例#3
0
static int capture_init (void)
{
	HRESULT hr;
	DSCBUFFERDESC sound_buffer_rec;
	WAVEFORMATEX wavfmt;
	TCHAR *name;
	int samplerate = 44100;

	if (currprefs.sampler_freq)
		samplerate = currprefs.sampler_freq;

	name = record_devices[currprefs.win32_samplersoundcard]->name;

	wavfmt.wFormatTag = WAVE_FORMAT_PCM;
	wavfmt.nChannels = 2;
	wavfmt.nSamplesPerSec = samplerate;
	wavfmt.wBitsPerSample = 16;
	wavfmt.nBlockAlign = wavfmt.wBitsPerSample / 8 * wavfmt.nChannels;
	wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
	wavfmt.cbSize = 0;

	clockspersample = sampler_evtime / samplerate;
	sampleframes = (samplerate + 49) / 50;
	recordbufferframes = 16384;
	if (currprefs.sampler_buffer)
		recordbufferframes = currprefs.sampler_buffer;

	hr = DirectSoundCaptureCreate (&record_devices[currprefs.win32_samplersoundcard]->guid, &lpDS2r, NULL);
	if (FAILED (hr)) {
		write_log (_T("SAMPLER: DirectSoundCaptureCreate('%s') failure: %s\n"), name, DXError (hr));
		return 0;
	}
	memset (&sound_buffer_rec, 0, sizeof (DSCBUFFERDESC));
	sound_buffer_rec.dwSize = sizeof (DSCBUFFERDESC);
	sound_buffer_rec.dwBufferBytes = recordbufferframes * SAMPLESIZE;
	sound_buffer_rec.lpwfxFormat = &wavfmt;
	sound_buffer_rec.dwFlags = 0 ;

	hr = lpDS2r->CreateCaptureBuffer (&sound_buffer_rec, &lpDSB2r, NULL);
	if (FAILED (hr)) {
		write_log (_T("SAMPLER: CreateCaptureSoundBuffer('%s') failure: %s\n"), name, DXError(hr));
		return 0;
	}

	hr = lpDSB2r->Start (DSCBSTART_LOOPING);
	if (FAILED (hr)) {
		write_log (_T("SAMPLER: DirectSoundCaptureBuffer_Start('%s') failed: %s\n"), name, DXError (hr));
		return 0;
	}
	samplebuffer = xcalloc (uae_u8, sampleframes * SAMPLESIZE);
	write_log (_T("SAMPLER: Parallel port sampler initialized, CPS=%f, '%s'\n"), clockspersample, name);
	return 1;
}
/* ============ Media Producer Interface ================= */
int tdav_producer_dsound_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
{
	HRESULT hr;

	WAVEFORMATEX wfx = {0};
	DSCBUFFERDESC dsbd = {0};

	tdav_producer_dsound_t* dsound = (tdav_producer_dsound_t*)self;

	if(!dsound || !codec){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	if(dsound->device || dsound->captureBuffer){
		TSK_DEBUG_ERROR("Producer already prepared");
		return -2;
	}

	TDAV_PRODUCER_AUDIO(dsound)->channels = codec->plugin->audio.channels;
	TDAV_PRODUCER_AUDIO(dsound)->rate = codec->plugin->rate;

	/* Create capture device */
	if((hr = DirectSoundCaptureCreate(NULL, &dsound->device, NULL) != DS_OK)){
		tdav_win32_print_error("DirectSoundCaptureCreate", hr);
		return -3;
	}

	/* Creates the capture buffer */
	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.nChannels = TDAV_PRODUCER_AUDIO(dsound)->channels;
	wfx.nSamplesPerSec = TDAV_PRODUCER_AUDIO(dsound)->rate;
	wfx.wBitsPerSample = TDAV_PRODUCER_AUDIO(dsound)->bits_per_sample;
	wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample/8);
	wfx.nAvgBytesPerSec = (wfx.nSamplesPerSec * wfx.nBlockAlign);

	/* Average bytes (count) for each notification */
	dsound->bytes_per_notif = ((wfx.nAvgBytesPerSec * TDAV_PRODUCER_AUDIO(dsound)->ptime)/1000);

	dsbd.dwSize = sizeof(DSCBUFFERDESC);
	dsbd.dwBufferBytes = (TDAV_DSOUNS_PRODUCER_NOTIF_POS_COUNT * dsound->bytes_per_notif);
	dsbd.lpwfxFormat = &wfx;

	if((hr = IDirectSoundCapture_CreateCaptureBuffer(dsound->device, &dsbd, &dsound->captureBuffer, NULL)) != DS_OK){
		tdav_win32_print_error("IDirectSoundCapture_CreateCaptureBuffer", hr);
		return -4;
	}	

	return 0;
}
示例#5
0
void *DSOUND_Capture_Init (int rate)
{
	dsndcapture_t *result;
	DSCBUFFERDESC bufdesc = {0};
	WAVEFORMATEX  wfxFormat = {0};

	Com_DPrintf("DSOUND_Capture_Init: rate %d\n", rate);

	wfxFormat.wFormatTag = WAVE_FORMAT_PCM;
    wfxFormat.nChannels = 1;
    wfxFormat.nSamplesPerSec = rate;
	wfxFormat.wBitsPerSample = 8*inputwidth;
    wfxFormat.nBlockAlign = wfxFormat.nChannels * (wfxFormat.wBitsPerSample / 8);
	wfxFormat.nAvgBytesPerSec = wfxFormat.nSamplesPerSec * wfxFormat.nBlockAlign;
    wfxFormat.cbSize = 0;

	bufdesc.dwSize = sizeof(bufdesc);
	bufdesc.dwBufferBytes = bufferbytes;
	bufdesc.dwFlags = 0;
	bufdesc.dwReserved = 0;
	bufdesc.lpwfxFormat = &wfxFormat;

	result = Z_Malloc(sizeof(*result));
	if (FAILED(DirectSoundCaptureCreate(NULL, &result->DSCapture, NULL)))
	{
		Com_Printf_State (PRINT_FAIL, "DirectSound: Couldn't create a capture device\n");
	}
	else if (FAILED(IDirectSoundCapture_CreateCaptureBuffer(result->DSCapture, &bufdesc, &result->DSCaptureBuffer, NULL)))
	{
		Com_Printf_State (PRINT_FAIL, "DirectSound: Couldn't create a capture buffer\n");	
	}
	else
	{
		Com_DPrintf("DSOUND_Capture_Init: OK\n");
		return result;	
	}

	// failure, lets clean up.

	if (result->DSCapture)
	{
		IDirectSoundCapture_Release(result->DSCapture);	
	}

	Z_Free(result);

	return NULL;
}
nuiAudioDevice_DirectSound::nuiAudioDevice_DirectSound()
: nuiAudioDevice()
{
  mInName = _T("Default Device");
  mOutName = _T("Default Device");

  mIsPresent = false;
  mHasInput = false;
  mHasOutput = false;

  mpDirectSound = NULL;
  mpDirectSoundCapture = NULL;

  mAPIName = API_NAME;

  mpRingBuffer = NULL;
  mpInputBuffer = NULL;
  mpOutputBuffer = NULL;

  mpProcessingTh = NULL;
  mpOutputTh = NULL;

  mNotifInputEvent[0] = NULL;
  mNotifInputEvent[1] = NULL;
  mNotifOutputEvent[0] = NULL;
  mNotifOutputEvent[1] = NULL;

  HRESULT hr;
  // Get Input device caps:
  hr = DirectSoundCaptureCreate(NULL, &mpDirectSoundCapture, NULL);
  if (hr != S_OK || !mpDirectSoundCapture)
  {
    NGL_LOG(_T("nuiAudioDevice_DirectSound"), NGL_LOG_INFO, _T("constructor ERROR : could not create DirectSoundCapture object!\n"));
  }

  // Get Output device caps:
  hr = DirectSoundCreate(NULL, &mpDirectSound, NULL);
  if (hr != S_OK || !mpDirectSound)
  {
    NGL_LOG(_T("nuiAudioDevice_DirectSound"), NGL_LOG_ERROR, _T("constructor ERROR : could not create DirectSound object!\n"));// if there is no output, consider the device as not valid
    return;
  }

  Init();
}
示例#7
0
HRESULT SoundCapture::Open( DWORD dwSampleRate, WORD wBitPerSample, WORD wChannels )
{
	GUID deviceGuid = GUID_NULL;
	HRESULT hr = DirectSoundCaptureCreate( &deviceGuid, &m_pDSCapture, NULL );
	m_dwNextCaptureOffset = 0;

	WAVEFORMATEX wfxInput;
	ZeroMemory ( &wfxInput, sizeof(wfxInput) );
	wfxInput.wFormatTag = WAVE_FORMAT_PCM;
	wfxInput.nSamplesPerSec = dwSampleRate;
	wfxInput.wBitsPerSample = wBitPerSample;
	wfxInput.nChannels = wChannels;
	wfxInput.nBlockAlign = wfxInput.nChannels * ( wfxInput.wBitsPerSample / 8 );
	wfxInput.nAvgBytesPerSec = wfxInput.nBlockAlign * wfxInput.nSamplesPerSec;

	DWORD dwNotifySize = max( 1024, wfxInput.nAvgBytesPerSec / 8 );
	dwNotifySize -= dwNotifySize % wfxInput.nBlockAlign;
	m_dwCaptureBufferSize = dwNotifySize * NUM_REC_NOTIFICATIONS;

	DSCBUFFERDESC dscbd;
	ZeroMemory( &dscbd, sizeof(dscbd) );
	dscbd.dwSize = sizeof(dscbd);
	dscbd.dwBufferBytes = m_dwCaptureBufferSize;
	dscbd.lpwfxFormat = &wfxInput; // Set the format during creatation
	hr = m_pDSCapture->CreateCaptureBuffer( &dscbd, &m_pDSBCapture, NULL );

	DSBPOSITIONNOTIFY arrPosNotify[NUM_REC_NOTIFICATIONS + 1];
	ZeroMemory( &arrPosNotify, sizeof( DSBPOSITIONNOTIFY ) * ( NUM_REC_NOTIFICATIONS + 1 ) );
	m_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

	hr = m_pDSBCapture->QueryInterface( IID_IDirectSoundNotify, (VOID**)&m_pDSNotify );
	for ( int i = 0; i < NUM_REC_NOTIFICATIONS; i++ )
	{
		arrPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
		arrPosNotify[i].hEventNotify = m_hNotificationEvent;
	}
	hr = m_pDSNotify->SetNotificationPositions( NUM_REC_NOTIFICATIONS, arrPosNotify );
	return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitDirectSound()
// Desc: Initilizes DirectSound
//-----------------------------------------------------------------------------
HRESULT CCaptureSound::InitDirectSound( GUID* pDeviceGuid )
{
    HRESULT hr;
    m_dwCaptureBufferSize = 0;
    m_dwNotifySize        = 0;
//    g_pWaveFile           = NULL;

    // Initialize COM
    if( FAILED( hr = CoInitialize(NULL) ) )
	{
        printf( "CoInitialize" );
		return hr;
	}


    // Create IDirectSoundCapture using the preferred capture device
    //if( FAILED( hr = DirectSoundCaptureCreate( pDeviceGuid, &m_pDSCapture, NULL ) ) )  //DirectSoundCaptureCreate??
	//in here ,use DSDEVID_DefaultVoiceCapture 
	if( FAILED( hr = DirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture, &m_pDSCapture, NULL ) ) )  //DSDEVID_DefaultCapture?? DSDEVID_DefaultVoiceCapture
	{				//DirectSoundCreate8(NULL,&dsound_handle->g_pDsd,NULL)
        printf("DirectSoundCaptureCreate");
		return hr;
	}

	//{WAVE_FORMAT_PCM, 1, 8000, 16000, 2, 16, 0} //Ĭ����Ƶ��ʽ
	 // wFormatTag, nChannels, nSamplesPerSec, mAvgBytesPerSec,
    // nBlockAlign, wBitsPerSample, cbSize
	m_wfxInput.wFormatTag= WAVE_FORMAT_PCM;
	m_wfxInput.nChannels=1;
	m_wfxInput.nSamplesPerSec=8000;
	m_wfxInput.wBitsPerSample=16;
	m_wfxInput.nBlockAlign = m_wfxInput.nChannels * ( m_wfxInput.wBitsPerSample / 8 );
    m_wfxInput.nAvgBytesPerSec = m_wfxInput.nBlockAlign * m_wfxInput.nSamplesPerSec;
	m_wfxInput.cbSize=0;

    return S_OK;
}
示例#9
0
HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
{
	HRESULT hr = DirectSoundCaptureCreate(  lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );
	if( hr != DS_OK ) return hr;
	return hr;
}
示例#10
0
PaError PaHost_OpenStream( internalPortAudioStream   *past )
{
	HRESULT          hr;
	PaError          result = paNoError;
	PaHostSoundControl *pahsc;
	int              numBytes, maxChannels;
	unsigned int     minNumBuffers;
	internalPortAudioDevice *pad;
	DSoundWrapper   *dsw;
/* Allocate and initialize host data. */
	pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */
	if( pahsc == NULL )
	{
		result = paInsufficientMemory;
		goto error;
	}
	memset( pahsc, 0, sizeof(PaHostSoundControl) );
	past->past_DeviceData = (void *) pahsc;
	pahsc->pahsc_TimerID = 0;
	dsw = &pahsc->pahsc_DSoundWrapper;
	DSW_Init( dsw );
/* Allocate native buffer. */
	maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ?
		past->past_NumOutputChannels : past->past_NumInputChannels;
	pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short);
	if( maxChannels > 0 )
	{
		pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */
		if( pahsc->pahsc_NativeBuffer == NULL )
		{
			result = paInsufficientMemory;
			goto error;
		}
	}
	else
	{
		result = paInvalidChannelCount;
		goto error;
	}
	
	DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer ));
	minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
	past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
	numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers;
	if( numBytes < DSBSIZE_MIN )
	{
		result = paBufferTooSmall;
		goto error;
	}
	if( numBytes > DSBSIZE_MAX )
	{
		result = paBufferTooBig;
		goto error;
	}
	pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
	{
		int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate);
		PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency ));
	}
/* ------------------ OUTPUT */
	if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) )
	{
		DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
		pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
		hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound,   NULL );
/* If this fails, then try each output device until we find one that works. */
		if( hr != DS_OK )
		{
			int i;
			ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n",
				((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
			for( i=0; i<Pa_CountDevices(); i++ )
			{
				pad = Pa_GetInternalDevice( i );
				if( pad->pad_Info.maxOutputChannels >= past->past_NumOutputChannels )
				{
					DBUG(("Try device '%s' instead.\n", pad->pad_Info.name ));
					hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound,   NULL );
					if( hr == DS_OK )
					{
						ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name ));
						break;
					}
				}
			}
		}
		if( hr != DS_OK )
		{
			ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
			result = paHostError;
			sPaHostError = hr;
			goto error;
		}
		hr = DSW_InitOutputBuffer( dsw,
			(unsigned long) (past->past_SampleRate + 0.5),
			past->past_NumOutputChannels, numBytes );
		DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
		if( hr != DS_OK )
		{
			result = paHostError;
			sPaHostError = hr;
			goto error;
		}
		past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten;
	}
#if SUPPORT_AUDIO_CAPTURE
/* ------------------ INPUT */
	if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) )
	{
		pad = Pa_GetInternalDevice( past->past_InputDeviceID );
		hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );
/* If this fails, then try each input device until we find one that works. */
		if( hr != DS_OK )
		{
			int i;
			ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n",
				((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
			for( i=0; i<Pa_CountDevices(); i++ )
			{
				pad = Pa_GetInternalDevice( i );
				if( pad->pad_Info.maxInputChannels >= past->past_NumInputChannels )
				{
					PRINT(("Try device '%s' instead.\n", pad->pad_Info.name ));
					hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );
					if( hr == DS_OK ) break;
				}
			}
		}
		if( hr != DS_OK )
		{
			ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
			result = paHostError;
			sPaHostError = hr;
			goto error;
		}
		hr = DSW_InitInputBuffer( dsw,
			(unsigned long) (past->past_SampleRate + 0.5),
			past->past_NumInputChannels, numBytes );
		DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
		if( hr != DS_OK )
		{
			ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
			result = paHostError;
			sPaHostError = hr;
			goto error;
		}
	}
#endif /* SUPPORT_AUDIO_CAPTURE */
	/* Calculate scalar used in CPULoad calculation. */ 
	{
		LARGE_INTEGER frequency;
		if( QueryPerformanceFrequency( &frequency ) == 0 )
		{
			pahsc->pahsc_InverseTicksPerUserBuffer = 0.0;
		}
		else
		{
			pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate /
				( (double)frequency.QuadPart * past->past_FramesPerUserBuffer );
			DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer ));
		}
	}
	return result;
error:
	PaHost_CloseStream( past );
	return result;
}
示例#11
0
/************************************************************************************
** Extract capabilities info from each device.
*/
static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID, 
				         LPCTSTR lpszDesc,
				         LPCTSTR lpszDrvName, 
				         LPVOID lpContext )
{
	HRESULT    hr;
	LPDIRECTSOUND          lpDirectSound;
#if SUPPORT_AUDIO_CAPTURE
	LPDIRECTSOUNDCAPTURE   lpDirectSoundCapture;
#endif /* SUPPORT_AUDIO_CAPTURE */
	int        isInput  = (int) lpContext;  /* Passed from Pa_CountDevices() */
	internalPortAudioDevice *pad;
		
	if( sDeviceIndex >= sNumDevices )
	{
		sEnumerationError = paInternalError;
		return FALSE;
	}
	pad = &sDevices[sDeviceIndex];
/* Copy GUID to static array. Set pointer. */
	if( lpGUID == NULL )
	{
		pad->pad_lpGUID = NULL;
	}
	else
	{
		memcpy( &pad->pad_GUID, lpGUID, sizeof(GUID) );
		pad->pad_lpGUID = &pad->pad_GUID;
	}
	pad->pad_Info.sampleRates = pad->pad_SampleRates;  /* Point to array. */
/* Allocate room for descriptive name. */
	if( lpszDesc != NULL )
	{
		int len = strlen(lpszDesc);
		pad->pad_Info.name = (char *)malloc( len+1 );
		if( pad->pad_Info.name == NULL )
		{
			sEnumerationError = paInsufficientMemory;
			return FALSE;
		}
		memcpy( (void *) pad->pad_Info.name, lpszDesc, len+1 );
	}
#if SUPPORT_AUDIO_CAPTURE
	if( isInput )
	{
	/********** Input ******************************/
		DSCCAPS     caps;
		if( lpGUID == NULL ) sDefaultInputDeviceID = sDeviceIndex;
		hr = DirectSoundCaptureCreate(  lpGUID, &lpDirectSoundCapture,   NULL );
		if( hr != DS_OK )
		{
			pad->pad_Info.maxInputChannels = 0;
			DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr ));
		}
		else
		{
	/* Query device characteristics. */
			caps.dwSize = sizeof(caps);
			IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
			/* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */
			pad->pad_Info.maxInputChannels = caps.dwChannels;
	/* Determine sample rates from flags. */
			if( caps.dwChannels == 2 )
			{
				int index = 0;
				if( caps.dwFormats & WAVE_FORMAT_1S16) pad->pad_SampleRates[index++] = 11025.0;
				if( caps.dwFormats & WAVE_FORMAT_2S16) pad->pad_SampleRates[index++] = 22050.0;
				if( caps.dwFormats & WAVE_FORMAT_4S16) pad->pad_SampleRates[index++] = 44100.0;
				pad->pad_Info.numSampleRates = index;
			}
			else if( caps.dwChannels == 1 )
			{
				int index = 0;
				if( caps.dwFormats & WAVE_FORMAT_1M16) pad->pad_SampleRates[index++] = 11025.0;
				if( caps.dwFormats & WAVE_FORMAT_2M16) pad->pad_SampleRates[index++] = 22050.0;
				if( caps.dwFormats & WAVE_FORMAT_4M16) pad->pad_SampleRates[index++] = 44100.0;
				pad->pad_Info.numSampleRates = index;
			}
			else pad->pad_Info.numSampleRates = 0;
			IDirectSoundCapture_Release( lpDirectSoundCapture );
		}
	}
	else
#endif /* SUPPORT_AUDIO_CAPTURE */
	{
	/********** Output ******************************/
		DSCAPS     caps;
		if( lpGUID == NULL ) sDefaultOutputDeviceID = sDeviceIndex;
	/* Create interfaces for each object. */
		hr = DirectSoundCreate(  lpGUID, &lpDirectSound,   NULL );
		if( hr != DS_OK )
		{
			pad->pad_Info.maxOutputChannels = 0;
			DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr ));
		}
		else
		{
		/* Query device characteristics. */
			caps.dwSize = sizeof(caps);
			IDirectSound_GetCaps( lpDirectSound, &caps );
			pad->pad_Info.maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
		/* Get sample rates. */
			pad->pad_SampleRates[0] = (double) caps.dwMinSecondarySampleRate;
			pad->pad_SampleRates[1] = (double) caps.dwMaxSecondarySampleRate;
			if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) pad->pad_Info.numSampleRates = -1;
			else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
			{
				if( caps.dwMinSecondarySampleRate == 0 )
				{
			/*
			** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
			** But it supports continuous sampling.
			** So fake range of rates, and hope it really supports it.
			*/
					pad->pad_SampleRates[0] = 11025.0f;
					pad->pad_SampleRates[1] = 48000.0f;
					pad->pad_Info.numSampleRates = -1; /* continuous range */
					
					DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
				}
				else
				{
					pad->pad_Info.numSampleRates = 1;
				}
			}
			else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
			{
			/* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
			** But we know that they really support a range of rates!
			** So when we see a ridiculous set of rates, assume it is a range.
			*/
				pad->pad_Info.numSampleRates = -1;
				DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
			}
			else pad->pad_Info.numSampleRates = 2;
			IDirectSound_Release( lpDirectSound );
		}
	}
	pad->pad_Info.nativeSampleFormats = paInt16;
	sDeviceIndex++;
	return( TRUE );
}
示例#12
0
static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
{
    DSoundCaptureData *data = NULL;
    WAVEFORMATEXTENSIBLE InputType;
    DSCBUFFERDESC DSCBDescription;
    LPGUID guid = NULL;
    HRESULT hr, hrcom;
    ALuint samples;

    if(!CaptureDeviceList)
    {
        /* Initialize COM to prevent name truncation */
        hrcom = CoInitialize(NULL);
        hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
        if(FAILED(hr))
            ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
        if(SUCCEEDED(hrcom))
            CoUninitialize();
    }

    if(!deviceName && NumCaptureDevices > 0)
    {
        deviceName = CaptureDeviceList[0].name;
        guid = &CaptureDeviceList[0].guid;
    }
    else
    {
        ALuint i;

        for(i = 0;i < NumCaptureDevices;i++)
        {
            if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
            {
                guid = &CaptureDeviceList[i].guid;
                break;
            }
        }
        if(i == NumCaptureDevices)
            return ALC_INVALID_VALUE;
    }

    switch(device->FmtType)
    {
        case DevFmtByte:
        case DevFmtUShort:
        case DevFmtUInt:
            WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
            return ALC_INVALID_ENUM;

        case DevFmtUByte:
        case DevFmtShort:
        case DevFmtInt:
        case DevFmtFloat:
            break;
    }

    //Initialise requested device
    data = calloc(1, sizeof(DSoundCaptureData));
    if(!data)
        return ALC_OUT_OF_MEMORY;

    hr = DS_OK;

    //DirectSoundCapture Init code
    if(SUCCEEDED(hr))
        hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL);
    if(SUCCEEDED(hr))
    {
        memset(&InputType, 0, sizeof(InputType));

        switch(device->FmtChans)
        {
            case DevFmtMono:
                InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
                break;
            case DevFmtStereo:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT;
                break;
            case DevFmtQuad:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT |
                                          SPEAKER_BACK_LEFT |
                                          SPEAKER_BACK_RIGHT;
                break;
            case DevFmtX51:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT |
                                          SPEAKER_FRONT_CENTER |
                                          SPEAKER_LOW_FREQUENCY |
                                          SPEAKER_BACK_LEFT |
                                          SPEAKER_BACK_RIGHT;
                break;
            case DevFmtX51Side:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT |
                                          SPEAKER_FRONT_CENTER |
                                          SPEAKER_LOW_FREQUENCY |
                                          SPEAKER_SIDE_LEFT |
                                          SPEAKER_SIDE_RIGHT;
                break;
            case DevFmtX61:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT |
                                          SPEAKER_FRONT_CENTER |
                                          SPEAKER_LOW_FREQUENCY |
                                          SPEAKER_BACK_CENTER |
                                          SPEAKER_SIDE_LEFT |
                                          SPEAKER_SIDE_RIGHT;
                break;
            case DevFmtX71:
                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                          SPEAKER_FRONT_RIGHT |
                                          SPEAKER_FRONT_CENTER |
                                          SPEAKER_LOW_FREQUENCY |
                                          SPEAKER_BACK_LEFT |
                                          SPEAKER_BACK_RIGHT |
                                          SPEAKER_SIDE_LEFT |
                                          SPEAKER_SIDE_RIGHT;
                break;
        }

        InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
        InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
        InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
        InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
        InputType.Format.nSamplesPerSec = device->Frequency;
        InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
        InputType.Format.cbSize = 0;

        if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
        {
            InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
            InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
            InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
            if(device->FmtType == DevFmtFloat)
                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
            else
                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
        }

        samples = device->UpdateSize * device->NumUpdates;
        samples = maxu(samples, 100 * device->Frequency / 1000);

        memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
        DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
        DSCBDescription.dwFlags = 0;
        DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
        DSCBDescription.lpwfxFormat = &InputType.Format;

        hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL);
    }
    if(SUCCEEDED(hr))
    {
         data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
         if(data->Ring == NULL)
             hr = DSERR_OUTOFMEMORY;
    }

    if(FAILED(hr))
    {
        ERR("Device init failed: 0x%08lx\n", hr);

        DestroyRingBuffer(data->Ring);
        data->Ring = NULL;
        if(data->DSCbuffer != NULL)
            IDirectSoundCaptureBuffer_Release(data->DSCbuffer);
        data->DSCbuffer = NULL;
        if(data->DSC)
            IDirectSoundCapture_Release(data->DSC);
        data->DSC = NULL;

        free(data);
        return ALC_INVALID_VALUE;
    }

    data->BufferBytes = DSCBDescription.dwBufferBytes;
    SetDefaultWFXChannelOrder(device);

    device->DeviceName = strdup(deviceName);
    device->ExtraData = data;

    return ALC_NO_ERROR;
}
示例#13
0
// ////////////////////////////////////////////////////////////////////////
BOOL NETinitAudioCapture(VOID)
{
	HRESULT				hr;
	WAVEFORMATEX        wfx;

	NetPlay.bAllowCaptureRecord = FALSE;

	hr = DirectSoundCaptureCreate(	NULL,&lpDirectSoundCapture,	NULL);
	if(hr != DS_OK)
	{
		DBPRINTF(("NETPLAY:Failed to create capture interface."));
		if(hr == DSERR_NOAGGREGATION)
		{
			DBPRINTF(("DSERR_NOAGGREGATION"));
		}
		if(hr == DSERR_OUTOFMEMORY)
		{
			DBPRINTF(("DSERR_OUTOFMEMORY"));
		}
		if(hr == DSERR_INVALIDPARAM)
		{
			DBPRINTF(("DSERR_INVALIDPARAM"));
		}
		return FALSE;
	}
	
	ZeroMemory(&captureBuff, sizeof(captureBuff));
	lpDirectSoundCaptureBuffer = NULL;
 
	wfx.wFormatTag			= WAVE_FORMAT_PCM; 	//set audio format
	wfx.nChannels			= AUDIOCHANNELS;
	wfx.nSamplesPerSec		= SAMPLERATE;			
	wfx.nAvgBytesPerSec		= SAMPLERATE * (BITSPERSAMPLE /8) * AUDIOCHANNELS  ;	
	wfx.nBlockAlign			= (AUDIOCHANNELS * BITSPERSAMPLE) / 8 ; 
	wfx.wBitsPerSample		= BITSPERSAMPLE;	
	wfx.cbSize				= 0;	

	captureBuff.dwSize		= sizeof(DSCBUFFERDESC);
	captureBuff.dwFlags		= DSCBCAPS_WAVEMAPPED;
	captureBuff.dwBufferBytes= SAMPLETIME * wfx.nAvgBytesPerSec;		// SAMPLETIME second’s worth of audio
	captureBuff.lpwfxFormat =  &wfx;
 
	hr = IDirectSoundCapture_CreateCaptureBuffer(lpDirectSoundCapture,
												&captureBuff,
												&lpDirectSoundCaptureBuffer,
												NULL);	
	if(hr != DS_OK)
	{
		if( hr == DSERR_INVALIDPARAM)
		{DBPRINTF(("NETPLAY:no capturebuffer,inv param"));
		}
		if( hr == DSERR_BADFORMAT)
		{DBPRINTF(("NETPLAY:no capturebuffer,badformat"));
		}
		if( hr == DSERR_GENERIC)
		{DBPRINTF(("NETPLAY:no capturebuffer,generic"));
		}
		if( hr == DSERR_NODRIVER)
		{DBPRINTF(("NETPLAY:no capturebuffer,nodriver"));
		}
		if( hr == DSERR_OUTOFMEMORY)
		{DBPRINTF(("NETPLAY:no capturebuffer,memory"));	
		}
		if( hr == DSERR_UNINITIALIZED)
		{DBPRINTF(("NETPLAY:no capturebuffer,uninit"));
		}
		return FALSE;
	}

	NetPlay.bAllowCaptureRecord = TRUE;
//	allowCapture = TRUE;
	return(TRUE);
}
示例#14
0
/*
 * Initialize DirectSound recorder device
 */
static pj_status_t init_capture_stream( struct dsound_stream *ds_strm,
				        int dev_id,
				        unsigned clock_rate,
				        unsigned channel_count,
				        unsigned samples_per_frame,
				        unsigned buffer_count)
{
    HRESULT hr;
    PCMWAVEFORMAT pcmwf; 
    DSCBUFFERDESC dscbdesc;
    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
    unsigned bytes_per_frame;
    unsigned i;


    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);


    /* Check device id */
    if (dev_id == -1)
	dev_id = 0;

    PJ_ASSERT_RETURN(dev_id>=0 && dev_id < (int)dev_count, PJ_EINVAL);

    /*
     * Creating recorder device.
     */
    hr = DirectSoundCaptureCreate(dev_info[dev_id].lpGuid, 
				  &ds_strm->ds.capture.lpDs, NULL);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);


    /* Init wave format to initialize buffer */
    init_waveformatex( &pcmwf, clock_rate, channel_count);
    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;

    /* 
     * Setup capture buffer using sound buffer structure that was passed
     * to play buffer creation earlier.
     */
    pj_bzero(&dscbdesc, sizeof(DSCBUFFERDESC));
    dscbdesc.dwSize = sizeof(DSCBUFFERDESC); 
    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;
    dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame; 
    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 

    hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs,
						  &dscbdesc, 
						  &ds_strm->ds.capture.lpDsBuffer,
						  NULL);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    /*
     * Create event for play notification.
     */
    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
    if (ds_strm->hEvent == NULL)
	return pj_get_os_error();

    /*
     * Setup notifications for recording.
     */
    hr = IDirectSoundCaptureBuffer_QueryInterface( ds_strm->ds.capture.lpDsBuffer, 
						   &IID_IDirectSoundNotify, 
						   (LPVOID *)&ds_strm->lpDsNotify); 
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    
    for (i=0; i<buffer_count; ++i) {
	dsPosNotify[i].dwOffset = i * bytes_per_frame;
	dsPosNotify[i].hEventNotify = ds_strm->hEvent;
    }
    
    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 
						      buffer_count, 
						      dsPosNotify);
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer, 
						       NULL, &ds_strm->dwBytePos );
    if (FAILED(hr))
	return PJ_RETURN_OS_ERROR(hr);

    ds_strm->timestamp.u64 = 0;
    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
    /*
     * Capture latency must always be on a frame boundry,
     * so compute it based off the calculated buffer_count.
     */
    ds_strm->latency = buffer_count * samples_per_frame * 1000 / clock_rate / 
		       channel_count;

    /* Done setting up recorder device. */
    PJ_LOG(5,(THIS_FILE, 
	      " DirectSound capture \"%s\" initialized (clock_rate=%d, "
	      "channel_count=%d, samples_per_frame=%d (%dms))",
	      dev_info[dev_id].info.name,
	      clock_rate, channel_count, samples_per_frame,
	      samples_per_frame * 1000 / clock_rate));

    return PJ_SUCCESS;
}
示例#15
0
/*
    nInterval is in SECONDS.  The buffer we create is 3 times the interval,
    so we make three notifications that will be placed at every interval.

    pProc will be called at approximately the interval specified.
*/
HRESULT WaveCapture::Initialize(int nDevice, WAVEFORMATEX* pFormat, WAVECAPTUREPROC pProc, PVOID pUser, int nInterval)
{
    DSCCAPS dsc;
    DSCBUFFERDESC1 dscbDesc;
    HRESULT hr;
    DSBPOSITIONNOTIFY NotifyPositions[3];
    IDirectSoundNotify* pdsn;

    this->Uninitialize();

    this->pProc = pProc;
    this->pUser = pUser;
    this->nInterval = nInterval;

    // Validation.
    if(pFormat->wFormatTag != WAVE_FORMAT_PCM)
    {
        return E_FAIL;
    }

    // Copy the wave format for our own purposes.
    memcpy(&this->Format, pFormat, sizeof(WAVEFORMATEX));

    m_iDevice = nDevice;
    memset(&m_Device, 0, sizeof(GUID));
    DirectSoundCaptureEnumerate(WaveCapture::DSEnumCallback, this);

    // Create DirectSoundCapture object.
    if(FAILED(hr = DirectSoundCaptureCreate(&m_Device, &this->pdsc, NULL)))
    {
        return E_FAIL;
    }

    /*
        Here is where we should check the capabilities of the sound card against
        the format that was passed in.
    */
    dsc.dwSize = sizeof(DSCCAPS);
    if(FAILED(hr = this->pdsc->GetCaps(&dsc)))
    {
        SAFE_RELEASE(this->pdsc);
        return E_FAIL;
    }

    /*
        Create the capture buffer.
    */
    dscbDesc.dwSize = sizeof(dscbDesc);
    dscbDesc.dwFlags = DSCBCAPS_WAVEMAPPED;
    dscbDesc.dwBufferBytes = (pFormat->nAvgBytesPerSec * nInterval) * 3;
    dscbDesc.dwReserved = 0;
    dscbDesc.lpwfxFormat = &this->Format;

    if(FAILED(hr = this->pdsc->CreateCaptureBuffer((DSCBUFFERDESC*)&dscbDesc, &this->pdsb, NULL)))
    {
        SAFE_RELEASE(this->pdsc);
        return E_FAIL;
    }

    /*
        Create the notifications
    */
    this->hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
    this->hEvents[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
    this->hEvents[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
    this->hEvents[3] = CreateEvent(NULL, FALSE, FALSE, NULL);

    NotifyPositions[0].dwOffset = 0;
    NotifyPositions[0].hEventNotify = this->hEvents[0];

    NotifyPositions[1].dwOffset = (this->Format.nAvgBytesPerSec * nInterval);
    NotifyPositions[1].hEventNotify = this->hEvents[1];

    NotifyPositions[2].dwOffset = (this->Format.nAvgBytesPerSec * nInterval) * 2;
    NotifyPositions[2].hEventNotify = this->hEvents[2];

    if(FAILED(hr = this->pdsb->QueryInterface(IID_IDirectSoundNotify, (PVOID*)&pdsn)))
    {
        SAFE_RELEASE(this->pdsb);
        SAFE_RELEASE(this->pdsc);
        return E_FAIL;
    }

    if(FAILED(hr = pdsn->SetNotificationPositions(3, NotifyPositions)))
    {
        SAFE_RELEASE(pdsn);
        SAFE_RELEASE(this->pdsb);
        SAFE_RELEASE(this->pdsc);
        return E_FAIL;
    }

    SAFE_RELEASE(pdsn);

    /*
        Create our own buffer so when we pass data to pProc, the data is ALWAYS
        contiguous.
    */
    this->nBufferSize = (pFormat->nAvgBytesPerSec * nInterval) * 3;
    this->pBuffer = (PBYTE)malloc(this->nBufferSize);

    /*
        Initialize our own information.
    */
    this->dwLastPosition = 0;
    this->nPassesLeft = 1;

    /*
        Now create our recording thread so life can continue.
    */
    UINT dwThreadId;
	this->hThread = (HANDLE)_beginthreadex(
        0, 0, WaveCapture::RecordingThread, this, 0, &dwThreadId);

    return S_OK;
}