LCOV - code coverage report
Current view: top level - muse/framework/audio/main/internal - playback.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 19.5 % 415 81
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) 2021 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 "playback.h"
      23              : 
      24              : #include "audio/common/rpc/rpcpacker.h"
      25              : #include "audio/common/audiosanitizer.h"
      26              : #include "audio/common/audioerrors.h"
      27              : #include "player.h"
      28              : 
      29              : #include "muse_framework_config.h"
      30              : 
      31              : #include "log.h"
      32              : 
      33              : using namespace muse;
      34              : using namespace muse::audio;
      35              : using namespace muse::audio::rpc;
      36              : using namespace muse::async;
      37              : 
      38            5 : Playback::~Playback()
      39              : {
      40            5 :     channel()->cancelAllRequests(ctxId());
      41            5 : }
      42              : 
      43           75 : rpc::CtxId Playback::ctxId() const
      44              : {
      45           75 :     return rpc::ctxId(iocContext());
      46              : }
      47              : 
      48              : // Init
      49            6 : async::Promise<Ret> Playback::init()
      50              : {
      51              :     ONLY_AUDIO_MAIN_THREAD;
      52              : 
      53            6 :     channel()->onNotification(ctxId(), MsgCode::TrackAdded, [this](const Msg& msg) {
      54              :         ONLY_AUDIO_MAIN_THREAD;
      55            0 :         TrackId trackId = 0;
      56            0 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId)) {
      57            0 :             return;
      58              :         }
      59            0 :         m_trackAdded.send(trackId);
      60              :     });
      61              : 
      62            6 :     channel()->onNotification(ctxId(), MsgCode::TrackRemoved, [this](const Msg& msg) {
      63              :         ONLY_AUDIO_MAIN_THREAD;
      64            1 :         TrackId trackId = 0;
      65            1 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId)) {
      66            0 :             return;
      67              :         }
      68            1 :         removeTrackStreams(trackId);
      69            1 :         m_trackRemoved.send(trackId);
      70              :     });
      71              : 
      72            6 :     channel()->onNotification(ctxId(), MsgCode::SourceParamsChanged, [this](const Msg& msg) {
      73              :         ONLY_AUDIO_MAIN_THREAD;
      74            0 :         TrackId trackId = 0;
      75            0 :         AudioSourceParams params;
      76            0 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId, params)) {
      77            0 :             return;
      78              :         }
      79            0 :         m_sourceParamsChanged.send(trackId, params);
      80            0 :     });
      81              : 
      82            6 :     channel()->onNotification(ctxId(), MsgCode::FxChainParamsChanged, [this](const Msg& msg) {
      83              :         ONLY_AUDIO_MAIN_THREAD;
      84            0 :         TrackId trackId = 0;
      85            0 :         AudioFxChain params;
      86            0 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId, params)) {
      87            0 :             return;
      88              :         }
      89            0 :         if (trackId == MASTER_TRACK_ID) {
      90            0 :             m_masterFxChainParamsChanged.send(params);
      91              :         } else {
      92            0 :             m_fxChainParamsChanged.send(trackId, params);
      93              :         }
      94            0 :     });
      95              : 
      96            6 :     channel()->onNotification(ctxId(), MsgCode::ControlParamsChanged, [this](const Msg& msg) {
      97              :         ONLY_AUDIO_MAIN_THREAD;
      98            0 :         TrackId trackId = 0;
      99            0 :         ControlParams params;
     100            0 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId, params)) {
     101            0 :             return;
     102              :         }
     103            0 :         if (trackId == MASTER_TRACK_ID) {
     104            0 :             m_masterControlParamsChanged.send(params);
     105              :         } else {
     106            0 :             m_controlParamsChanged.send(trackId, params);
     107              :         }
     108            0 :     });
     109              : 
     110            6 :     channel()->onNotification(ctxId(), MsgCode::AuxSendsParamsChanged, [this](const Msg& msg) {
     111              :         ONLY_AUDIO_MAIN_THREAD;
     112            0 :         TrackId trackId = 0;
     113            0 :         AuxSendsParams params;
     114            0 :         IF_ASSERT_FAILED(RpcPacker::unpack(msg.data, trackId, params)) {
     115            0 :             return;
     116              :         }
     117            0 :         if (trackId == MASTER_TRACK_ID) {
     118            0 :             m_masterAuxSendsParamsChanged.send(params);
     119              :         } else {
     120            0 :             m_auxSendsParamsChanged.send(trackId, params);
     121              :         }
     122            0 :     });
     123              : 
     124           12 :     return async::make_promise<Ret>([this](auto resolve, auto /*reject*/) {
     125              :         ONLY_AUDIO_MAIN_THREAD;
     126              : 
     127           12 :         auto initContext = [this, resolve]() {
     128              :             //! NOTE The message context here is global, and the context ID is the data in the message
     129            6 :             Msg msg = rpc::make_request(rpc::GLOBAL_CTX_ID, MsgCode::ContextInit, RpcPacker::pack(ctxId()));
     130            6 :             channel()->send(msg, [this, resolve](const Msg& res) {
     131              :                 ONLY_AUDIO_MAIN_THREAD;
     132            6 :                 Ret ret;
     133            6 :                 IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     134            0 :                     ret = audio::make_ret(Err::InvalidRpcData);
     135            0 :                     (void)resolve(ret);
     136            0 :                     return;
     137              :                 }
     138            6 :                 m_inited.set(ret.success());
     139            6 :                 (void)resolve(ret);
     140            6 :             });
     141            6 :         };
     142              : 
     143            6 :         LOGD() << "isAudioStarted: " << startAudioController()->isAudioStarted();
     144            6 :         if (startAudioController()->isAudioStarted()) {
     145            6 :             initContext();
     146              :         } else {
     147            0 :             startAudioController()->isAudioStartedChanged().onReceive(this, [this, initContext](bool arg) {
     148            0 :                 LOGD() << "isAudioStartedChanged: " << arg;
     149            0 :                 if (arg) {
     150            0 :                     initContext();
     151              :                 } else {
     152            0 :                     LOGE() << "audio not started";
     153              :                 }
     154            0 :                 startAudioController()->isAudioStartedChanged().disconnect(this);
     155              :             });
     156              :         }
     157              : 
     158           12 :         return Promise<Ret>::dummy_result();
     159           18 :     }, PromiseType::AsyncByPromise);
     160              : }
     161              : 
     162            3 : void Playback::deinit()
     163              : {
     164              :     ONLY_AUDIO_MAIN_THREAD;
     165              : 
     166            3 :     channel()->onNotification(ctxId(), MsgCode::TrackAdded, nullptr);
     167            3 :     channel()->onNotification(ctxId(), MsgCode::TrackRemoved, nullptr);
     168            3 :     channel()->onNotification(ctxId(), MsgCode::SourceParamsChanged, nullptr);
     169            3 :     channel()->onNotification(ctxId(), MsgCode::FxChainParamsChanged, nullptr);
     170            3 :     channel()->onNotification(ctxId(), MsgCode::ControlParamsChanged, nullptr);
     171            3 :     channel()->onNotification(ctxId(), MsgCode::AuxSendsParamsChanged, nullptr);
     172              : 
     173            3 :     channel()->cancelAllRequests(ctxId());
     174              : 
     175            3 :     m_saveSoundTrackProgressStream = SaveSoundTrackProgress();
     176            3 :     m_saveSoundTrackProgressStreamInited = false;
     177            3 :     m_saveSoundTrackProgressStreamId = 0;
     178              : 
     179            3 :     if (m_player) {
     180            2 :         m_player->deinit();
     181            2 :         m_player.reset();
     182              :     }
     183              : 
     184            3 :     m_trackStreams.clear();
     185              : 
     186            3 :     channel()->send(rpc::make_request(rpc::GLOBAL_CTX_ID, MsgCode::ContextDeinit, RpcPacker::pack(ctxId())));
     187            3 :     m_inited.set(false);
     188            6 : }
     189              : 
     190            2 : void Playback::addTrackStream(TrackId trackId, rpc::StreamId streamId) const
     191              : {
     192            2 :     m_trackStreams[trackId].push_back(streamId);
     193            2 : }
     194              : 
     195            1 : void Playback::removeTrackStreams(TrackId trackId) const
     196              : {
     197            1 :     auto it = m_trackStreams.find(trackId);
     198            1 :     if (it == m_trackStreams.end()) {
     199            0 :         return;
     200              :     }
     201              : 
     202            2 :     for (StreamId streamId : it->second) {
     203            1 :         channel()->removeStream(streamId);
     204              :     }
     205              : 
     206            1 :     m_trackStreams.erase(it);
     207              : }
     208              : 
     209           13 : bool Playback::isInited() const
     210              : {
     211           13 :     return m_inited.val;
     212              : }
     213              : 
     214            0 : async::Channel<bool> Playback::initedChanged() const
     215              : {
     216            0 :     return m_inited.ch;
     217              : }
     218              : 
     219            6 : IPlayerPtr Playback::player() const
     220              : {
     221              :     //! NOTE The player requests the engine context, so it must exist
     222            6 :     IF_ASSERT_FAILED(isInited()) {
     223            0 :         return nullptr;
     224              :     }
     225              : 
     226            6 :     if (!m_player) {
     227            5 :         m_player = std::make_shared<Player>(iocContext());
     228            5 :         m_player->init();
     229              :     }
     230              : 
     231            6 :     return m_player;
     232              : }
     233              : 
     234              : template<typename T>
     235            0 : static void doReject(MsgCode code, T& reject, const Ret& ret)
     236              : {
     237            0 :     LOGE() << "failed rpc request: " << rpc::to_string(code) << ", err: " << ret.toString();
     238            0 :     (void)reject(ret.code(), ret.text());
     239            0 : }
     240              : 
     241              : // Resources
     242            0 : async::Promise<AudioResourceMetaList> Playback::availableInputResources() const
     243              : {
     244              :     ONLY_AUDIO_MAIN_THREAD;
     245            0 :     return async::make_promise<AudioResourceMetaList>([this](auto resolve, auto reject) {
     246              :         ONLY_AUDIO_MAIN_THREAD;
     247            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetAvailableInputResources);
     248            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     249              :             ONLY_AUDIO_MAIN_THREAD;
     250            0 :             RetVal<AudioResourceMetaList> ret;
     251            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     252            0 :                 doReject(MsgCode::GetAvailableInputResources, reject, audio::make_ret(Err::InvalidRpcData));
     253            0 :                 return;
     254              :             }
     255            0 :             if (ret.ret) {
     256            0 :                 (void)resolve(ret.val);
     257              :             } else {
     258            0 :                 doReject(MsgCode::GetAvailableInputResources, reject, ret.ret);
     259              :             }
     260            0 :         });
     261            0 :         return Promise<AudioResourceMetaList>::dummy_result();
     262            0 :     }, PromiseType::AsyncByBody);
     263              : }
     264              : 
     265            0 : async::Promise<SoundPresetList> Playback::availableSoundPresets(const AudioResourceMeta& resourceMeta) const
     266              : {
     267              :     ONLY_AUDIO_MAIN_THREAD;
     268            0 :     return async::make_promise<SoundPresetList>([this, resourceMeta](auto resolve, auto reject) {
     269              :         ONLY_AUDIO_MAIN_THREAD;
     270            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetAvailableSoundPresets, RpcPacker::pack(resourceMeta));
     271            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     272              :             ONLY_AUDIO_MAIN_THREAD;
     273            0 :             RetVal<SoundPresetList> ret;
     274            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     275            0 :                 doReject(MsgCode::GetAvailableSoundPresets, reject, audio::make_ret(Err::InvalidRpcData));
     276            0 :                 return;
     277              :             }
     278            0 :             if (ret.ret) {
     279            0 :                 (void)resolve(ret.val);
     280              :             } else {
     281            0 :                 doReject(MsgCode::GetAvailableSoundPresets, reject, ret.ret);
     282              :             }
     283            0 :         });
     284            0 :         return Promise<SoundPresetList>::dummy_result();
     285            0 :     }, PromiseType::AsyncByBody);
     286              : }
     287              : 
     288            0 : async::Promise<AudioResourceMetaList> Playback::availableOutputResources() const
     289              : {
     290              :     ONLY_AUDIO_MAIN_THREAD;
     291            0 :     return async::make_promise<AudioResourceMetaList>([this](auto resolve, auto reject) {
     292              :         ONLY_AUDIO_MAIN_THREAD;
     293            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetAvailableOutputResources);
     294            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     295              :             ONLY_AUDIO_MAIN_THREAD;
     296            0 :             RetVal<AudioResourceMetaList> ret;
     297            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     298            0 :                 doReject(MsgCode::GetAvailableOutputResources, reject, audio::make_ret(Err::InvalidRpcData));
     299            0 :                 return;
     300              :             }
     301            0 :             if (ret.ret) {
     302            0 :                 (void)resolve(ret.val);
     303              :             } else {
     304            0 :                 doReject(MsgCode::GetAvailableOutputResources, reject, ret.ret);
     305              :             }
     306            0 :         });
     307            0 :         return Promise<AudioResourceMetaList>::dummy_result();
     308            0 :     }, PromiseType::AsyncByBody);
     309              : }
     310              : 
     311              : // Setup tracks
     312            0 : async::Promise<TrackIdList> Playback::trackIdList() const
     313              : {
     314              :     ONLY_AUDIO_MAIN_THREAD;
     315            0 :     return async::make_promise<TrackIdList>([this](auto resolve, auto reject) {
     316              :         ONLY_AUDIO_MAIN_THREAD;
     317            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetTrackIdList);
     318            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     319              :             ONLY_AUDIO_MAIN_THREAD;
     320            0 :             RetVal<TrackIdList> ret;
     321            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     322            0 :                 doReject(MsgCode::GetTrackIdList, reject, audio::make_ret(Err::InvalidRpcData));
     323            0 :                 return;
     324              :             }
     325            0 :             if (ret.ret) {
     326            0 :                 (void)resolve(ret.val);
     327              :             } else {
     328            0 :                 doReject(MsgCode::GetTrackIdList, reject, ret.ret);
     329              :             }
     330            0 :         });
     331            0 :         return Promise<TrackIdList>::dummy_result();
     332            0 :     }, PromiseType::AsyncByBody);
     333              : }
     334              : 
     335            0 : async::Promise<RetVal<TrackName> > Playback::trackName(const TrackId trackId) const
     336              : {
     337              :     ONLY_AUDIO_MAIN_THREAD;
     338            0 :     return async::make_promise<RetVal<TrackName> >([this, trackId](auto resolve, auto reject) {
     339              :         ONLY_AUDIO_MAIN_THREAD;
     340            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetTrackName, RpcPacker::pack(trackId));
     341            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     342              :             ONLY_AUDIO_MAIN_THREAD;
     343            0 :             RetVal<TrackName> ret;
     344            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     345            0 :                 doReject(MsgCode::GetTrackName, reject, audio::make_ret(Err::InvalidRpcData));
     346            0 :                 return;
     347              :             }
     348            0 :             (void)resolve(ret);
     349            0 :         });
     350            0 :         return Promise<RetVal<TrackName> >::dummy_result();
     351            0 :     }, PromiseType::AsyncByBody);
     352              : }
     353              : 
     354            0 : async::Promise<TrackId, TrackParams> Playback::addTrack(const TrackName& trackName,
     355              :                                                         io::IODevice* playbackData,
     356              :                                                         const TrackParams& params)
     357              : {
     358              : #ifdef MUSE_CONFIGURATION_IS_WEB
     359              :     NOT_SUPPORTED;
     360              :     return async::make_promise<TrackId, TrackParams>([](auto /*resolve*/, auto reject) {
     361              :         doReject(MsgCode::AddTrackWithIODevice, reject, muse::make_ret(Ret::Code::NotSupported));
     362              :         return Promise<TrackId, TrackParams>::dummy_result();
     363              :     });
     364              : #else
     365              :     ONLY_AUDIO_MAIN_THREAD;
     366            0 :     return async::make_promise<TrackId, TrackParams>([this, trackName, playbackData, params](auto resolve, auto reject) {
     367              :         ONLY_AUDIO_MAIN_THREAD;
     368              : 
     369            0 :         ByteArray data = RpcPacker::pack(trackName, reinterpret_cast<uint64_t>(playbackData), params);
     370              : 
     371            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::AddTrackWithIODevice, data);
     372            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     373              :             ONLY_AUDIO_MAIN_THREAD;
     374            0 :             RetVal2<TrackId, TrackParams> ret;
     375            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     376            0 :                 doReject(MsgCode::AddTrackWithIODevice, reject, audio::make_ret(Err::InvalidRpcData));
     377            0 :                 return;
     378              :             }
     379            0 :             if (ret.ret) {
     380            0 :                 (void)resolve(ret.val1, ret.val2);
     381              :             } else {
     382            0 :                 doReject(MsgCode::AddTrackWithIODevice, reject, ret.ret);
     383              :             }
     384            0 :         });
     385            0 :         return Promise<TrackId, TrackParams>::dummy_result();
     386            0 :     }, PromiseType::AsyncByBody);
     387              : 
     388              : #endif // MUSE_CONFIGURATION_IS_WEB
     389              : }
     390              : 
     391            0 : async::Promise<TrackId, TrackParams> Playback::addTrack(const TrackName& trackName,
     392              :                                                         const mpe::PlaybackData& playbackData,
     393              :                                                         const TrackParams& params)
     394              : {
     395              :     ONLY_AUDIO_MAIN_THREAD;
     396            0 :     return async::make_promise<TrackId, TrackParams>([this, trackName, playbackData, params](auto resolve, auto reject) {
     397              :         ONLY_AUDIO_MAIN_THREAD;
     398              : 
     399            0 :         rpc::StreamId mainStreamId = channel()->addSendStream(ctxId(), StreamName::PlaybackDataMainStream, playbackData.mainStream);
     400            0 :         rpc::StreamId offStreamId = channel()->addSendStream(ctxId(), StreamName::PlaybackDataOffStream, playbackData.offStream);
     401              : 
     402            0 :         ByteArray data = RpcPacker::pack(trackName, playbackData, params, mainStreamId, offStreamId);
     403              : 
     404            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::AddTrackWithPlaybackData, data);
     405            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     406              :             ONLY_AUDIO_MAIN_THREAD;
     407            0 :             RetVal2<TrackId, TrackParams> ret;
     408            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     409            0 :                 doReject(MsgCode::AddTrackWithPlaybackData, reject, audio::make_ret(Err::InvalidRpcData));
     410            0 :                 return;
     411              :             }
     412            0 :             if (ret.ret) {
     413            0 :                 (void)resolve(ret.val1, ret.val2);
     414              :             } else {
     415            0 :                 doReject(MsgCode::AddTrackWithPlaybackData, reject, ret.ret);
     416              :             }
     417            0 :         });
     418            0 :         return Promise<TrackId, TrackParams>::dummy_result();
     419            0 :     }, PromiseType::AsyncByBody);
     420              : }
     421              : 
     422            0 : async::Promise<TrackId, TrackParams> Playback::addAuxTrack(const TrackName& trackName, const TrackParams& params)
     423              : {
     424              :     ONLY_AUDIO_MAIN_THREAD;
     425            0 :     return async::make_promise<TrackId, TrackParams>([this, trackName, params](auto resolve, auto reject) {
     426              :         ONLY_AUDIO_MAIN_THREAD;
     427            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::AddAuxTrack, RpcPacker::pack(trackName, params));
     428            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     429              :             ONLY_AUDIO_MAIN_THREAD;
     430            0 :             RetVal2<TrackId, TrackParams> ret;
     431            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     432            0 :                 doReject(MsgCode::AddAuxTrack, reject, audio::make_ret(Err::InvalidRpcData));
     433            0 :                 return;
     434              :             }
     435            0 :             if (ret.ret) {
     436            0 :                 (void)resolve(ret.val1, ret.val2);
     437              :             } else {
     438            0 :                 doReject(MsgCode::AddAuxTrack, reject, ret.ret);
     439              :             }
     440            0 :         });
     441            0 :         return Promise<TrackId, TrackParams>::dummy_result();
     442            0 :     }, PromiseType::AsyncByBody);
     443              : }
     444              : 
     445            0 : void Playback::removeTrack(const TrackId trackId)
     446              : {
     447              :     ONLY_AUDIO_MAIN_THREAD;
     448            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::RemoveTrack, RpcPacker::pack(trackId));
     449            0 :     channel()->send(msg);
     450            0 : }
     451              : 
     452            0 : void Playback::removeAllTracks()
     453              : {
     454              :     ONLY_AUDIO_MAIN_THREAD;
     455            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::RemoveAllTracks);
     456            0 :     channel()->send(msg);
     457            0 : }
     458              : 
     459            0 : async::Channel<TrackId> Playback::trackAdded() const
     460              : {
     461            0 :     return m_trackAdded;
     462              : }
     463              : 
     464            0 : async::Channel<TrackId> Playback::trackRemoved() const
     465              : {
     466            0 :     return m_trackRemoved;
     467              : }
     468              : 
     469              : // Params
     470            0 : async::Promise<TrackParams> Playback::params(const TrackId trackId) const
     471              : {
     472              :     ONLY_AUDIO_MAIN_THREAD;
     473            0 :     return async::make_promise<TrackParams>([this, trackId](auto resolve, auto reject) {
     474              :         ONLY_AUDIO_MAIN_THREAD;
     475            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetTrackParams, RpcPacker::pack(trackId));
     476            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     477              :             ONLY_AUDIO_MAIN_THREAD;
     478            0 :             RetVal<TrackParams> ret;
     479            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     480            0 :                 doReject(MsgCode::GetTrackParams, reject, audio::make_ret(Err::InvalidRpcData));
     481            0 :                 return;
     482              :             }
     483              : 
     484            0 :             if (ret.ret) {
     485            0 :                 (void)resolve(ret.val);
     486              :             } else {
     487            0 :                 doReject(MsgCode::GetTrackParams, reject, ret.ret);
     488              :             }
     489            0 :         });
     490            0 :         return Promise<TrackParams>::dummy_result();
     491            0 :     }, PromiseType::AsyncByBody);
     492              : }
     493              : 
     494            0 : void Playback::setSourceParams(const TrackId trackId, const AudioSourceParams& params)
     495              : {
     496              :     ONLY_AUDIO_MAIN_THREAD;
     497            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::SetSourceParams, RpcPacker::pack(trackId, params));
     498            0 :     channel()->send(msg);
     499            0 : }
     500              : 
     501            0 : void Playback::setControlParams(const TrackId trackId, const ControlParams& params)
     502              : {
     503              :     ONLY_AUDIO_MAIN_THREAD;
     504            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::SetControlParams, RpcPacker::pack(trackId, params));
     505            0 :     channel()->send(msg);
     506            0 : }
     507              : 
     508            0 : void Playback::setFxChainParams(const TrackId trackId, const AudioFxChain& params)
     509              : {
     510              :     ONLY_AUDIO_MAIN_THREAD;
     511            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::SetFxChainParams, RpcPacker::pack(trackId, params));
     512            0 :     channel()->send(msg);
     513            0 : }
     514              : 
     515            0 : void Playback::setAuxSendsParams(const TrackId trackId, const AuxSendsParams& params)
     516              : {
     517              :     ONLY_AUDIO_MAIN_THREAD;
     518            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::SetAuxSendsParams, RpcPacker::pack(trackId, params));
     519            0 :     channel()->send(msg);
     520            0 : }
     521              : 
     522            0 : async::Channel<TrackId, AudioSourceParams> Playback::sourceParamsChanged() const
     523              : {
     524            0 :     return m_sourceParamsChanged;
     525              : }
     526              : 
     527            0 : async::Channel<TrackId, ControlParams> Playback::controlParamsChanged() const
     528              : {
     529            0 :     return m_controlParamsChanged;
     530              : }
     531              : 
     532            0 : async::Channel<TrackId, AudioFxChain> Playback::fxChainParamsChanged() const
     533              : {
     534            0 :     return m_fxChainParamsChanged;
     535              : }
     536              : 
     537            0 : async::Channel<TrackId, AuxSendsParams> Playback::auxSendsParamsChanged() const
     538              : {
     539            0 :     return m_auxSendsParamsChanged;
     540              : }
     541              : 
     542              : // Same for master
     543            0 : async::Promise<TrackParams> Playback::masterParams() const
     544              : {
     545            0 :     return params(MASTER_TRACK_ID);
     546              : }
     547              : 
     548            0 : void Playback::setMasterControlParams(const ControlParams& params)
     549              : {
     550            0 :     setControlParams(MASTER_TRACK_ID, params);
     551            0 : }
     552              : 
     553            0 : void Playback::setMasterFxChainParams(const AudioFxChain& params)
     554              : {
     555            0 :     setFxChainParams(MASTER_TRACK_ID, params);
     556            0 : }
     557              : 
     558            0 : void Playback::setMasterAuxSendsParams(const AuxSendsParams& params)
     559              : {
     560            0 :     setAuxSendsParams(MASTER_TRACK_ID, params);
     561            0 : }
     562              : 
     563            0 : async::Channel<ControlParams> Playback::masterControlParamsChanged() const
     564              : {
     565            0 :     return m_masterControlParamsChanged;
     566              : }
     567              : 
     568            0 : async::Channel<AudioFxChain> Playback::masterFxChainParamsChanged() const
     569              : {
     570            0 :     return m_masterFxChainParamsChanged;
     571              : }
     572              : 
     573            0 : async::Channel<AuxSendsParams> Playback::masterAuxSendsParamsChanged() const
     574              : {
     575            0 :     return m_masterAuxSendsParamsChanged;
     576              : }
     577              : 
     578            0 : void Playback::processInput(const TrackId trackId) const
     579              : {
     580              :     ONLY_AUDIO_MAIN_THREAD;
     581            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ProcessInput, RpcPacker::pack(trackId));
     582            0 :     channel()->send(msg);
     583            0 : }
     584              : 
     585            0 : muse::async::Promise<InputProcessingProgress> Playback::inputProcessingProgress(const TrackId trackId) const
     586              : {
     587              :     ONLY_AUDIO_MAIN_THREAD;
     588            0 :     return async::make_promise<InputProcessingProgress>([this, trackId](auto resolve, auto reject) {
     589              :         ONLY_AUDIO_MAIN_THREAD;
     590            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetInputProcessingProgress, RpcPacker::pack(trackId));
     591            0 :         channel()->send(msg, [this, trackId, resolve, reject](const Msg& res) {
     592              :             ONLY_AUDIO_MAIN_THREAD;
     593            0 :             Ret ret;
     594            0 :             bool isStarted = false;
     595            0 :             StreamId streamId = 0;
     596            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret, isStarted, streamId)) {
     597            0 :                 doReject(MsgCode::GetInputProcessingProgress, reject, audio::make_ret(Err::InvalidRpcData));
     598            0 :                 return;
     599              :             }
     600              : 
     601            0 :             if (ret) {
     602            0 :                 InputProcessingProgress prog;
     603            0 :                 prog.isStarted = isStarted;
     604            0 :                 channel()->addReceiveStream(ctxId(), StreamName::InputProcessingProgressStream, streamId, prog.processedChannel);
     605            0 :                 addTrackStream(trackId, streamId);
     606            0 :                 (void)resolve(prog);
     607            0 :             } else {
     608            0 :                 doReject(MsgCode::GetInputProcessingProgress, reject, ret);
     609              :             }
     610            0 :         });
     611            0 :         return Promise<InputProcessingProgress>::dummy_result();
     612            0 :     }, PromiseType::AsyncByBody);
     613              : }
     614              : 
     615            0 : void Playback::clearCache(const TrackId trackId) const
     616              : {
     617              :     ONLY_AUDIO_MAIN_THREAD;
     618            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ClearCache, RpcPacker::pack(trackId));
     619            0 :     channel()->send(msg);
     620            0 : }
     621              : 
     622            0 : void Playback::clearSources()
     623              : {
     624              :     ONLY_AUDIO_MAIN_THREAD;
     625            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ClearSources);
     626            0 :     channel()->send(msg);
     627            0 : }
     628              : 
     629            0 : void Playback::clearMasterOutputParams()
     630              : {
     631              :     ONLY_AUDIO_MAIN_THREAD;
     632            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ClearMasterOutputParams);
     633            0 :     channel()->send(msg);
     634            0 : }
     635              : 
     636            0 : void Playback::clearAllFx()
     637              : {
     638              :     ONLY_AUDIO_MAIN_THREAD;
     639            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::ClearAllFx);
     640            0 :     channel()->send(msg);
     641            0 : }
     642              : 
     643              : // Signals
     644            2 : async::Promise<AudioSignalChanges> Playback::signalChanges(const TrackId trackId) const
     645              : {
     646              :     ONLY_AUDIO_MAIN_THREAD;
     647            4 :     return async::make_promise<AudioSignalChanges>([this, trackId](auto resolve, auto reject) {
     648              :         ONLY_AUDIO_MAIN_THREAD;
     649            2 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetSignalChanges, RpcPacker::pack(trackId));
     650            4 :         channel()->send(msg, [this, trackId, resolve, reject](const Msg& res) {
     651              :             ONLY_AUDIO_MAIN_THREAD;
     652            2 :             RetVal<StreamId> ret;
     653            2 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     654            0 :                 doReject(MsgCode::GetSignalChanges, reject, audio::make_ret(Err::InvalidRpcData));
     655            0 :                 return;
     656              :             }
     657              : 
     658            2 :             if (ret.ret) {
     659            2 :                 AudioSignalChanges ch;
     660            2 :                 channel()->addReceiveStream(ctxId(), StreamName::AudioSignalStream, ret.val, ch);
     661            2 :                 addTrackStream(trackId, ret.val);
     662            2 :                 (void)resolve(ch);
     663            2 :             } else {
     664            0 :                 doReject(MsgCode::GetSignalChanges, reject, ret.ret);
     665              :             }
     666            2 :         });
     667            4 :         return Promise<AudioSignalChanges>::dummy_result();
     668            6 :     }, PromiseType::AsyncByBody);
     669              : }
     670              : 
     671            0 : async::Promise<AudioSignalChanges> Playback::masterSignalChanges() const
     672              : {
     673            0 :     return signalChanges(MASTER_TRACK_ID);
     674              : }
     675              : 
     676            0 : async::Promise<AutomatedControlParamsChanges> Playback::automatedControlParamsChanges(const TrackId trackId) const
     677              : {
     678              :     ONLY_AUDIO_MAIN_THREAD;
     679            0 :     return async::make_promise<AutomatedControlParamsChanges>([this, trackId](auto resolve, auto reject) {
     680              :         ONLY_AUDIO_MAIN_THREAD;
     681            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetAutomatedControlParamsChanges, RpcPacker::pack(trackId));
     682            0 :         channel()->send(msg, [this, trackId, resolve, reject](const Msg& res) {
     683              :             ONLY_AUDIO_MAIN_THREAD;
     684            0 :             RetVal<StreamId> ret;
     685            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     686            0 :                 doReject(MsgCode::GetAutomatedControlParamsChanges, reject, audio::make_ret(Err::InvalidRpcData));
     687            0 :                 return;
     688              :             }
     689              : 
     690            0 :             if (ret.ret) {
     691            0 :                 AutomatedControlParamsChanges ch;
     692            0 :                 channel()->addReceiveStream(ctxId(), StreamName::AutomatedControlParamsStream, ret.val, ch);
     693            0 :                 addTrackStream(trackId, ret.val);
     694            0 :                 (void)resolve(ch);
     695            0 :             } else {
     696            0 :                 doReject(MsgCode::GetAutomatedControlParamsChanges, reject, ret.ret);
     697              :             }
     698            0 :         });
     699            0 :         return Promise<AutomatedControlParamsChanges>::dummy_result();
     700            0 :     }, PromiseType::AsyncByBody);
     701              : }
     702              : 
     703            0 : async::Promise<bool> Playback::saveSoundTrack(const SoundTrackFormat& format, io::IODevice& dstDevice)
     704              : {
     705              :     ONLY_AUDIO_MAIN_THREAD;
     706            0 :     return async::make_promise<bool>([this, format, &dstDevice](auto resolve, auto reject) {
     707              :         ONLY_AUDIO_MAIN_THREAD;
     708            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::SaveSoundTrack, RpcPacker::pack(format, reinterpret_cast<uintptr_t>(&dstDevice)));
     709            0 :         channel()->send(msg, [resolve, reject](const Msg& res) {
     710              :             ONLY_AUDIO_MAIN_THREAD;
     711            0 :             Ret ret;
     712            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     713            0 :                 doReject(MsgCode::SaveSoundTrack, reject, audio::make_ret(Err::InvalidRpcData));
     714            0 :                 return;
     715              :             }
     716              : 
     717            0 :             if (ret) {
     718            0 :                 (void)resolve(true);
     719              :             } else {
     720            0 :                 doReject(MsgCode::SaveSoundTrack, reject, ret);
     721              :             }
     722            0 :         });
     723            0 :         return Promise<bool>::dummy_result();
     724            0 :     }, PromiseType::AsyncByBody);
     725              : }
     726              : 
     727            0 : void Playback::abortSavingAllSoundTracks()
     728              : {
     729              :     ONLY_AUDIO_MAIN_THREAD;
     730            0 :     Msg msg = rpc::make_request(ctxId(), MsgCode::AbortSavingAllSoundTracks);
     731            0 :     channel()->send(msg);
     732            0 : }
     733              : 
     734            0 : SaveSoundTrackProgress Playback::saveSoundTrackProgressChanged() const
     735              : {
     736            0 :     if (!m_saveSoundTrackProgressStreamInited) {
     737            0 :         Msg msg = rpc::make_request(ctxId(), MsgCode::GetSaveSoundTrackProgress);
     738            0 :         channel()->send(msg, [this](const Msg& res) {
     739              :             ONLY_AUDIO_MAIN_THREAD;
     740            0 :             RetVal<StreamId> ret;
     741            0 :             IF_ASSERT_FAILED(RpcPacker::unpack(res.data, ret)) {
     742            0 :                 return;
     743              :             }
     744              : 
     745            0 :             if (!ret.ret) {
     746            0 :                 LOGE() << "GetSaveSoundTrackProgress failed: " << ret.ret.toString();
     747            0 :                 return;
     748              :             }
     749              : 
     750            0 :             if (m_saveSoundTrackProgressStreamId == 0) {
     751            0 :                 m_saveSoundTrackProgressStreamId = ret.val;
     752            0 :                 channel()->addReceiveStream(ctxId(), StreamName::SaveSoundTrackProgressStream,
     753              :                                             m_saveSoundTrackProgressStreamId,
     754            0 :                                             m_saveSoundTrackProgressStream);
     755              :             }
     756              : 
     757            0 :             assert(m_saveSoundTrackProgressStreamId == ret.val);
     758            0 :         });
     759              : 
     760            0 :         m_saveSoundTrackProgressStreamInited = true;
     761            0 :     }
     762              : 
     763            0 :     return m_saveSoundTrackProgressStream;
     764              : }
        

Generated by: LCOV version 2.0-1