Serenity Operating System
at hosted 180 lines 4.6 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "PlaybackManager.h" 28 29PlaybackManager::PlaybackManager(NonnullRefPtr<Audio::ClientConnection> connection) 30 : m_connection(connection) 31{ 32 m_timer = Core::Timer::construct(100, [&]() { 33 if (!m_loader) 34 return; 35 next_buffer(); 36 }); 37 m_timer->stop(); 38} 39 40PlaybackManager::~PlaybackManager() 41{ 42} 43 44void PlaybackManager::set_loader(OwnPtr<Audio::WavLoader>&& loader) 45{ 46 stop(); 47 m_loader = move(loader); 48 if (m_loader) { 49 m_total_length = m_loader->total_samples() / static_cast<float>(m_loader->sample_rate()); 50 m_timer->start(); 51 load_next_buffer(); 52 } else { 53 m_timer->stop(); 54 } 55} 56 57void PlaybackManager::stop() 58{ 59 set_paused(true); 60 m_connection->clear_buffer(true); 61 m_buffers.clear(); 62 m_last_seek = 0; 63 m_next_buffer = nullptr; 64 m_current_buffer = nullptr; 65 m_next_ptr = 0; 66 67 if (m_loader) 68 m_loader->reset(); 69} 70 71void PlaybackManager::play() 72{ 73 set_paused(false); 74} 75 76void PlaybackManager::seek(const int position) 77{ 78 if (!m_loader) 79 return; 80 81 m_last_seek = position; 82 bool paused_state = m_paused; 83 set_paused(true); 84 85 m_connection->clear_buffer(true); 86 m_next_buffer = nullptr; 87 m_current_buffer = nullptr; 88 m_next_ptr = 0; 89 m_buffers.clear(); 90 m_loader->seek(position); 91 92 if (!paused_state) 93 set_paused(false); 94} 95 96void PlaybackManager::pause() 97{ 98 set_paused(true); 99} 100 101void PlaybackManager::remove_dead_buffers() 102{ 103 int id = m_connection->get_playing_buffer(); 104 int current_id = -1; 105 if (m_current_buffer) 106 current_id = m_current_buffer->shbuf_id(); 107 108 if (id >= 0 && id != current_id) { 109 while (!m_buffers.is_empty()) { 110 --m_next_ptr; 111 auto buffer = m_buffers.take_first(); 112 113 if (buffer->shbuf_id() == id) { 114 m_current_buffer = buffer; 115 break; 116 } 117 } 118 } 119} 120 121void PlaybackManager::load_next_buffer() 122{ 123 if (m_buffers.size() < 10) { 124 for (int i = 0; i < 20 && m_loader->loaded_samples() < m_loader->total_samples(); i++) { 125 auto buffer = m_loader->get_more_samples(PLAYBACK_MANAGER_BUFFER_SIZE); 126 if (buffer) 127 m_buffers.append(buffer); 128 } 129 } 130 131 if (m_next_ptr < m_buffers.size()) { 132 m_next_buffer = m_buffers.at(m_next_ptr++); 133 } else { 134 m_next_buffer = nullptr; 135 } 136} 137 138void PlaybackManager::set_paused(bool paused) 139{ 140 if (!m_next_buffer && m_loader) 141 load_next_buffer(); 142 143 m_paused = paused; 144 m_connection->set_paused(paused); 145} 146 147bool PlaybackManager::toggle_pause() 148{ 149 if (m_paused) { 150 play(); 151 } else { 152 pause(); 153 } 154 return m_paused; 155} 156 157void PlaybackManager::next_buffer() 158{ 159 if (on_update) 160 on_update(); 161 162 if (m_paused) 163 return; 164 165 remove_dead_buffers(); 166 if (!m_next_buffer) { 167 if (!m_connection->get_remaining_samples() && !m_paused) { 168 dbg() << "Exhausted samples :^)"; 169 stop(); 170 } 171 172 return; 173 } 174 175 bool enqueued = m_connection->try_enqueue(*m_next_buffer); 176 if (!enqueued) 177 return; 178 179 load_next_buffer(); 180}