Problem trying to play noise through WASAPI

I am trying to play noise through the default speaker on my system using WASAPI, but I can not get it to work.

Here is the code that deals with the system:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 
#include <InitGuid.h>
#include <iostream>
#include <Windows.h>
#include <dshow.h>
#include <Mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>
#include <Audiopolicy.h>
#include <Audioclient.h>
#include "Noise_Gen.h"

#define REFTIMES_PER_SEC  10000000
#define REFTIMES_PER_MILLISEC  10000
#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);

HRESULT PlayAudioStream(Noise_Gen* pMySource) {
	HRESULT hr;
	REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
	REFERENCE_TIME hnsActualDuration;
	IMMDeviceEnumerator* pEnumerator = NULL;
	IMMDevice* pDevice = NULL;
	IAudioClient* pAudioClient = NULL;
	IAudioRenderClient* pRenderClient = NULL;
	WAVEFORMATEX* pwfx = NULL;
	UINT32 bufferFrameCount;
	UINT32 numFramesAvailable;
	UINT32 numFramesPadding;
	BYTE* pData;
	DWORD flags = 0;
	IPropertyStore* pPropertyStore = NULL;
	PROPVARIANT name;

	hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL,
						  CLSCTX_ALL, IID_IMMDeviceEnumerator,
						  (void**) &pEnumerator);
	EXIT_ON_ERROR(hr);
	hr = pEnumerator->GetDefaultAudioEndpoint(
		eRender, eConsole, &pDevice);

	hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
	PropVariantInit(&name);
	hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &name);
	printf("%S", name.pwszVal);
	printf("\n");
	EXIT_ON_ERROR(hr);
	hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL,
						   NULL, (void**) &pAudioClient);
	EXIT_ON_ERROR(hr);
	hr = pAudioClient->GetMixFormat(&pwfx);
	EXIT_ON_ERROR(hr);
	hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
								  0, hnsRequestedDuration,
								  0, pwfx, NULL);
	EXIT_ON_ERROR(hr);
	hr = pMySource->SetFormat(pwfx);
	EXIT_ON_ERROR(hr);
	hr = pAudioClient->GetBufferSize(&bufferFrameCount);
	EXIT_ON_ERROR(hr);
	hr = pAudioClient->GetService(IID_IAudioRenderClient,
								  (void**) &pRenderClient);
	EXIT_ON_ERROR(hr);
	hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
	EXIT_ON_ERROR(hr);
	hr = pMySource->LoadData(bufferFrameCount, pData, &flags);
	EXIT_ON_ERROR(hr);
	hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
	EXIT_ON_ERROR(hr);
	hnsActualDuration = (double) REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
	hr = pAudioClient->Start();  // Start playing.
	EXIT_ON_ERROR(hr);
	while(flags != AUDCLNT_BUFFERFLAGS_SILENT) {
		Sleep((DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
		hr = pAudioClient->GetCurrentPadding(&numFramesPadding);
		EXIT_ON_ERROR(hr);
		numFramesAvailable = bufferFrameCount - numFramesPadding;
		hr = pRenderClient->GetBuffer(numFramesAvailable, &pData);
		EXIT_ON_ERROR(hr);
		hr = pMySource->LoadData(numFramesAvailable, pData, &flags);
		EXIT_ON_ERROR(hr);
		hr = pRenderClient->ReleaseBuffer(numFramesAvailable, flags);
		EXIT_ON_ERROR(hr);
	}
	Sleep((DWORD) (hnsActualDuration / REFTIMES_PER_MILLISEC / 2));
	hr = pAudioClient->Stop();  // Stop playing.
	EXIT_ON_ERROR(hr);
Exit:
	CoTaskMemFree(pwfx);
	SAFE_RELEASE(pEnumerator);
	SAFE_RELEASE(pDevice);
	SAFE_RELEASE(pAudioClient);
	SAFE_RELEASE(pRenderClient);
	return hr;
}

int main() {
	HRESULT hr = CoInitialize(nullptr);
	if(FAILED(hr)) { return hr; }
	Noise_Gen* ng = new Noise_Gen;
	PlayAudioStream(ng);
	CoUninitialize();
}


Here is the header and source used to generate the noise and write it to the buffer provided by the system's default audio endpoint.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#pragma once

#include <functional>
#include <random>

template <typename T>
class Random {
public:
	Random(T low, T high) :function(std::bind(std::uniform_real_distribution<>(low, high), std::default_random_engine())) {}

	T operator()() { return function(); }

private:
	std::function<T()> function;
};

class Noise_Gen {

public:

	Noise_Gen() : rd(NULL) {};

	~Noise_Gen() {
		if(rd != NULL) {
			delete rd;
		}
	};

	HRESULT SetFormat(WAVEFORMATEX*);

	HRESULT LoadData(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags);

private:
	void* rd;

	WORD nChannels;
	DWORD nSamplesPerSec;
	DWORD nAvgBytesPerSec;
	WORD nByteAlign;
	WORD wBitsPerSample;

	WORD wValidBitsPerSample;
	WORD wSamplesPerBlock;
	DWORD dwChannelMask;
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <Audiopolicy.h>
#include <Audioclient.h>
#include "Noise_Gen.h"

HRESULT Noise_Gen::SetFormat(WAVEFORMATEX* format) {
	nChannels = format->nChannels;
	nSamplesPerSec = format->nSamplesPerSec;
	nAvgBytesPerSec = format->nAvgBytesPerSec;
	nByteAlign = format->nBlockAlign;
	wBitsPerSample = format->wBitsPerSample;
	double amplitude = std::pow(2.0, wBitsPerSample) - 1;
	switch(wBitsPerSample / 8) {
	case(1):
		rd = new Random<unsigned __int8>(0.0, amplitude);
		break;
	case(2): 
		rd = new Random<unsigned __int16>(0.0, amplitude);
		break;
	case(3):
		rd = new Random<unsigned __int32>(0.0, amplitude);
		break;
	case(4): 
		rd = new Random<unsigned __int32>(0.0, amplitude);
		break;
	case(5): 
		rd = new Random<unsigned __int64>(0.0, amplitude);
		break;
	case(6):
		rd = new Random<unsigned __int64>(0.0, amplitude);
		break;
	case(7): 
		rd = new Random<unsigned __int64>(0.0, amplitude);
		break;
	case(8):
		rd = new Random<unsigned __int64>(0.0, amplitude);
		break;
	default:
		return E_NOTIMPL;
	}
	WORD  wFormatTag = format->wFormatTag;
	if(wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
		WAVEFORMATEXTENSIBLE* pWFE = reinterpret_cast<WAVEFORMATEXTENSIBLE*>(format);
		wValidBitsPerSample = pWFE->Samples.wValidBitsPerSample;
		wSamplesPerBlock = pWFE->Samples.wSamplesPerBlock;
		dwChannelMask = pWFE->dwChannelMask;
	}
	return S_OK;
}

HRESULT Noise_Gen::LoadData(UINT32 bufferFrameCount, BYTE* pData, DWORD* flags) {
	for(UINT32 i = 0; i < nChannels *bufferFrameCount; i++) {
		switch(wBitsPerSample / 8) {
		case(1):
			pData[i] = (((Random<unsigned __int8>*)rd)->operator()());
			break;
		case(2):{
			unsigned __int16* pData2 = (unsigned __int16*) pData;
			pData2[i] = (((Random<unsigned __int16>*)rd)->operator()());
			break;
		}
		case(3): {
			__int32 data = ((Random<unsigned __int32>*)rd)->operator()();
			unsigned char* cp = (unsigned char*) (data);
			pData[(3 * i)] = cp[0];
			pData[1 + (3 * i)] = cp[1];
			pData[2 + (3 * i)] = cp[2];
			break;
		}
		case(4):{
			unsigned __int32* pData2 = (unsigned __int32*) pData;
			pData2[i] = (((Random<unsigned __int32>*)rd)->operator()());
			break;
		}
		case(5): {
			__int64 data = ((Random<unsigned __int64>*)rd)->operator()();
			unsigned char* cp = (unsigned char*) data;
			pData[(5 * i)] = cp[0];
			pData[1 + (5 * i)] = cp[1];
			pData[2 + (5 * i)] = cp[2];
			pData[3 + (5 * i)] = cp[3];
			pData[4 + (5 * i)] = cp[4];
			break;
		}
		case(6): {
			__int64 data = ((Random<unsigned __int64>*)rd)->operator()();
			unsigned char* cp = (unsigned char*) data;
			pData[(6 * i)] = cp[0];
			pData[1 + (6 * i)] = cp[1];
			pData[2 + (6 * i)] = cp[2];
			pData[3 + (6 * i)] = cp[3];
			pData[4 + (6 * i)] = cp[4];
			pData[5 + (6 * i)] = cp[5];
			break;
		}
		case(7): {
			__int64 data = ((Random<unsigned __int64>*)rd)->operator()();
			unsigned char* cp = (unsigned char*) data;
			pData[(7 * i)] = cp[0];
			pData[1 + (7 * i)] = cp[1];
			pData[2 + (7 * i)] = cp[2];
			pData[3 + (7 * i)] = cp[3];
			pData[4 + (7 * i)] = cp[4];
			pData[5 + (7 * i)] = cp[5];
			pData[6 + (7 * i)] = cp[6];
			break;
		}
		case(8): {
			unsigned __int64* pData2 = (unsigned __int64*) pData;
			pData2[i] = (((Random<unsigned __int64>*)rd)->operator()());
			break;
		}
		default:
			// For stopping playback
			(*flags) = AUDCLNT_BUFFERFLAGS_SILENT;
			return E_NOTIMPL;
		}
	}
	return S_OK;
}


I have tried unsigned and signed values. I have verified the speaker's buffer is being written to both by writing it's name to cmd, and seeing my app in the volume mixer. I have also debugged and see that the values being generated are indeed being written to pData. The volume mixer does not show sound being played though.

What is the error?
I had to check the format subtype. It was IEEE_FLOAT, so I had to use float values from -1 to 1.
Registered users can post here. Sign in or register to post.