[XAudio2] share Xbox audio device enumeration with desktop and Windows 8.1 compatibility
[xbmc.git] / xbmc / cores / AudioEngine / Sinks / AESinkXAudio.h
blob1335714d09d74133c2352bad1b227aa4ef86e8c7
1 /*
2 * Copyright (C) 2010-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #pragma once
11 #include "cores/AudioEngine/Interfaces/AESink.h"
12 #include "cores/AudioEngine/Utils/AEDeviceInfo.h"
14 #include <stdint.h>
16 #include <x3daudio.h>
17 #include <xapofx.h>
18 #include <xaudio2.h>
19 #include <xaudio2fx.h>
21 class CAESinkXAudio : public IAESink
23 public:
24 virtual const char *GetName() { return "XAudio"; }
26 CAESinkXAudio();
27 virtual ~CAESinkXAudio();
29 static void Register();
30 static std::unique_ptr<IAESink> Create(std::string& device, AEAudioFormat& desiredFormat);
32 bool Initialize (AEAudioFormat &format, std::string &device) override;
33 void Deinitialize() override;
35 void GetDelay(AEDelayStatus& status) override;
36 double GetCacheTotal() override;
37 double GetLatency() override;
38 unsigned int AddPackets(uint8_t **data, unsigned int frames, unsigned int offset) override;
39 void Drain() override;
41 static void EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force = false);
43 private:
44 struct buffer_ctx
46 uint8_t *data;
47 uint32_t frames;
48 CAESinkXAudio* sink;
50 ~buffer_ctx()
52 delete[] data;
53 sink->m_framesInBuffers -= frames;
54 sink = nullptr;
58 struct VoiceCallback : public IXAudio2VoiceCallback
60 VoiceCallback()
62 mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));
63 if (!mBufferEnd)
65 throw std::exception("CreateEventEx BufferEnd");
67 if (NULL == (m_StreamEndEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET,
68 EVENT_MODIFY_STATE | SYNCHRONIZE)))
70 throw std::exception("CreateEventEx StreamEnd");
73 virtual ~VoiceCallback()
75 if (m_StreamEndEvent != NULL)
76 CloseHandle(m_StreamEndEvent);
79 STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) override {}
80 STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}
81 STDMETHOD_(void, OnStreamEnd)() override
83 if (m_StreamEndEvent != NULL)
84 SetEvent(m_StreamEndEvent);
86 STDMETHOD_(void, OnBufferStart)(void*) override {}
87 STDMETHOD_(void, OnBufferEnd)(void* context) override
89 SetEvent(mBufferEnd.get());
90 struct buffer_ctx *ctx = static_cast<struct buffer_ctx*>(context);
91 delete ctx;
94 STDMETHOD_(void, OnLoopEnd)(void*) override {}
95 STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override {}
97 struct handle_closer
99 void operator()(HANDLE h) const
101 assert(h != INVALID_HANDLE_VALUE);
102 if (h)
103 CloseHandle(h);
106 std::unique_ptr<void, handle_closer> mBufferEnd;
107 HANDLE m_StreamEndEvent{0};
110 bool InitializeInternal(std::string deviceId, AEAudioFormat& format);
113 * \brief Add a 1 frame long buffer with the end of stream flag to the voice.
114 * \return true for success, false for failure
116 bool AddEndOfStreamPacket();
118 * \brief Create a XAUDIO2_BUFFER with a struct buffer_ctx in pContext member, which must
119 * be deleted either manually or by XAudio2 BufferEnd callbak to avoid memory leaks.
120 * \param data data of the frames to copy. if null, the new buffer will contain silence.
121 * \param frames number of frames
122 * \param offset offset from the start in the data buffer.
123 * \return the new buffer
125 XAUDIO2_BUFFER BuildXAudio2Buffer(uint8_t** data, unsigned int frames, unsigned int offset);
127 Microsoft::WRL::ComPtr<IXAudio2> m_xAudio2;
128 IXAudio2MasteringVoice* m_masterVoice{nullptr};
129 IXAudio2SourceVoice* m_sourceVoice{nullptr};
130 VoiceCallback m_voiceCallback;
132 AEAudioFormat m_format;
134 uint64_t m_sinkFrames{0};
135 std::atomic<uint16_t> m_framesInBuffers{0};
137 // time between next buffer of data from SoftAE and driver call for data
138 double m_avgTimeWaiting{50.0};
140 bool m_running{false};
141 bool m_initialized{false};
142 bool m_isSuspended{false}; // sink is in a suspended state - release audio device
143 bool m_isDirty{false}; // sink output failed - needs re-init or new device
145 LARGE_INTEGER m_timerFreq{}; // performance counter frequency for latency calculations