AudioCommon.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Copyright 2009 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "AudioCommon/AudioCommon.h"
  4. #include <fmt/chrono.h>
  5. #include <fmt/format.h>
  6. #include "AudioCommon/AlsaSoundStream.h"
  7. #include "AudioCommon/CubebStream.h"
  8. #include "AudioCommon/Mixer.h"
  9. #include "AudioCommon/NullSoundStream.h"
  10. #include "AudioCommon/OpenALStream.h"
  11. #include "AudioCommon/OpenSLESStream.h"
  12. #include "AudioCommon/PulseAudioStream.h"
  13. #include "AudioCommon/WASAPIStream.h"
  14. #include "Common/Common.h"
  15. #include "Common/FileUtil.h"
  16. #include "Common/Logging/Log.h"
  17. #include "Core/Config/MainSettings.h"
  18. #include "Core/ConfigManager.h"
  19. #include "Core/System.h"
  20. namespace AudioCommon
  21. {
  22. constexpr int AUDIO_VOLUME_MIN = 0;
  23. constexpr int AUDIO_VOLUME_MAX = 100;
  24. static std::unique_ptr<SoundStream> CreateSoundStreamForBackend(std::string_view backend)
  25. {
  26. if (backend == BACKEND_CUBEB)
  27. return std::make_unique<CubebStream>();
  28. else if (backend == BACKEND_OPENAL && OpenALStream::IsValid())
  29. return std::make_unique<OpenALStream>();
  30. else if (backend == BACKEND_NULLSOUND)
  31. return std::make_unique<NullSound>();
  32. else if (backend == BACKEND_ALSA && AlsaSound::IsValid())
  33. return std::make_unique<AlsaSound>();
  34. else if (backend == BACKEND_PULSEAUDIO && PulseAudio::IsValid())
  35. return std::make_unique<PulseAudio>();
  36. else if (backend == BACKEND_OPENSLES && OpenSLESStream::IsValid())
  37. return std::make_unique<OpenSLESStream>();
  38. else if (backend == BACKEND_WASAPI && WASAPIStream::IsValid())
  39. return std::make_unique<WASAPIStream>();
  40. return {};
  41. }
  42. void InitSoundStream(Core::System& system)
  43. {
  44. std::string backend = Config::Get(Config::MAIN_AUDIO_BACKEND);
  45. std::unique_ptr<SoundStream> sound_stream = CreateSoundStreamForBackend(backend);
  46. if (!sound_stream)
  47. {
  48. WARN_LOG_FMT(AUDIO, "Unknown backend {}, using {} instead.", backend, GetDefaultSoundBackend());
  49. backend = GetDefaultSoundBackend();
  50. sound_stream = CreateSoundStreamForBackend(backend);
  51. }
  52. if (!sound_stream || !sound_stream->Init())
  53. {
  54. WARN_LOG_FMT(AUDIO, "Could not initialize backend {}, using {} instead.", backend,
  55. BACKEND_NULLSOUND);
  56. sound_stream = std::make_unique<NullSound>();
  57. sound_stream->Init();
  58. }
  59. system.SetSoundStream(std::move(sound_stream));
  60. }
  61. void PostInitSoundStream(Core::System& system)
  62. {
  63. // This needs to be called after AudioInterface::Init and SerialInterface::Init (for GBA devices)
  64. // where input sample rates are set
  65. UpdateSoundStream(system);
  66. SetSoundStreamRunning(system, true);
  67. if (Config::Get(Config::MAIN_DUMP_AUDIO) && !system.IsAudioDumpStarted())
  68. StartAudioDump(system);
  69. }
  70. void ShutdownSoundStream(Core::System& system)
  71. {
  72. INFO_LOG_FMT(AUDIO, "Shutting down sound stream");
  73. if (Config::Get(Config::MAIN_DUMP_AUDIO) && system.IsAudioDumpStarted())
  74. StopAudioDump(system);
  75. SetSoundStreamRunning(system, false);
  76. system.SetSoundStream(nullptr);
  77. INFO_LOG_FMT(AUDIO, "Done shutting down sound stream");
  78. }
  79. std::string GetDefaultSoundBackend()
  80. {
  81. std::string backend = BACKEND_NULLSOUND;
  82. #if defined ANDROID
  83. backend = BACKEND_OPENSLES;
  84. #elif defined __linux__
  85. if (AlsaSound::IsValid())
  86. backend = BACKEND_ALSA;
  87. else
  88. backend = BACKEND_CUBEB;
  89. #elif defined(__APPLE__) || defined(_WIN32) || defined(__OpenBSD__)
  90. backend = BACKEND_CUBEB;
  91. #endif
  92. return backend;
  93. }
  94. DPL2Quality GetDefaultDPL2Quality()
  95. {
  96. return DPL2Quality::High;
  97. }
  98. std::vector<std::string> GetSoundBackends()
  99. {
  100. std::vector<std::string> backends;
  101. backends.emplace_back(BACKEND_NULLSOUND);
  102. backends.emplace_back(BACKEND_CUBEB);
  103. if (AlsaSound::IsValid())
  104. backends.emplace_back(BACKEND_ALSA);
  105. if (PulseAudio::IsValid())
  106. backends.emplace_back(BACKEND_PULSEAUDIO);
  107. if (OpenALStream::IsValid())
  108. backends.emplace_back(BACKEND_OPENAL);
  109. if (OpenSLESStream::IsValid())
  110. backends.emplace_back(BACKEND_OPENSLES);
  111. if (WASAPIStream::IsValid())
  112. backends.emplace_back(BACKEND_WASAPI);
  113. return backends;
  114. }
  115. bool SupportsDPL2Decoder(std::string_view backend)
  116. {
  117. #ifndef __APPLE__
  118. if (backend == BACKEND_OPENAL)
  119. return true;
  120. #endif
  121. if (backend == BACKEND_CUBEB)
  122. return true;
  123. if (backend == BACKEND_PULSEAUDIO)
  124. return true;
  125. return false;
  126. }
  127. bool SupportsLatencyControl(std::string_view backend)
  128. {
  129. return backend == BACKEND_OPENAL || backend == BACKEND_WASAPI;
  130. }
  131. bool SupportsVolumeChanges(std::string_view backend)
  132. {
  133. // FIXME: this one should ask the backend whether it supports it.
  134. // but getting the backend from string etc. is probably
  135. // too much just to enable/disable a stupid slider...
  136. return backend == BACKEND_CUBEB || backend == BACKEND_OPENAL || backend == BACKEND_WASAPI;
  137. }
  138. void UpdateSoundStream(Core::System& system)
  139. {
  140. SoundStream* sound_stream = system.GetSoundStream();
  141. if (sound_stream)
  142. {
  143. int volume = Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
  144. sound_stream->SetVolume(volume);
  145. }
  146. }
  147. void SetSoundStreamRunning(Core::System& system, bool running)
  148. {
  149. SoundStream* sound_stream = system.GetSoundStream();
  150. if (!sound_stream)
  151. return;
  152. if (system.IsSoundStreamRunning() == running)
  153. return;
  154. system.SetSoundStreamRunning(running);
  155. if (sound_stream->SetRunning(running))
  156. return;
  157. if (running)
  158. ERROR_LOG_FMT(AUDIO, "Error starting stream.");
  159. else
  160. ERROR_LOG_FMT(AUDIO, "Error stopping stream.");
  161. }
  162. void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples)
  163. {
  164. SoundStream* sound_stream = system.GetSoundStream();
  165. if (!sound_stream)
  166. return;
  167. if (Config::Get(Config::MAIN_DUMP_AUDIO) && !system.IsAudioDumpStarted())
  168. StartAudioDump(system);
  169. else if (!Config::Get(Config::MAIN_DUMP_AUDIO) && system.IsAudioDumpStarted())
  170. StopAudioDump(system);
  171. Mixer* mixer = sound_stream->GetMixer();
  172. if (mixer && samples)
  173. {
  174. mixer->PushSamples(samples, num_samples);
  175. }
  176. }
  177. void StartAudioDump(Core::System& system)
  178. {
  179. SoundStream* sound_stream = system.GetSoundStream();
  180. std::time_t start_time = std::time(nullptr);
  181. std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID();
  182. std::string base_name =
  183. fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(start_time));
  184. const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name);
  185. const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name);
  186. File::CreateFullPath(audio_file_name_dtk);
  187. File::CreateFullPath(audio_file_name_dsp);
  188. sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk);
  189. sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp);
  190. system.SetAudioDumpStarted(true);
  191. }
  192. void StopAudioDump(Core::System& system)
  193. {
  194. SoundStream* sound_stream = system.GetSoundStream();
  195. if (!sound_stream)
  196. return;
  197. sound_stream->GetMixer()->StopLogDTKAudio();
  198. sound_stream->GetMixer()->StopLogDSPAudio();
  199. system.SetAudioDumpStarted(false);
  200. }
  201. void IncreaseVolume(Core::System& system, unsigned short offset)
  202. {
  203. Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
  204. int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
  205. currentVolume += offset;
  206. if (currentVolume > AUDIO_VOLUME_MAX)
  207. currentVolume = AUDIO_VOLUME_MAX;
  208. Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
  209. UpdateSoundStream(system);
  210. }
  211. void DecreaseVolume(Core::System& system, unsigned short offset)
  212. {
  213. Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
  214. int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
  215. currentVolume -= offset;
  216. if (currentVolume < AUDIO_VOLUME_MIN)
  217. currentVolume = AUDIO_VOLUME_MIN;
  218. Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
  219. UpdateSoundStream(system);
  220. }
  221. void ToggleMuteVolume(Core::System& system)
  222. {
  223. bool isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
  224. Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
  225. UpdateSoundStream(system);
  226. }
  227. } // namespace AudioCommon