diff --git a/linphone-app/src/components/chat-room/ChatRoomModel.cpp b/linphone-app/src/components/chat-room/ChatRoomModel.cpp index 6fe698752..2ee0aa3c4 100644 --- a/linphone-app/src/components/chat-room/ChatRoomModel.cpp +++ b/linphone-app/src/components/chat-room/ChatRoomModel.cpp @@ -663,6 +663,7 @@ void ChatRoomModel::sendMessage (const QString &message) { _message= mChatRoom->createEmptyMessage(); auto recorder = CoreManager::getInstance()->getRecorderManager(); if(recorder->haveVocalRecorder()) { + recorder->getVocalRecorder()->stop(); auto content = recorder->getVocalRecorder()->getRecorder()->createContent(); if(content) _message->addContent(content); @@ -672,6 +673,8 @@ void ChatRoomModel::sendMessage (const QString &message) { _message->send(); emit messageSent(_message); setReply(nullptr); + if(recorder->haveVocalRecorder()) + recorder->clearVocalRecorder(); } void ChatRoomModel::sendFileMessage (const QString &path) { diff --git a/linphone-app/src/components/sound-player/SoundPlayer.cpp b/linphone-app/src/components/sound-player/SoundPlayer.cpp index 579f086d4..2beedeb90 100644 --- a/linphone-app/src/components/sound-player/SoundPlayer.cpp +++ b/linphone-app/src/components/sound-player/SoundPlayer.cpp @@ -32,200 +32,200 @@ using namespace std; namespace { - int ForceCloseTimerInterval = 20; + int ForceCloseTimerInterval = 20; } class SoundPlayer::Handlers : public linphone::PlayerListener { public: - Handlers (SoundPlayer *soundPlayer) { - mSoundPlayer = soundPlayer; - } - + Handlers (SoundPlayer *soundPlayer) { + mSoundPlayer = soundPlayer; + } + private: - void onEofReached (const shared_ptr &) override { - QMutex &mutex = mSoundPlayer->mForceCloseMutex; - // Workaround. - // This callback is called in a standard thread of mediastreamer, not a QThread. - // Signals, connect functions, timers... are unavailable. - mutex.lock(); - mSoundPlayer->mForceClose = true; - mutex.unlock(); - } - SoundPlayer *mSoundPlayer; + void onEofReached (const shared_ptr &) override { + QMutex &mutex = mSoundPlayer->mForceCloseMutex; + // Workaround. + // This callback is called in a standard thread of mediastreamer, not a QThread. + // Signals, connect functions, timers... are unavailable. + mutex.lock(); + mSoundPlayer->mForceClose = true; + mutex.unlock(); + } + SoundPlayer *mSoundPlayer; }; // ----------------------------------------------------------------------------- SoundPlayer::SoundPlayer (QObject *parent) : QObject(parent) { - CoreManager *coreManager = CoreManager::getInstance(); - SettingsModel *settingsModel = coreManager->getSettingsModel(); - mForceCloseTimer = new QTimer(this); - - mForceCloseTimer->setInterval(ForceCloseTimerInterval); - QObject::connect(mForceCloseTimer, &QTimer::timeout, this, &SoundPlayer::handleEof); - mHandlers = make_shared(this); -// Connection to rebuilding player when changing ringer selection. This player is only for Ringer. - QObject::connect(settingsModel, &SettingsModel::ringerDeviceChanged, this, [this] { - rebuildInternalPlayer(); - }); - buildInternalPlayer(); + CoreManager *coreManager = CoreManager::getInstance(); + SettingsModel *settingsModel = coreManager->getSettingsModel(); + mForceCloseTimer = new QTimer(this); + + mForceCloseTimer->setInterval(ForceCloseTimerInterval); + QObject::connect(mForceCloseTimer, &QTimer::timeout, this, &SoundPlayer::handleEof); + mHandlers = make_shared(this); + // Connection to rebuilding player when changing ringer selection. This player is only for Ringer. + QObject::connect(settingsModel, &SettingsModel::ringerDeviceChanged, this, [this] { + rebuildInternalPlayer(); + }); + buildInternalPlayer(); } SoundPlayer::~SoundPlayer () { - mForceCloseTimer->stop(); - if( mInternalPlayer) - mInternalPlayer->close(); + mForceCloseTimer->stop(); + if( mInternalPlayer) + mInternalPlayer->close(); } // ----------------------------------------------------------------------------- void SoundPlayer::pause () { - if (mPlaybackState == SoundPlayer::PausedState) - return; - if (mInternalPlayer->pause()) { - setError(QStringLiteral("Unable to pause: `%1`").arg(mSource)); - return; - } - mForceCloseTimer->stop(); - mPlaybackState = SoundPlayer::PausedState; - - emit paused(); - emit playbackStateChanged(mPlaybackState); + if (mPlaybackState == SoundPlayer::PausedState) + return; + if (mInternalPlayer->pause()) { + setError(QStringLiteral("Unable to pause: `%1`").arg(mSource)); + return; + } + mForceCloseTimer->stop(); + mPlaybackState = SoundPlayer::PausedState; + + emit paused(); + emit playbackStateChanged(mPlaybackState); } void SoundPlayer::play () { - if (mPlaybackState == SoundPlayer::PlayingState) - return; - if ( - (mPlaybackState == SoundPlayer::StoppedState || mPlaybackState == SoundPlayer::ErrorState) && - mInternalPlayer->open(Utils::appStringToCoreString(mSource)) - ) { - qWarning() << QStringLiteral("Unable to open: `%1`").arg(mSource); - return; - } - if (mInternalPlayer->start() - ) { - setError(QStringLiteral("Unable to play: `%1`").arg(mSource)); - return; - } - mForceCloseTimer->start(); - mPlaybackState = SoundPlayer::PlayingState; - - emit playing(); - emit playbackStateChanged(mPlaybackState); + if (mPlaybackState == SoundPlayer::PlayingState || mSource == "") + return; + if ( + (mPlaybackState == SoundPlayer::StoppedState || mPlaybackState == SoundPlayer::ErrorState) && + mInternalPlayer->open(Utils::appStringToCoreString(mSource)) + ) { + qWarning() << QStringLiteral("Unable to open: `%1`").arg(mSource); + return; + } + if (mInternalPlayer->start() + ) { + setError(QStringLiteral("Unable to play: `%1`").arg(mSource)); + return; + } + mForceCloseTimer->start(); + mPlaybackState = SoundPlayer::PlayingState; + + emit playing(); + emit playbackStateChanged(mPlaybackState); } void SoundPlayer::stop () { - stop(false); + stop(false); } // ----------------------------------------------------------------------------- void SoundPlayer::seek (int offset) { - mInternalPlayer->seek(offset); + mInternalPlayer->seek(offset); } // ----------------------------------------------------------------------------- int SoundPlayer::getPosition () const { - return mInternalPlayer->getCurrentPosition(); + return mInternalPlayer->getCurrentPosition(); } // ----------------------------------------------------------------------------- void SoundPlayer::buildInternalPlayer () { - CoreManager *coreManager = CoreManager::getInstance(); - SettingsModel *settingsModel = coreManager->getSettingsModel(); - - mInternalPlayer = coreManager->getCore()->createLocalPlayer( - Utils::appStringToCoreString(settingsModel->getRingerDevice()), "", nullptr - ); - if(mInternalPlayer) - mInternalPlayer->addListener(mHandlers); + CoreManager *coreManager = CoreManager::getInstance(); + SettingsModel *settingsModel = coreManager->getSettingsModel(); + + mInternalPlayer = coreManager->getCore()->createLocalPlayer( + Utils::appStringToCoreString(settingsModel->getRingerDevice()), "", nullptr + ); + if(mInternalPlayer) + mInternalPlayer->addListener(mHandlers); } void SoundPlayer::rebuildInternalPlayer () { - stop(true); - buildInternalPlayer(); + stop(true); + buildInternalPlayer(); } void SoundPlayer::stop (bool force) { - if (mPlaybackState == SoundPlayer::StoppedState && !force) - return; - mForceCloseTimer->stop(); - mPlaybackState = SoundPlayer::StoppedState; - if(mInternalPlayer) - mInternalPlayer->close(); - - emit stopped(); - emit playbackStateChanged(mPlaybackState); + if (mPlaybackState == SoundPlayer::StoppedState && !force) + return; + mForceCloseTimer->stop(); + mPlaybackState = SoundPlayer::StoppedState; + if(mInternalPlayer) + mInternalPlayer->close(); + + emit stopped(); + emit playbackStateChanged(mPlaybackState); } // ----------------------------------------------------------------------------- void SoundPlayer::handleEof () { - mForceCloseMutex.lock(); - - if (mForceClose) { - mForceClose = false; - stop(); - } - - mForceCloseMutex.unlock(); + mForceCloseMutex.lock(); + + if (mForceClose) { + mForceClose = false; + stop(); + } + + mForceCloseMutex.unlock(); } // ----------------------------------------------------------------------------- void SoundPlayer::setError (const QString &message) { - qWarning() << message; - mInternalPlayer->close(); - - if (mPlaybackState != SoundPlayer::ErrorState) { - mPlaybackState = SoundPlayer::ErrorState; - emit playbackStateChanged(mPlaybackState); - } + qWarning() << message; + mInternalPlayer->close(); + + if (mPlaybackState != SoundPlayer::ErrorState) { + mPlaybackState = SoundPlayer::ErrorState; + emit playbackStateChanged(mPlaybackState); + } } // ----------------------------------------------------------------------------- QString SoundPlayer::getSource () const { - return mSource; + return mSource; } void SoundPlayer::setSource (const QString &source) { - if (source == mSource) - return; - - stop(); - mSource = source; - - emit sourceChanged(source); + if (source == mSource) + return; + + stop(); + mSource = source; + + emit sourceChanged(source); } // ----------------------------------------------------------------------------- SoundPlayer::PlaybackState SoundPlayer::getPlaybackState () const { - return mPlaybackState; + return mPlaybackState; } void SoundPlayer::setPlaybackState (PlaybackState playbackState) { - switch (playbackState) { - case PlayingState: - play(); - break; - case PausedState: - pause(); - break; - case StoppedState: - stop(); - break; - case ErrorState: - break; - } + switch (playbackState) { + case PlayingState: + play(); + break; + case PausedState: + pause(); + break; + case StoppedState: + stop(); + break; + case ErrorState: + break; + } } // ----------------------------------------------------------------------------- int SoundPlayer::getDuration () const { - return mInternalPlayer->getDuration(); + return mInternalPlayer->getDuration(); } diff --git a/linphone-app/src/components/sound-player/SoundPlayer.hpp b/linphone-app/src/components/sound-player/SoundPlayer.hpp index 0dc18309c..7276deb55 100644 --- a/linphone-app/src/components/sound-player/SoundPlayer.hpp +++ b/linphone-app/src/components/sound-player/SoundPlayer.hpp @@ -31,75 +31,75 @@ class QTimer; namespace linphone { - class Player; + class Player; } class SoundPlayer : public QObject { - class Handlers; - - Q_OBJECT - - Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY playbackStateChanged) - Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged) - + class Handlers; + + Q_OBJECT + + Q_PROPERTY(QString source READ getSource WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(PlaybackState playbackState READ getPlaybackState WRITE setPlaybackState NOTIFY playbackStateChanged) + Q_PROPERTY(int duration READ getDuration NOTIFY sourceChanged) + public: - enum PlaybackState { - PlayingState, - PausedState, - StoppedState, - ErrorState - }; - Q_ENUM(PlaybackState); - - SoundPlayer (QObject *parent = Q_NULLPTR); - ~SoundPlayer (); - - Q_INVOKABLE void pause (); - Q_INVOKABLE void play (); - Q_INVOKABLE void stop (); - - Q_INVOKABLE void seek (int offset); - - Q_INVOKABLE int getPosition () const; - + enum PlaybackState { + PlayingState, + PausedState, + StoppedState, + ErrorState + }; + Q_ENUM(PlaybackState); + + SoundPlayer (QObject *parent = Q_NULLPTR); + ~SoundPlayer (); + + Q_INVOKABLE void pause (); + Q_INVOKABLE void play (); + Q_INVOKABLE void stop (); + + Q_INVOKABLE void seek (int offset); + + Q_INVOKABLE int getPosition () const; + signals: - void sourceChanged (const QString &source); - - void paused (); - void playing (); - void stopped (); - - void playbackStateChanged (PlaybackState playbackState); - + void sourceChanged (const QString &source); + + void paused (); + void playing (); + void stopped (); + + void playbackStateChanged (PlaybackState playbackState); + private: - void buildInternalPlayer (); - void rebuildInternalPlayer (); - - void stop (bool force); - - void handleEof (); - - void setError (const QString &message); - - QString getSource () const; - void setSource (const QString &source); - - PlaybackState getPlaybackState () const; - void setPlaybackState (PlaybackState playbackState); - - int getDuration () const; - - QString mSource; - PlaybackState mPlaybackState = StoppedState; - - bool mForceClose = false; - QMutex mForceCloseMutex; - - QTimer *mForceCloseTimer = nullptr; - - std::shared_ptr mInternalPlayer; - std::shared_ptr mHandlers; + void buildInternalPlayer (); + void rebuildInternalPlayer (); + + void stop (bool force); + + void handleEof (); + + void setError (const QString &message); + + QString getSource () const; + void setSource (const QString &source); + + PlaybackState getPlaybackState () const; + void setPlaybackState (PlaybackState playbackState); + + int getDuration () const; + + QString mSource; + PlaybackState mPlaybackState = StoppedState; + + bool mForceClose = false; + QMutex mForceCloseMutex; + + QTimer *mForceCloseTimer = nullptr; + + std::shared_ptr mInternalPlayer; + std::shared_ptr mHandlers; }; #endif // SOUND_PLAYER_H_ diff --git a/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml b/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml index a7553aebe..30fffcce9 100644 --- a/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml +++ b/linphone-app/ui/modules/Common/Indicators/MediaProgressBar.qml @@ -17,7 +17,7 @@ ProgressBar { property bool stopAtEnd: true property bool resetAtEnd: false property int progressDuration // Max duration - property int progressPosition // Position of pregress bar in [0 ; progressDuration] + property int progressPosition // Position of progress bar in [0 ; progressDuration] property alias colorSet: progression.colorSet function start(){ @@ -54,7 +54,6 @@ ProgressBar { progressBar.value = 100// Stay at 100 progressPosition = progressDuration } - progressBar.endReached() }else progression.percentageDisplayed = value diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml b/linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml index 5e1b4cb6a..689898c7d 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatAudioPreview.qml @@ -22,10 +22,8 @@ Rectangle{ property bool isRecording : (vocalRecorder ? vocalRecorder.state != LinphoneEnums.RecorderStateClosed : false) property bool isPlaying : vocalPlayer.item && vocalPlayer.item.playbackState === SoundPlayer.PlayingState - onVocalRecorderChanged: if(haveRecorder) - audioPreviewBlock.state = 'showed' onIsRecordingChanged: if(isRecording) { - mediaProgressBar.start() + mediaProgressBar.resume() }else mediaProgressBar.stop() onIsPlayingChanged: isPlaying ? mediaProgressBar.resume() : mediaProgressBar.stop() @@ -34,25 +32,22 @@ Rectangle{ color: ChatAudioPreviewStyle.backgroundColor radius: 0 - state: "hidden" - visible: haveRecorder - onVisibleChanged: if(!visible) hide() + state: haveRecorder ? 'showed' : 'hidden' clip: false - function hide(){ - state = 'hidden' - } Loader { id: vocalPlayer - active: false + active: haveRecorder && vocalRecorder && !isRecording sourceComponent: SoundPlayer { source: (haveRecorder && vocalRecorder? vocalRecorder.file : '') onStopped:{ - mediaProgressBar.value = 100 + mediaProgressBar.value = 101 } Component.onCompleted: { play()// This will open the file and allow seeking pause() + mediaProgressBar.value = 101 + mediaProgressBar.refresh() } } } @@ -67,7 +62,7 @@ Rectangle{ Layout.alignment: Qt.AlignVCenter isCustom: true colorSet: ChatAudioPreviewStyle.deleteAction - onClicked: audioPreviewBlock.hide() + onClicked: RecorderManager.clearVocalRecorder() } Item{ Layout.fillHeight: true @@ -78,23 +73,27 @@ Rectangle{ MediaProgressBar{ id: mediaProgressBar anchors.fill: parent - progressDuration: 0 - progressPosition: 0 + progressDuration: !vocalPlayer.item ? vocalRecorder.getDuration() : 0 + progressPosition: !vocalPlayer.item ? progressDuration : 0 + value: !vocalPlayer.item ? 0.01 * progressDuration / 5 : 100 stopAtEnd: !audioPreviewBlock.isRecording resetAtEnd: false colorSet: isRecording ? ChatAudioPreviewStyle.recordingProgressionWave : ChatAudioPreviewStyle.progressionWave + function refresh(){ + if( vocalPlayer.item){ + progressPosition = vocalPlayer.item.getPosition() + value = 100 * ( progressPosition / vocalPlayer.item.duration) + }else{// Recording + progressDuration = vocalRecorder.getDuration() + progressPosition = progressDuration + value = value + 0.01 + } + } onEndReached:{ if(vocalPlayer.item) vocalPlayer.item.stop() } - onRefreshPositionRequested: if( vocalPlayer.item){ - progressPosition = vocalPlayer.item.getPosition() - value = 100 * ( progressPosition / vocalPlayer.item.duration) - }else{// Recording - progressDuration = vocalRecorder.getDuration() - progressPosition = progressDuration - value = value + 0.01 - } + onRefreshPositionRequested: refresh() onSeekRequested: if( vocalPlayer.item){ vocalPlayer.item.seek(ms) progressPosition = vocalPlayer.item.getPosition() @@ -115,8 +114,7 @@ Rectangle{ onClicked:{ if(audioPreviewBlock.isRecording){// Stop the record and save the file audioPreviewBlock.vocalRecorder.stop() - mediaProgressBar.value = 100 - vocalPlayer.active = true + //mediaProgressBar.value = 100 }else if(audioPreviewBlock.isPlaying){// Pause the play vocalPlayer.item.pause() }else{// Play the audio @@ -128,17 +126,18 @@ Rectangle{ states: [ State { name: "hidden" - PropertyChanges { target: audioPreviewBlock; opacity: 0 } + PropertyChanges { target: audioPreviewBlock; opacity: 0 ; visible: false } }, State { name: "showed" - PropertyChanges { target: audioPreviewBlock; opacity: 1 } + PropertyChanges { target: audioPreviewBlock; opacity: 1 ; visible: true } } ] transitions: [ Transition { from: "*"; to: "showed" SequentialAnimation{ + ScriptAction{ script: audioPreviewBlock.visible = true } ScriptAction{ script: audioPreviewBlock.vocalRecorder.start() } NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 250 } } @@ -146,9 +145,8 @@ Rectangle{ Transition { from: "*"; to: "hidden" SequentialAnimation{ - ScriptAction{ script: RecorderManager.clearVocalRecorder()} - ScriptAction{ script: vocalPlayer.active = false } NumberAnimation{ properties: "opacity"; duration: 250 } + ScriptAction{ script: audioPreviewBlock.visible = false } } } ] diff --git a/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml b/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml index d406d2649..a2a75fb71 100644 --- a/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml +++ b/linphone-app/ui/modules/Linphone/Chat/ChatMessagePreview.qml @@ -22,7 +22,6 @@ ColumnLayout{ spacing: 0 function hide(){ - audioPreview.hide() } ChatReplyPreview{ id: replyPreview diff --git a/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml b/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml index db6cd5023..414941252 100644 --- a/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml +++ b/linphone-app/ui/modules/Linphone/Dialog/SipAddressDialog.qml @@ -58,7 +58,7 @@ DialogPlus { return UtilsCpp.hasCapability(entry.sipAddress, LinphoneEnums.FriendCapabilityLimeX3Dh) }, handler: function (entry) { - mainItem.addressSelectedCallback(sipAddress) + mainItem.addressSelectedCallback(entry.sipAddress) exit(1) }, }]