feat: add sound callback
This commit is contained in:
parent
c061c8c802
commit
88c758b47c
|
|
@ -29,6 +29,42 @@ namespace kiwano
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class VoiceCallback : public IXAudio2VoiceCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SoundCallback* cb;
|
||||||
|
|
||||||
|
VoiceCallback(SoundCallback* cb)
|
||||||
|
: cb(cb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~VoiceCallback() {}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnBufferStart(void* pBufferContext))
|
||||||
|
{
|
||||||
|
cb->OnStart(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnLoopEnd(void* pBufferContext))
|
||||||
|
{
|
||||||
|
cb->OnLoopEnd(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnBufferEnd(void* pBufferContext))
|
||||||
|
{
|
||||||
|
cb->OnEnd(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnStreamEnd()) {}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnVoiceProcessingPassEnd()) {}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnVoiceProcessingPassStart(UINT32 SamplesRequired)) {}
|
||||||
|
|
||||||
|
STDMETHOD_(void, OnVoiceError(void* pBufferContext, HRESULT Error)) {}
|
||||||
|
};
|
||||||
|
|
||||||
AudioModule::AudioModule()
|
AudioModule::AudioModule()
|
||||||
: x_audio2_(nullptr)
|
: x_audio2_(nullptr)
|
||||||
, mastering_voice_(nullptr)
|
, mastering_voice_(nullptr)
|
||||||
|
|
@ -121,10 +157,12 @@ bool AudioModule::CreateSound(Sound& sound, TranscoderPtr transcoder)
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
auto chain = sound.GetCallbackChain();
|
||||||
|
chain->SetNative(VoiceCallback{ chain.Get() });
|
||||||
|
auto callback = const_cast<VoiceCallback*>(chain->GetNative().CastPtr<VoiceCallback>());
|
||||||
|
|
||||||
IXAudio2SourceVoice* voice = nullptr;
|
IXAudio2SourceVoice* voice = nullptr;
|
||||||
|
hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, callback);
|
||||||
hr = x_audio2_->CreateSourceVoice(&voice, buffer.format, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
sound.Close();
|
sound.Close();
|
||||||
|
|
@ -143,7 +181,6 @@ bool AudioModule::CreateSound(Sound& sound, TranscoderPtr transcoder)
|
||||||
void AudioModule::Open()
|
void AudioModule::Open()
|
||||||
{
|
{
|
||||||
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
KGE_ASSERT(x_audio2_ && "AudioModule hasn't been initialized!");
|
||||||
|
|
||||||
if (x_audio2_)
|
if (x_audio2_)
|
||||||
x_audio2_->StartEngine();
|
x_audio2_->StartEngine();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,13 @@ namespace kiwano
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
|
|
||||||
SoundPtr Sound::Preload(const String& file_path)
|
SoundPtr Sound::Preload(const String& file_path, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||||
{
|
{
|
||||||
auto ptr = MakePtr<Sound>();
|
auto ptr = MakePtr<Sound>();
|
||||||
|
for (auto& cb : callbacks)
|
||||||
|
{
|
||||||
|
ptr->AddCallback(cb);
|
||||||
|
}
|
||||||
|
|
||||||
size_t hash_code = std::hash<String>{}(file_path);
|
size_t hash_code = std::hash<String>{}(file_path);
|
||||||
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||||
|
|
@ -46,9 +50,13 @@ SoundPtr Sound::Preload(const String& file_path)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundPtr Sound::Preload(const Resource& res)
|
SoundPtr Sound::Preload(const Resource& res, std::initializer_list<SoundCallbackPtr> callbacks)
|
||||||
{
|
{
|
||||||
auto ptr = MakePtr<Sound>();
|
auto ptr = MakePtr<Sound>();
|
||||||
|
for (auto& cb : callbacks)
|
||||||
|
{
|
||||||
|
ptr->AddCallback(cb);
|
||||||
|
}
|
||||||
|
|
||||||
size_t hash_code = res.GetId();
|
size_t hash_code = res.GetId();
|
||||||
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
if (TranscoderPtr transcoder = TranscoderCache::GetInstance().Get(hash_code))
|
||||||
|
|
@ -80,6 +88,7 @@ Sound::Sound(const Resource& res)
|
||||||
Sound::Sound()
|
Sound::Sound()
|
||||||
: opened_(false)
|
: opened_(false)
|
||||||
, playing_(false)
|
, playing_(false)
|
||||||
|
, volume_(1.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,6 +138,11 @@ bool Sound::Load(TranscoderPtr transcoder)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset volume
|
||||||
|
const float old_volume = volume_;
|
||||||
|
volume_ = 0.f;
|
||||||
|
SetVolume(old_volume);
|
||||||
|
|
||||||
coder_ = transcoder;
|
coder_ = transcoder;
|
||||||
opened_ = true;
|
opened_ = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -181,8 +195,14 @@ void Sound::Pause()
|
||||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
if (SUCCEEDED(voice->Stop()))
|
HRESULT hr = voice->Stop();
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
playing_ = false;
|
playing_ = false;
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Pause voice failed with HRESULT of %08X", hr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Resume()
|
void Sound::Resume()
|
||||||
|
|
@ -190,8 +210,14 @@ void Sound::Resume()
|
||||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
if (SUCCEEDED(voice->Start()))
|
HRESULT hr = voice->Start();
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
playing_ = true;
|
playing_ = true;
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Start voice failed with HRESULT of %08X", hr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Stop()
|
void Sound::Stop()
|
||||||
|
|
@ -209,6 +235,11 @@ void Sound::Stop()
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
playing_ = false;
|
playing_ = false;
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_ERRORF("Stop voice failed with HRESULT of %08X", hr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::Close()
|
void Sound::Close()
|
||||||
|
|
@ -246,21 +277,169 @@ bool Sound::IsPlaying() const
|
||||||
|
|
||||||
float Sound::GetVolume() const
|
float Sound::GetVolume() const
|
||||||
{
|
{
|
||||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
return volume_;
|
||||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
|
||||||
|
|
||||||
float volume = 0.0f;
|
|
||||||
voice->GetVolume(&volume);
|
|
||||||
return volume;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::SetVolume(float volume)
|
void Sound::SetVolume(float volume)
|
||||||
{
|
{
|
||||||
|
if (volume_ == volume)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
volume_ = volume;
|
||||||
|
|
||||||
|
float actual_volume = GetCallbackChain()->OnVolumeChanged(this, volume_);
|
||||||
|
|
||||||
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
auto voice = GetNativePtr<IXAudio2SourceVoice>();
|
||||||
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
KGE_ASSERT(voice != nullptr && "IXAudio2SourceVoice* is NULL");
|
||||||
|
|
||||||
volume = std::min(std::max(volume, -XAUDIO2_MAX_VOLUME_LEVEL), XAUDIO2_MAX_VOLUME_LEVEL);
|
actual_volume = std::min(std::max(actual_volume, -XAUDIO2_MAX_VOLUME_LEVEL), XAUDIO2_MAX_VOLUME_LEVEL);
|
||||||
voice->SetVolume(volume);
|
voice->SetVolume(actual_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SoundCallbackPtr Sound::GetCallbackChain()
|
||||||
|
{
|
||||||
|
class SoundCallbackChain : public SoundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sound* sound;
|
||||||
|
|
||||||
|
void OnStart(Sound*) override
|
||||||
|
{
|
||||||
|
for (auto& cb : sound->GetCallbacks())
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb->OnStart(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnLoopEnd(Sound*) override
|
||||||
|
{
|
||||||
|
for (auto& cb : sound->GetCallbacks())
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb->OnLoopEnd(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnd(Sound*) override
|
||||||
|
{
|
||||||
|
for (auto& cb : sound->GetCallbacks())
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb->OnEnd(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float OnVolumeChanged(Sound*, float volume) override
|
||||||
|
{
|
||||||
|
float actual_volume = volume;
|
||||||
|
for (auto& cb : sound->GetCallbacks())
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
actual_volume = cb->OnVolumeChanged(sound, volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actual_volume;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!callback_chain_)
|
||||||
|
{
|
||||||
|
auto chain = MakePtr<SoundCallbackChain>();
|
||||||
|
chain->sound = this;
|
||||||
|
callback_chain_ = chain;
|
||||||
|
}
|
||||||
|
return callback_chain_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundCallbackPtr SoundCallback::OnStart(const Function<void(Sound* sound)>& cb)
|
||||||
|
{
|
||||||
|
class SoundCallbackFunc : public SoundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Function<void(Sound* sound)> cb;
|
||||||
|
|
||||||
|
void OnStart(Sound* sound) override
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||||
|
ptr->cb = cb;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundCallbackPtr SoundCallback::OnLoopEnd(const Function<void(Sound* sound)>& cb)
|
||||||
|
{
|
||||||
|
class SoundCallbackFunc : public SoundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Function<void(Sound* sound)> cb;
|
||||||
|
|
||||||
|
void OnLoopEnd(Sound* sound) override
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||||
|
ptr->cb = cb;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundCallbackPtr SoundCallback::OnEnd(const Function<void(Sound* sound)>& cb)
|
||||||
|
{
|
||||||
|
class SoundCallbackFunc : public SoundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Function<void(Sound* sound)> cb;
|
||||||
|
|
||||||
|
void OnEnd(Sound* sound) override
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||||
|
ptr->cb = cb;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundCallbackPtr SoundCallback::OnVolumeChanged(const Function<float(Sound* sound, float volume)>& cb)
|
||||||
|
{
|
||||||
|
class SoundCallbackFunc : public SoundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Function<float(Sound* sound, float volume)> cb;
|
||||||
|
|
||||||
|
float OnVolumeChanged(Sound* sound, float volume) override
|
||||||
|
{
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
return cb(sound, volume);
|
||||||
|
}
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto ptr = MakePtr<SoundCallbackFunc>();
|
||||||
|
ptr->cb = cb;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,10 @@ namespace kiwano
|
||||||
namespace audio
|
namespace audio
|
||||||
{
|
{
|
||||||
class AudioModule;
|
class AudioModule;
|
||||||
|
class SoundPlayer;
|
||||||
|
|
||||||
KGE_DECLARE_SMART_PTR(Sound);
|
KGE_DECLARE_SMART_PTR(Sound);
|
||||||
|
KGE_DECLARE_SMART_PTR(SoundCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \addtogroup Audio
|
* \addtogroup Audio
|
||||||
|
|
@ -39,20 +41,64 @@ KGE_DECLARE_SMART_PTR(Sound);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 音频对象
|
* @brief 音频回调
|
||||||
|
*/
|
||||||
|
class KGE_API SoundCallback : public NativeObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建一个回调,在音频开始播放时执行
|
||||||
|
static SoundCallbackPtr OnStart(const Function<void(Sound* sound)>& cb);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建一个回调,在音频循环结束时执行
|
||||||
|
static SoundCallbackPtr OnLoopEnd(const Function<void(Sound* sound)>& cb);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建一个回调,在音频结束时执行
|
||||||
|
static SoundCallbackPtr OnEnd(const Function<void(Sound* sound)>& cb);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 创建一个回调,在音频修改音量时执行
|
||||||
|
static SoundCallbackPtr OnVolumeChanged(const Function<float(Sound* sound, float volume)>& cb);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 在音频开始播放时执行
|
||||||
|
virtual inline void OnStart(Sound* sound) {}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 在音频循环结束时执行
|
||||||
|
virtual inline void OnLoopEnd(Sound* sound) {}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 在音频结束时执行
|
||||||
|
virtual inline void OnEnd(Sound* sound) {}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 在音频修改音量时执行
|
||||||
|
virtual inline float OnVolumeChanged(Sound* sound, float volume)
|
||||||
|
{
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \~chinese
|
||||||
|
* @brief 音频
|
||||||
*/
|
*/
|
||||||
class KGE_API Sound : public NativeObject
|
class KGE_API Sound : public NativeObject
|
||||||
{
|
{
|
||||||
friend class AudioModule;
|
friend class AudioModule;
|
||||||
|
friend class SoundPlayer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 预加载音频
|
/// @brief 预加载音频
|
||||||
static SoundPtr Preload(const String& file_path);
|
static SoundPtr Preload(const String& file_path, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 预加载音频资源
|
/// @brief 预加载音频资源
|
||||||
static SoundPtr Preload(const Resource& res);
|
static SoundPtr Preload(const Resource& res, std::initializer_list<SoundCallbackPtr> callbacks = {});
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 创建音频对象
|
/// @brief 创建音频对象
|
||||||
|
|
@ -68,21 +114,6 @@ public:
|
||||||
|
|
||||||
virtual ~Sound();
|
virtual ~Sound();
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 打开本地音频文件
|
|
||||||
/// @param res 本地音频文件路径
|
|
||||||
bool Load(const String& file_path);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 打开音频资源
|
|
||||||
/// @param res 音频资源
|
|
||||||
bool Load(const Resource& res);
|
|
||||||
|
|
||||||
/// \~chinese
|
|
||||||
/// @brief 打开音频资源
|
|
||||||
/// @param res 音频资源
|
|
||||||
bool Load(TranscoderPtr transcoder);
|
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 播放
|
/// @brief 播放
|
||||||
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
/// @param loop_count 播放循环次数,设置 -1 为循环播放
|
||||||
|
|
@ -117,13 +148,62 @@ public:
|
||||||
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
/// @param volume 音量大小,1.0 为原始音量, 大于 1 为放大音量, 0 为最小音量
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 添加回调
|
||||||
|
void AddCallback(SoundCallbackPtr callback);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取所有回调
|
||||||
|
List<SoundCallbackPtr>& GetCallbacks();
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 获取所有回调
|
||||||
|
const List<SoundCallbackPtr>& GetCallbacks() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 打开本地音频文件
|
||||||
|
/// @param res 本地音频文件路径
|
||||||
|
bool Load(const String& file_path);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 打开音频资源
|
||||||
|
/// @param res 音频资源
|
||||||
|
bool Load(const Resource& res);
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 打开音频资源
|
||||||
|
/// @param res 音频资源
|
||||||
|
bool Load(TranscoderPtr transcoder);
|
||||||
|
|
||||||
|
SoundCallbackPtr GetCallbackChain();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opened_;
|
bool opened_;
|
||||||
bool playing_;
|
bool playing_;
|
||||||
|
float volume_;
|
||||||
TranscoderPtr coder_;
|
TranscoderPtr coder_;
|
||||||
|
|
||||||
|
SoundCallbackPtr callback_chain_;
|
||||||
|
List<SoundCallbackPtr> callbacks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
inline List<SoundCallbackPtr>& kiwano::audio::Sound::GetCallbacks()
|
||||||
|
{
|
||||||
|
return callbacks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const List<SoundCallbackPtr>& kiwano::audio::Sound::GetCallbacks() const
|
||||||
|
{
|
||||||
|
return callbacks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void kiwano::audio::Sound::AddCallback(SoundCallbackPtr callback)
|
||||||
|
{
|
||||||
|
callbacks_.push_back(callback);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace kiwano
|
} // namespace kiwano
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue