LCOV - code coverage report
Current view: top level - muse/framework/audio/main/internal - player.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 38.8 % 103 40
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2024 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "player.h"
      23              : 
      24              : #include "audio/common/rpc/rpcpacker.h"
      25              : #include "audio/common/audiosanitizer.h"
      26              : 
      27              : #include "log.h"
      28              : 
      29              : using namespace muse;
      30              : using namespace muse::async;
      31              : using namespace muse::audio;
      32              : using namespace muse::audio::rpc;
      33              : 
      34           14 : rpc::CtxId Player::ctxId() const
      35              : {
      36           14 :     return rpc::ctxId(iocContext());
      37              : }
      38              : 
      39            5 : void Player::init()
      40              : {
      41              :     ONLY_AUDIO_MAIN_THREAD;
      42              : 
      43              :     //! NOTE Subscribe and request initial state
      44              : 
      45              :     {
      46            5 :         m_playbackStatusChanged.onReceive(this, [this](PlaybackStatus st) {
      47            2 :             m_playbackStatus = st;
      48            2 :         });
      49              : 
      50            5 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetPlaybackStatus);
      51            5 :         channel()->send(msg, [this](const Msg& res) {
      52              :             ONLY_AUDIO_MAIN_THREAD;
      53            2 :             Ret ret;
      54            2 :             PlaybackStatus status = PlaybackStatus::Stopped;
      55            2 :             StreamId streamId = 0;
      56            2 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret, status, streamId)) {
      57            0 :                 return;
      58              :             }
      59              : 
      60            2 :             if (ret) {
      61            2 :                 channel()->addReceiveStream(ctxId(), StreamName::PlaybackStatusStream, streamId, m_playbackStatusChanged);
      62              :                 //! NOTE Send initial state
      63            2 :                 m_playbackStatusChanged.send(status);
      64              :             } else {
      65            0 :                 LOGE() << "GetPlaybackStatus failed: " << ret.toString();
      66              :             }
      67            2 :         });
      68            5 :     }
      69              : 
      70              :     {
      71            5 :         m_playbackPositionChanged.onReceive(this, [this](const secs_t newPos) {
      72            2 :             m_playbackPosition = newPos;
      73            2 :         });
      74              : 
      75            5 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetPlaybackPosition);
      76            5 :         channel()->send(msg, [this](const Msg& res) {
      77              :             ONLY_AUDIO_MAIN_THREAD;
      78            2 :             Ret ret;
      79            2 :             secs_t pos = 0.0;
      80            2 :             StreamId streamId = 0;
      81            2 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret, pos, streamId)) {
      82            0 :                 return;
      83              :             }
      84              : 
      85            2 :             if (ret) {
      86            2 :                 channel()->addReceiveStream(ctxId(), StreamName::PlaybackPositionStream, streamId, m_playbackPositionChanged);
      87              :                 //! NOTE Send initial state
      88            2 :                 m_playbackPositionChanged.send(pos);
      89              :             } else {
      90            0 :                 LOGE() << "GetPlaybackPosition failed: " << ret.toString();
      91              :             }
      92            2 :         });
      93            5 :     }
      94            5 : }
      95              : 
      96            2 : void Player::deinit()
      97              : {
      98              :     ONLY_AUDIO_MAIN_THREAD;
      99              : 
     100            2 :     m_playbackStatusChanged.disconnect(this);
     101            2 :     m_playbackPositionChanged.disconnect(this);
     102            2 : }
     103              : 
     104            0 : async::Promise<Ret> Player::prepareToPlay()
     105              : {
     106              :     ONLY_AUDIO_MAIN_THREAD;
     107            0 :     return async::make_promise<Ret>([this](auto resolve, auto) {
     108              :         ONLY_AUDIO_MAIN_THREAD;
     109            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::PrepareToPlay);
     110            0 :         channel()->send(msg, [resolve](const Msg& res) {
     111              :             ONLY_AUDIO_MAIN_THREAD;
     112            0 :             Ret ret;
     113            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     114            0 :                 (void)resolve(make_ret(Ret::Code::UnknownError));
     115            0 :                 return;
     116              :             }
     117              : 
     118            0 :             (void)resolve(ret);
     119            0 :         });
     120            0 :         return Promise<Ret>::dummy_result();
     121            0 :     }, PromiseType::AsyncByBody);
     122              : }
     123              : 
     124            0 : void Player::play(const secs_t delay)
     125              : {
     126              :     ONLY_AUDIO_MAIN_THREAD;
     127            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::Play, RpcPacker::pack(delay));
     128            0 :     channel()->send(msg);
     129            0 : }
     130              : 
     131            0 : void Player::seek(const secs_t newPosition, const bool flushSound)
     132              : {
     133              :     ONLY_AUDIO_MAIN_THREAD;
     134              : 
     135            0 :     if (m_playbackPosition == newPosition) {
     136            0 :         return;
     137              :     }
     138              : 
     139            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::Seek, RpcPacker::pack(newPosition, flushSound));
     140            0 :     channel()->send(msg);
     141            0 : }
     142              : 
     143            0 : void Player::stop()
     144              : {
     145              :     ONLY_AUDIO_MAIN_THREAD;
     146            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::Stop);
     147            0 :     channel()->send(msg);
     148            0 : }
     149              : 
     150            0 : void Player::pause()
     151              : {
     152              :     ONLY_AUDIO_MAIN_THREAD;
     153            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::Pause);
     154            0 :     channel()->send(msg);
     155            0 : }
     156              : 
     157            0 : void Player::resume(const secs_t delay)
     158              : {
     159              :     ONLY_AUDIO_MAIN_THREAD;
     160            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::Resume, RpcPacker::pack(delay));
     161            0 :     channel()->send(msg);
     162            0 : }
     163              : 
     164            0 : void Player::setDuration(const secs_t duration)
     165              : {
     166              :     ONLY_AUDIO_MAIN_THREAD;
     167            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::SetDuration, RpcPacker::pack(duration));
     168            0 :     channel()->send(msg);
     169            0 : }
     170              : 
     171            0 : async::Promise<bool> Player::setLoop(const secs_t from, const secs_t to)
     172              : {
     173              :     ONLY_AUDIO_MAIN_THREAD;
     174            0 :     return async::make_promise<bool>([this, from, to](auto resolve, auto reject) {
     175              :         ONLY_AUDIO_MAIN_THREAD;
     176            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::SetLoop, RpcPacker::pack(from, to));
     177            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     178              :             ONLY_AUDIO_MAIN_THREAD;
     179            0 :             Ret ret;
     180            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     181            0 :                 return;
     182              :             }
     183              : 
     184            0 :             if (ret) {
     185            0 :                 (void)resolve(true);
     186              :             } else {
     187            0 :                 (void)reject(ret.code(), ret.text());
     188              :             }
     189            0 :         });
     190            0 :         return Promise<bool>::dummy_result();
     191            0 :     }, PromiseType::AsyncByBody);
     192              : }
     193              : 
     194            0 : void Player::resetLoop()
     195              : {
     196              :     ONLY_AUDIO_MAIN_THREAD;
     197            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ResetLoop);
     198            0 :     channel()->send(msg);
     199            0 : }
     200              : 
     201            1 : secs_t Player::playbackPosition() const
     202              : {
     203              :     ONLY_AUDIO_MAIN_THREAD;
     204            1 :     return m_playbackPosition;
     205              : }
     206              : 
     207            0 : async::Channel<secs_t> Player::playbackPositionChanged() const
     208              : {
     209              :     ONLY_AUDIO_MAIN_THREAD;
     210            0 :     return m_playbackPositionChanged;
     211              : }
     212              : 
     213            1 : PlaybackStatus Player::playbackStatus() const
     214              : {
     215              :     ONLY_AUDIO_MAIN_THREAD;
     216            1 :     return m_playbackStatus;
     217              : }
     218              : 
     219            0 : async::Channel<PlaybackStatus> Player::playbackStatusChanged() const
     220              : {
     221              :     ONLY_AUDIO_MAIN_THREAD;
     222            0 :     return m_playbackStatusChanged;
     223              : }
        

Generated by: LCOV version 2.0-1