AudioCodecPluginSerenity.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibAudio/ConnectionToServer.h>
  7. #include <LibAudio/Loader.h>
  8. #include <LibAudio/Sample.h>
  9. #include <LibWeb/Platform/Timer.h>
  10. #include <WebContent/AudioCodecPluginSerenity.h>
  11. namespace WebContent {
  12. // These constants and this implementation is based heavily on SoundPlayer::PlaybackManager.
  13. static constexpr u32 UPDATE_RATE_MS = 50;
  14. static constexpr u32 BUFFER_SIZE_MS = 100;
  15. static constexpr size_t ALWAYS_ENQUEUED_BUFFER_COUNT = 5;
  16. ErrorOr<NonnullOwnPtr<AudioCodecPluginSerenity>> AudioCodecPluginSerenity::create(NonnullRefPtr<Audio::Loader> loader)
  17. {
  18. auto connection = TRY(Audio::ConnectionToServer::try_create());
  19. return adopt_nonnull_own_or_enomem(new (nothrow) AudioCodecPluginSerenity(move(connection), move(loader)));
  20. }
  21. AudioCodecPluginSerenity::AudioCodecPluginSerenity(NonnullRefPtr<Audio::ConnectionToServer> connection, NonnullRefPtr<Audio::Loader> loader)
  22. : m_connection(move(connection))
  23. , m_loader(move(loader))
  24. , m_sample_timer(Web::Platform::Timer::create_repeating(UPDATE_RATE_MS, [this]() {
  25. if (play_next_samples().is_error()) {
  26. // FIXME: Propagate the error to the HTMLMediaElement.
  27. } else {
  28. if (on_playback_position_updated)
  29. on_playback_position_updated(m_position);
  30. }
  31. }))
  32. {
  33. auto duration = static_cast<double>(m_loader->total_samples()) / static_cast<double>(m_loader->sample_rate());
  34. m_duration = Duration::from_milliseconds(static_cast<i64>(duration * 1000.0));
  35. m_device_sample_rate = m_connection->get_sample_rate();
  36. m_device_samples_per_buffer = static_cast<size_t>(BUFFER_SIZE_MS / 1000.0 * static_cast<double>(m_device_sample_rate));
  37. m_samples_to_load_per_buffer = static_cast<size_t>(BUFFER_SIZE_MS / 1000.0 * static_cast<double>(m_loader->sample_rate()));
  38. }
  39. AudioCodecPluginSerenity::~AudioCodecPluginSerenity() = default;
  40. ErrorOr<void> AudioCodecPluginSerenity::play_next_samples()
  41. {
  42. while (m_connection->remaining_samples() < m_device_samples_per_buffer * ALWAYS_ENQUEUED_BUFFER_COUNT) {
  43. bool all_samples_loaded = m_loader->loaded_samples() >= m_loader->total_samples();
  44. bool audio_server_done = m_connection->remaining_samples() == 0;
  45. if (all_samples_loaded && audio_server_done) {
  46. pause_playback();
  47. m_connection->clear_client_buffer();
  48. m_connection->async_clear_buffer();
  49. (void)m_loader->reset();
  50. m_position = m_duration;
  51. break;
  52. }
  53. auto samples = TRY(read_samples_from_loader(m_loader, m_samples_to_load_per_buffer, m_device_sample_rate));
  54. TRY(m_connection->async_enqueue(move(samples)));
  55. m_position = current_loader_position(m_loader, m_device_sample_rate);
  56. }
  57. return {};
  58. }
  59. void AudioCodecPluginSerenity::resume_playback()
  60. {
  61. m_connection->async_start_playback();
  62. m_sample_timer->start();
  63. }
  64. void AudioCodecPluginSerenity::pause_playback()
  65. {
  66. m_connection->async_pause_playback();
  67. m_sample_timer->stop();
  68. }
  69. void AudioCodecPluginSerenity::set_volume(double volume)
  70. {
  71. m_connection->async_set_self_volume(volume);
  72. }
  73. void AudioCodecPluginSerenity::seek(double position)
  74. {
  75. auto duration = static_cast<double>(this->duration().to_milliseconds()) / 1000.0;
  76. position = position / duration * static_cast<double>(m_loader->total_samples());
  77. m_loader->seek(static_cast<int>(position)).release_value_but_fixme_should_propagate_errors();
  78. m_position = current_loader_position(m_loader, m_device_sample_rate);
  79. if (on_playback_position_updated)
  80. on_playback_position_updated(m_position);
  81. }
  82. Duration AudioCodecPluginSerenity::duration()
  83. {
  84. return m_duration;
  85. }
  86. }