Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/WASAPIContext.h
3185 views
1
#pragma once
2
3
#include "Audio/AudioBackend.h"
4
#include <atomic>
5
6
#include <windows.h>
7
#include <mmdeviceapi.h>
8
#include <audioclient.h>
9
#include <thread>
10
#include <string>
11
#include <string_view>
12
#include <wrl/client.h>
13
14
class WASAPIContext : public AudioBackend {
15
public:
16
WASAPIContext();
17
~WASAPIContext();
18
19
void SetRenderCallback(RenderCallback callback, void *userdata) override {
20
callback_ = callback;
21
userdata_ = userdata;
22
}
23
24
void EnumerateDevices(std::vector<AudioDeviceDesc> *outputDevices, bool captureDevices = false) override;
25
26
bool InitOutputDevice(std::string_view uniqueId, LatencyMode latencyMode, bool *revertedToDefault) override;
27
28
void FrameUpdate(bool allowAutoChange) override;
29
30
int PeriodFrames() const override { return actualPeriodFrames_; } // NOTE: This may have the wrong value (too large) until audio has started playing.
31
int BufferSize() const override { return reportedBufferSize_; }
32
int SampleRate() const override { return format_->nSamplesPerSec; }
33
34
// Implements device change notifications
35
class DeviceNotificationClient : public IMMNotificationClient {
36
public:
37
DeviceNotificationClient(WASAPIContext *engine) : engine_(engine) {}
38
ULONG STDMETHODCALLTYPE AddRef() override { return 1; }
39
ULONG STDMETHODCALLTYPE Release() override { return 1; }
40
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppv) override {
41
if (iid == __uuidof(IUnknown) || iid == __uuidof(IMMNotificationClient)) {
42
*ppv = static_cast<IMMNotificationClient*>(this);
43
return S_OK;
44
}
45
*ppv = nullptr;
46
return E_NOINTERFACE;
47
}
48
49
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) override {
50
if (flow == eRender && role == eConsole) {
51
// PostMessage(hwnd, WM_APP + 1, 0, 0);
52
engine_->defaultDeviceChanged_ = true;
53
}
54
return S_OK;
55
}
56
57
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR) override { return S_OK; }
58
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR) override { return S_OK; }
59
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) override { return S_OK; }
60
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override { return S_OK; }
61
private:
62
WASAPIContext *engine_;
63
};
64
65
void DescribeOutputFormat(char *buffer, size_t bufferSize) const override;
66
67
private:
68
void Start();
69
void Stop();
70
71
void AudioLoop();
72
73
enum class AudioFormat {
74
Float,
75
S16,
76
Unhandled,
77
};
78
static AudioFormat Classify(const WAVEFORMATEX *format);
79
80
// Only one of these can be non-null at a time. Check audioClient3 to determine if it's being used.
81
Microsoft::WRL::ComPtr<IAudioClient3> audioClient3_;
82
Microsoft::WRL::ComPtr<IAudioClient> audioClient_;
83
84
Microsoft::WRL::ComPtr<IAudioRenderClient> renderClient_;
85
WAVEFORMATEX *format_ = nullptr;
86
HANDLE audioEvent_ = nullptr;
87
std::thread audioThread_;
88
UINT32 defaultPeriodFrames = 0, fundamentalPeriodFrames = 0, minPeriodFrames = 0, maxPeriodFrames = 0;
89
std::atomic<bool> running_ = true;
90
UINT32 actualPeriodFrames_ = 0; // may not be the requested.
91
UINT32 reportedBufferSize_ = 0;
92
Microsoft::WRL::ComPtr<IMMDeviceEnumerator> enumerator_;
93
DeviceNotificationClient notificationClient_;
94
RenderCallback callback_{};
95
void *userdata_ = nullptr;
96
LatencyMode latencyMode_ = LatencyMode::Aggressive;
97
std::string deviceId_;
98
std::atomic<bool> defaultDeviceChanged_{};
99
100
float *tempBuf_ = nullptr;
101
};
102
103