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.
11 #include "cores/AudioEngine/Interfaces/AESink.h"
12 #include "cores/AudioEngine/Utils/AEDeviceInfo.h"
19 #include <xaudio2fx.h>
21 class CAESinkXAudio
: public IAESink
24 virtual const char *GetName() { return "XAudio"; }
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);
53 sink
->m_framesInBuffers
-= frames
;
58 struct VoiceCallback
: public IXAudio2VoiceCallback
62 mBufferEnd
.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE
| SYNCHRONIZE
));
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
);
94 STDMETHOD_(void, OnLoopEnd
)(void*) override
{}
95 STDMETHOD_(void, OnVoiceError
)(void*, HRESULT
) override
{}
99 void operator()(HANDLE h
) const
101 assert(h
!= INVALID_HANDLE_VALUE
);
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