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 120 121 122 123 124 125 126 127 128 129 130 131
|
/*
* Copyright (C) 2010-2018 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
#pragma once
#include "cores/AudioEngine/Interfaces/AESink.h"
#include "cores/AudioEngine/Utils/AEDeviceInfo.h"
#include <stdint.h>
#include <mmdeviceapi.h>
#include <ppltasks.h>
#include <wrl/implements.h>
#include <x3daudio.h>
#include <xapofx.h>
#include <xaudio2.h>
#include <xaudio2fx.h>
#pragma comment(lib,"xaudio2.lib")
class CAESinkXAudio : public IAESink
{
public:
virtual const char *GetName() { return "XAudio"; }
CAESinkXAudio();
virtual ~CAESinkXAudio();
static void Register();
static IAESink* Create(std::string &device, AEAudioFormat &desiredFormat);
bool Initialize (AEAudioFormat &format, std::string &device) override;
void Deinitialize() override;
void GetDelay(AEDelayStatus& status) override;
double GetCacheTotal() override;
double GetLatency() override;
unsigned int AddPackets(uint8_t **data, unsigned int frames, unsigned int offset) override;
void Drain() override;
static void EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force = false);
private:
struct buffer_ctx
{
uint8_t *data;
uint32_t frames;
CAESinkXAudio* sink;
~buffer_ctx()
{
delete[] data;
sink->m_framesInBuffers -= frames;
sink = nullptr;
}
};
struct VoiceCallback : public IXAudio2VoiceCallback
{
VoiceCallback()
{
mBufferEnd.reset(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE));
if (!mBufferEnd)
{
throw std::exception("CreateEvent");
}
}
virtual ~VoiceCallback() { }
STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) override {}
STDMETHOD_(void, OnVoiceProcessingPassEnd)() override {}
STDMETHOD_(void, OnStreamEnd)() override {}
STDMETHOD_(void, OnBufferStart)(void*) override {}
STDMETHOD_(void, OnBufferEnd)(void* context) override
{
SetEvent(mBufferEnd.get());
struct buffer_ctx *ctx = static_cast<struct buffer_ctx*>(context);
delete ctx;
}
STDMETHOD_(void, OnLoopEnd)(void*) override {}
STDMETHOD_(void, OnVoiceError)(void*, HRESULT) override {}
struct handle_closer
{
void operator()(HANDLE h) const
{
assert(h != INVALID_HANDLE_VALUE);
if (h)
CloseHandle(h);
}
};
std::unique_ptr<void, handle_closer> mBufferEnd;
};
bool InitializeInternal(std::string deviceId, AEAudioFormat &format);
bool IsUSBDevice();
Microsoft::WRL::ComPtr<IXAudio2> m_xAudio2;
IXAudio2MasteringVoice* m_masterVoice;
IXAudio2SourceVoice* m_sourceVoice;
VoiceCallback m_voiceCallback;
AEAudioFormat m_format;
unsigned int m_encodedChannels;
unsigned int m_encodedSampleRate;
CAEChannelInfo m_channelLayout;
std::string m_device;
enum AEDataFormat sinkReqFormat;
enum AEDataFormat sinkRetFormat;
unsigned int m_uiBufferLen; /* xaudio endpoint buffer size, in frames */
unsigned int m_AvgBytesPerSec;
unsigned int m_dwChunkSize;
unsigned int m_dwFrameSize;
unsigned int m_dwBufferLen;
uint64_t m_sinkFrames;
std::atomic<uint16_t> m_framesInBuffers;
double m_avgTimeWaiting; /* time between next buffer of data from SoftAE and driver call for data */
bool m_running;
bool m_initialized;
bool m_isSuspended; /* sink is in a suspended state - release audio device */
bool m_isDirty; /* sink output failed - needs re-init or new device */
};
|