pref: add sound transcoder cache
This commit is contained in:
parent
03c24091c7
commit
c061c8c802
|
|
@ -22,11 +22,13 @@
|
||||||
#include <kiwano-audio/libraries.h>
|
#include <kiwano-audio/libraries.h>
|
||||||
#include <kiwano/core/Exception.h>
|
#include <kiwano/core/Exception.h>
|
||||||
#include <kiwano/utils/Logger.h>
|
#include <kiwano/utils/Logger.h>
|
||||||
|
#include <kiwano/platform/FileSystem.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
AudioModule::AudioModule()
|
AudioModule::AudioModule()
|
||||||
: x_audio2_(nullptr)
|
: x_audio2_(nullptr)
|
||||||
, mastering_voice_(nullptr)
|
, mastering_voice_(nullptr)
|
||||||
|
|
@ -58,6 +60,8 @@ void AudioModule::DestroyModule()
|
||||||
{
|
{
|
||||||
KGE_DEBUG_LOGF("Destroying audio resources");
|
KGE_DEBUG_LOGF("Destroying audio resources");
|
||||||
|
|
||||||
|
TranscoderCache::GetInstance().Clear();
|
||||||
|
|
||||||
if (mastering_voice_)
|
if (mastering_voice_)
|
||||||
{
|
{
|
||||||
mastering_voice_->DestroyVoice();
|
mastering_voice_->DestroyVoice();
|
||||||
|
|
@ -73,12 +77,45 @@ void AudioModule::DestroyModule()
|
||||||
dlls::MediaFoundation::Get().MFShutdown();
|
dlls::MediaFoundation::Get().MFShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
TranscoderPtr AudioModule::CreateTranscoder(const String& file_path)
|
||||||
|
{
|
||||||
|
if (!FileSystem::GetInstance().IsFileExists(file_path))
|
||||||
|
{
|
||||||
|
KGE_WARNF("Media file '%s' not found", file_path.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
|
||||||
|
|
||||||
|
auto ptr = MakePtr<Transcoder>();
|
||||||
|
HRESULT hr = ptr->LoadMediaFile(full_path);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Load media file failed with HRESULT of %08X", hr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TranscoderPtr AudioModule::CreateTranscoder(const Resource& res)
|
||||||
|
{
|
||||||
|
auto ptr = MakePtr<Transcoder>();
|
||||||
|
HRESULT hr = ptr->LoadMediaResource(res);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioModule::CreateSound(Sound& sound, TranscoderPtr transcoder)
|
||||||
{
|
{
|
||||||
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
auto buffer = transcoder->GetBuffer();
|
||||||
if (buffer.format == nullptr)
|
if (buffer.format == nullptr)
|
||||||
hr = E_INVALIDARG;
|
hr = E_INVALIDARG;
|
||||||
|
|
||||||
|
|
@ -90,14 +127,8 @@ bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
IXAudio2SourceVoice* old = sound.GetXAudio2Voice();
|
sound.Close();
|
||||||
if (old)
|
sound.SetNative(voice);
|
||||||
{
|
|
||||||
old->DestroyVoice();
|
|
||||||
old = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sound.SetXAudio2Voice(voice);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,16 @@ public:
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 从解码器数据缓冲中创建音频对象
|
/// @brief 创建音频解码器
|
||||||
bool CreateSound(Sound& sound, const Transcoder::Buffer& buffer);
|
TranscoderPtr CreateTranscoder(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建音频解码器
|
||||||
|
TranscoderPtr CreateTranscoder(const Resource& res);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建音频
|
||||||
|
bool CreateSound(Sound& sound, TranscoderPtr transcoder);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SetupModule() override;
|
void SetupModule() override;
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,50 @@
|
||||||
#include <kiwano-audio/AudioModule.h>
|
#include <kiwano-audio/AudioModule.h>
|
||||||
#include <kiwano-audio/Sound.h>
|
#include <kiwano-audio/Sound.h>
|
||||||
#include <kiwano/utils/Logger.h>
|
#include <kiwano/utils/Logger.h>
|
||||||
#include <kiwano/platform/FileSystem.h>
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
|
SoundPtr Sound::Preload(const String& file_path)
|
||||||
|
{
|
||||||
|
auto ptr = MakePtr<Sound>();
|
||||||
|
|
||||||
|
size_t hash_code = std::hash<String>{}(file_path);
|
||||||
|
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||||
|
{
|
||||||
|
if (ptr->Load(transcoder))
|
||||||
|
return ptr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr && ptr->Load(file_path))
|
||||||
|
{
|
||||||
|
TranscoderCache::GetInstance().Add(hash_code, ptr->coder_);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundPtr Sound::Preload(const Resource& res)
|
||||||
|
{
|
||||||
|
auto ptr = MakePtr<Sound>();
|
||||||
|
|
||||||
|
size_t hash_code = res.GetId();
|
||||||
|
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||||
|
{
|
||||||
|
if (ptr->Load(transcoder))
|
||||||
|
return ptr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr && ptr->Load(res))
|
||||||
|
{
|
||||||
|
TranscoderCache::GetInstance().Add(hash_code, ptr->coder_);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
Sound::Sound(const String& file_path)
|
Sound::Sound(const String& file_path)
|
||||||
: Sound()
|
: Sound()
|
||||||
{
|
{
|
||||||
|
|
@ -42,7 +80,6 @@ Sound::Sound(const Resource& res)
|
||||||
Sound::Sound()
|
Sound::Sound()
|
||||||
: opened_(false)
|
: opened_(false)
|
||||||
, playing_(false)
|
, playing_(false)
|
||||||
, voice_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,34 +90,17 @@ Sound::~Sound()
|
||||||
|
|
||||||
bool Sound::Load(const String& file_path)
|
bool Sound::Load(const String& file_path)
|
||||||
{
|
{
|
||||||
if (!FileSystem::GetInstance().IsFileExists(file_path))
|
|
||||||
{
|
|
||||||
KGE_WARNF("Media file '%s' not found", file_path.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opened_)
|
if (opened_)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
|
TranscoderPtr transcoder = AudioModule::GetInstance().CreateTranscoder(file_path);
|
||||||
|
if (!transcoder)
|
||||||
HRESULT hr = transcoder_.LoadMediaFile(full_path);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
{
|
||||||
KGE_ERRORF("Load media file failed with HRESULT of %08X", hr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return Load(transcoder);
|
||||||
if (!AudioModule::GetInstance().CreateSound(*this, transcoder_.GetBuffer()))
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sound::Load(const Resource& res)
|
bool Sound::Load(const Resource& res)
|
||||||
|
|
@ -90,26 +110,28 @@ bool Sound::Load(const Resource& res)
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr = transcoder_.LoadMediaResource(res);
|
TranscoderPtr transcoder = AudioModule::GetInstance().CreateTranscoder(res);
|
||||||
if (FAILED(hr))
|
if (!transcoder)
|
||||||
{
|
{
|
||||||
KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return Load(transcoder);
|
||||||
if (!AudioModule::GetInstance().CreateSound(*this, transcoder_.GetBuffer()))
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sound::IsValid() const
|
bool Sound::Load(TranscoderPtr transcoder)
|
||||||
{
|
{
|
||||||
return voice_ != nullptr;
|
if (opened_)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
if (!AudioModule::GetInstance().CreateSound(*this, transcoder))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
coder_ = transcoder;
|
||||||
|
opened_ = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Play(int loop_count)
|
void Sound::Play(int loop_count)
|
||||||
|
|
@ -120,29 +142,30 @@ void Sound::Play(int loop_count)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
// if sound stream is not empty, stop() will clear it
|
// if sound stream is not empty, stop() will clear it
|
||||||
XAUDIO2_VOICE_STATE state;
|
XAUDIO2_VOICE_STATE state;
|
||||||
voice_->GetState(&state);
|
voice->GetState(&state);
|
||||||
if (state.BuffersQueued)
|
if (state.BuffersQueued)
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
// clamp loop count
|
// clamp loop count
|
||||||
loop_count = (loop_count < 0) ? XAUDIO2_LOOP_INFINITE : std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
|
loop_count = (loop_count < 0) ? XAUDIO2_LOOP_INFINITE : std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
|
||||||
|
|
||||||
auto wave_buffer = transcoder_.GetBuffer();
|
auto buffer = coder_->GetBuffer();
|
||||||
|
|
||||||
XAUDIO2_BUFFER buffer = { 0 };
|
XAUDIO2_BUFFER xaudio2_buffer = { 0 };
|
||||||
buffer.pAudioData = wave_buffer.data;
|
xaudio2_buffer.pAudioData = buffer.data;
|
||||||
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
xaudio2_buffer.Flags = XAUDIO2_END_OF_STREAM;
|
||||||
buffer.AudioBytes = wave_buffer.size;
|
xaudio2_buffer.AudioBytes = buffer.size;
|
||||||
buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
xaudio2_buffer.LoopCount = static_cast<uint32_t>(loop_count);
|
||||||
|
|
||||||
HRESULT hr = voice_->SubmitSourceBuffer(&buffer);
|
HRESULT hr = voice->SubmitSourceBuffer(&xaudio2_buffer);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
hr = voice_->Start();
|
hr = voice->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
|
|
@ -155,31 +178,34 @@ void Sound::Play(int loop_count)
|
||||||
|
|
||||||
void Sound::Pause()
|
void Sound::Pause()
|
||||||
{
|
{
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
if (SUCCEEDED(voice_->Stop()))
|
if (SUCCEEDED(voice->Stop()))
|
||||||
playing_ = false;
|
playing_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Resume()
|
void Sound::Resume()
|
||||||
{
|
{
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
if (SUCCEEDED(voice_->Start()))
|
if (SUCCEEDED(voice->Start()))
|
||||||
playing_ = true;
|
playing_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Stop()
|
void Sound::Stop()
|
||||||
{
|
{
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
HRESULT hr = voice_->Stop();
|
HRESULT hr = voice->Stop();
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = voice_->ExitLoop();
|
hr = voice->ExitLoop();
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = voice_->FlushSourceBuffers();
|
hr = voice->FlushSourceBuffers();
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
playing_ = false;
|
playing_ = false;
|
||||||
|
|
@ -187,16 +213,15 @@ void Sound::Stop()
|
||||||
|
|
||||||
void Sound::Close()
|
void Sound::Close()
|
||||||
{
|
{
|
||||||
if (voice_)
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
if (voice)
|
||||||
{
|
{
|
||||||
voice_->Stop();
|
voice->Stop();
|
||||||
voice_->FlushSourceBuffers();
|
voice->FlushSourceBuffers();
|
||||||
voice_->DestroyVoice();
|
voice->DestroyVoice();
|
||||||
voice_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transcoder_.ClearBuffer();
|
coder_ = nullptr;
|
||||||
|
|
||||||
opened_ = false;
|
opened_ = false;
|
||||||
playing_ = false;
|
playing_ = false;
|
||||||
}
|
}
|
||||||
|
|
@ -205,14 +230,15 @@ bool Sound::IsPlaying() const
|
||||||
{
|
{
|
||||||
if (opened_)
|
if (opened_)
|
||||||
{
|
{
|
||||||
if (!voice_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!playing_)
|
if (!playing_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
if (!voice)
|
||||||
|
return false;
|
||||||
|
|
||||||
XAUDIO2_VOICE_STATE state;
|
XAUDIO2_VOICE_STATE state;
|
||||||
voice_->GetState(&state);
|
voice->GetState(&state);
|
||||||
return !!state.BuffersQueued;
|
return !!state.BuffersQueued;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -220,19 +246,21 @@ bool Sound::IsPlaying() const
|
||||||
|
|
||||||
float Sound::GetVolume() const
|
float Sound::GetVolume() const
|
||||||
{
|
{
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
float volume = 0.0f;
|
float volume = 0.0f;
|
||||||
voice_->GetVolume(&volume);
|
voice->GetVolume(&volume);
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::SetVolume(float volume)
|
void Sound::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
KGE_ASSERT(voice_ != nullptr && "IXAudio2SourceVoice* is NULL");
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
volume = std::min(std::max(volume, -XAUDIO2_MAX_VOLUME_LEVEL), XAUDIO2_MAX_VOLUME_LEVEL);
|
volume = std::min(std::max(volume, -XAUDIO2_MAX_VOLUME_LEVEL), XAUDIO2_MAX_VOLUME_LEVEL);
|
||||||
voice_->SetVolume(volume);
|
voice->SetVolume(volume);
|
||||||
}
|
}
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano-audio/Transcoder.h>
|
#include <kiwano-audio/Transcoder.h>
|
||||||
#include <kiwano/core/Resource.h>
|
#include <kiwano/core/Resource.h>
|
||||||
#include <kiwano/base/ObjectBase.h>
|
#include <kiwano/platform/NativeObject.hpp>
|
||||||
#include <xaudio2.h>
|
#include <xaudio2.h>
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
|
|
@ -41,11 +41,19 @@ KGE_DECLARE_SMART_PTR(Sound);
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频对象
|
* @brief 音频对象
|
||||||
*/
|
*/
|
||||||
class KGE_API Sound : public ObjectBase
|
class KGE_API Sound : public NativeObject
|
||||||
{
|
{
|
||||||
friend class AudioModule;
|
friend class AudioModule;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief Ô¤¼ÓÔØÒôƵ
|
||||||
|
static SoundPtr Preload(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief Ô¤¼ÓÔØÒôƵ×ÊÔ´
|
||||||
|
static SoundPtr Preload(const Resource& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 创建音频对象
|
/// @brief 创建音频对象
|
||||||
/// @param res 本地音频文件路径
|
/// @param res 本地音频文件路径
|
||||||
|
|
@ -71,8 +79,9 @@ public:
|
||||||
bool Load(const Resource& res);
|
bool Load(const Resource& res);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief ÊÇ·ñÓÐЧ
|
/// @brief ´ò¿ªÒôƵ×ÊÔ´
|
||||||
bool IsValid() const;
|
/// @param res ÒôƵ×ÊÔ´
|
||||||
|
bool Load(TranscoderPtr transcoder);
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 播放
|
/// @brief 播放
|
||||||
|
|
@ -109,27 +118,12 @@ public:
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IXAudio2SourceVoice* GetXAudio2Voice() const;
|
bool opened_;
|
||||||
|
bool playing_;
|
||||||
void SetXAudio2Voice(IXAudio2SourceVoice* voice);
|
TranscoderPtr coder_;
|
||||||
|
|
||||||
private:
|
|
||||||
bool opened_;
|
|
||||||
bool playing_;
|
|
||||||
Transcoder transcoder_;
|
|
||||||
IXAudio2SourceVoice* voice_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
inline IXAudio2SourceVoice* Sound::GetXAudio2Voice() const
|
|
||||||
{
|
|
||||||
return voice_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Sound::SetXAudio2Voice(IXAudio2SourceVoice* voice)
|
|
||||||
{
|
|
||||||
voice_ = voice;
|
|
||||||
}
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/Resource.h>
|
#include <kiwano/core/Resource.h>
|
||||||
|
#include <kiwano/base/ObjectBase.h>
|
||||||
#include <mfapi.h>
|
#include <mfapi.h>
|
||||||
#include <mfidl.h>
|
#include <mfidl.h>
|
||||||
#include <mfreadwrite.h>
|
#include <mfreadwrite.h>
|
||||||
|
|
@ -28,7 +29,9 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
class Sound;
|
class AudioModule;
|
||||||
|
|
||||||
|
KGE_DECLARE_SMART_PTR(Transcoder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \addtogroup Audio
|
||||||
|
|
@ -39,9 +42,9 @@ class Sound;
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频解码器
|
* @brief 音频解码器
|
||||||
*/
|
*/
|
||||||
class KGE_API Transcoder
|
class KGE_API Transcoder : public ObjectBase
|
||||||
{
|
{
|
||||||
friend class Sound;
|
friend class AudioModule;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -86,6 +89,56 @@ private:
|
||||||
WAVEFORMATEX* wave_format_;
|
WAVEFORMATEX* wave_format_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class KGE_API TranscoderCache final : public Singleton<TranscoderCache>
|
||||||
|
{
|
||||||
|
friend Singleton<TranscoderCache>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 警속뻠닸
|
||||||
|
inline void Add(size_t key, TranscoderPtr v)
|
||||||
|
{
|
||||||
|
cache_.insert(std::make_pair(key, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 삿혤뻠닸
|
||||||
|
inline TranscoderPtr Get(size_t key) const
|
||||||
|
{
|
||||||
|
if (cache_.count(key))
|
||||||
|
{
|
||||||
|
return cache_.at(key);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 盧뇜뻠닸
|
||||||
|
inline void Remove(size_t key)
|
||||||
|
{
|
||||||
|
cache_.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 헌왕뻠닸
|
||||||
|
inline void Clear()
|
||||||
|
{
|
||||||
|
cache_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
~TranscoderCache()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TranscoderCache() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UnorderedMap<size_t, TranscoderPtr> cache_;
|
||||||
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue