Fix some bugs in double playback speed.

- Apply double speed for all voice tracks, not only for the current.
- Use dedicated atomic in Mixer for the voice speed (fix race).
- Store the playback speed in user settings, not in global settings.
- Use float64 for setting (just consistency, no float-s right now).
This commit is contained in:
John Preston 2018-11-08 17:06:22 +04:00
parent de8518a112
commit 346cb4e203
8 changed files with 60 additions and 34 deletions

View File

@ -649,7 +649,7 @@ struct Data {
bool SuggestEmoji = true; bool SuggestEmoji = true;
bool SuggestStickersByEmoji = true; bool SuggestStickersByEmoji = true;
base::Observable<void> ReplaceEmojiChanged; base::Observable<void> ReplaceEmojiChanged;
float VoiceMsgPlaybackSpeed = 1.f; float64 VoiceMsgPlaybackSpeed = 1.;
bool SoundNotify = true; bool SoundNotify = true;
bool DesktopNotify = true; bool DesktopNotify = true;
bool RestoreSoundNotifyFromTray = false; bool RestoreSoundNotifyFromTray = false;
@ -779,7 +779,7 @@ DefineVar(Global, bool, ReplaceEmoji);
DefineVar(Global, bool, SuggestEmoji); DefineVar(Global, bool, SuggestEmoji);
DefineVar(Global, bool, SuggestStickersByEmoji); DefineVar(Global, bool, SuggestStickersByEmoji);
DefineRefVar(Global, base::Observable<void>, ReplaceEmojiChanged); DefineRefVar(Global, base::Observable<void>, ReplaceEmojiChanged);
DefineVar(Global, float, VoiceMsgPlaybackSpeed); DefineVar(Global, float64, VoiceMsgPlaybackSpeed);
DefineVar(Global, bool, SoundNotify); DefineVar(Global, bool, SoundNotify);
DefineVar(Global, bool, DesktopNotify); DefineVar(Global, bool, DesktopNotify);
DefineVar(Global, bool, RestoreSoundNotifyFromTray); DefineVar(Global, bool, RestoreSoundNotifyFromTray);

View File

@ -304,7 +304,7 @@ DeclareVar(bool, ReplaceEmoji);
DeclareVar(bool, SuggestEmoji); DeclareVar(bool, SuggestEmoji);
DeclareVar(bool, SuggestStickersByEmoji); DeclareVar(bool, SuggestStickersByEmoji);
DeclareRefVar(base::Observable<void>, ReplaceEmojiChanged); DeclareRefVar(base::Observable<void>, ReplaceEmojiChanged);
DeclareVar(float, VoiceMsgPlaybackSpeed); DeclareVar(float64, VoiceMsgPlaybackSpeed);
DeclareVar(bool, SoundNotify); DeclareVar(bool, SoundNotify);
DeclareVar(bool, DesktopNotify); DeclareVar(bool, DesktopNotify);
DeclareVar(bool, RestoreSoundNotifyFromTray); DeclareVar(bool, RestoreSoundNotifyFromTray);

View File

@ -318,14 +318,16 @@ Mixer *mixer() {
return Audio::MixerInstance; return Audio::MixerInstance;
} }
void Mixer::Track::createStream() { void Mixer::Track::createStream(AudioMsgId::Type type) {
alGenSources(1, &stream.source); alGenSources(1, &stream.source);
alSourcef(stream.source, AL_PITCH, 1.f); alSourcef(stream.source, AL_PITCH, 1.f);
alSource3f(stream.source, AL_POSITION, 0, 0, 0); alSource3f(stream.source, AL_POSITION, 0, 0, 0);
alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); alSource3f(stream.source, AL_VELOCITY, 0, 0, 0);
alSourcei(stream.source, AL_LOOPING, 0); alSourcei(stream.source, AL_LOOPING, 0);
alGenBuffers(3, stream.buffers); alGenBuffers(3, stream.buffers);
mixer()->updatePlaybackSpeed(); if (type == AudioMsgId::Type::Voice) {
mixer()->updatePlaybackSpeed(this);
}
} }
void Mixer::Track::destroyStream() { void Mixer::Track::destroyStream() {
@ -344,7 +346,7 @@ void Mixer::Track::reattach(AudioMsgId::Type type) {
return; return;
} }
createStream(); createStream(type);
for (auto i = 0; i != kBuffersCount; ++i) { for (auto i = 0; i != kBuffersCount; ++i) {
if (!samplesCount[i]) { if (!samplesCount[i]) {
break; break;
@ -415,9 +417,9 @@ bool Mixer::Track::isStreamCreated() const {
return alIsSource(stream.source); return alIsSource(stream.source);
} }
void Mixer::Track::ensureStreamCreated() { void Mixer::Track::ensureStreamCreated(AudioMsgId::Type type) {
if (!isStreamCreated()) { if (!isStreamCreated()) {
createStream(); createStream(type);
} }
} }
@ -1019,26 +1021,30 @@ void Mixer::stop(const AudioMsgId &audio, State state) {
if (current) emit updated(current); if (current) emit updated(current);
} }
void Mixer::updatePlaybackSpeed() // Thread: Any. Must be locked: AudioMutex.
{ void Mixer::updatePlaybackSpeed(Track *track) {
const auto track = trackForType(AudioMsgId::Type::Voice); const auto doubled = (_voicePlaybackSpeed.loadAcquire() == 2);
if (!track || track->state.id.type() != AudioMsgId::Type::Voice || !track->isStreamCreated()) { updatePlaybackSpeed(track, doubled);
}
void Mixer::updatePlaybackSpeed(Track *track, bool doubled) {
if (!track->isStreamCreated()) {
return; return;
} }
const auto src = track->stream.source; const auto source = track->stream.source;
// Note: This alters the playback speed AND the pitch // Note: This alters the playback speed AND the pitch
alSourcef(src, AL_PITCH, Global::VoiceMsgPlaybackSpeed()); alSourcef(source, AL_PITCH, doubled ? 2. : 1.);
// fix the pitch using effects and filters // fix the pitch using effects and filters
if (Global::VoiceMsgPlaybackSpeed() > 1.f) { if (doubled) {
// connect the effect slot with the stream // connect the effect slot with the stream
alSource3i(src, AL_AUXILIARY_SEND_FILTER, Media::Audio::_playbackSpeedData.uiEffectSlot, 0, 0); alSource3i(source, AL_AUXILIARY_SEND_FILTER, Media::Audio::_playbackSpeedData.uiEffectSlot, 0, 0);
// connect the filter with the stream // connect the filter with the stream
alSourcei(src, AL_DIRECT_FILTER, Media::Audio::_playbackSpeedData.uiFilter); alSourcei(source, AL_DIRECT_FILTER, Media::Audio::_playbackSpeedData.uiFilter);
} else { } else {
// disconnect the effect slot // disconnect the effect slot
alSource3i(src, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, 0); alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, 0);
// disconnect the filter // disconnect the filter
alSourcei(src, AL_DIRECT_FILTER, AL_FILTER_NULL); alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
} }
} }
@ -1143,6 +1149,17 @@ void Mixer::reattachTracks() {
_videoTrack.reattach(AudioMsgId::Type::Video); _videoTrack.reattach(AudioMsgId::Type::Video);
} }
// Thread: Any. Locks AudioMutex.
void Mixer::setVoicePlaybackSpeed(float64 speed) {
const auto doubled = (std::round(speed) == 2);
_voicePlaybackSpeed.storeRelease(doubled ? 2 : 1);
QMutexLocker lock(&AudioMutex);
for (auto &track : _audioTracks) {
updatePlaybackSpeed(&track, doubled);
}
}
void Mixer::setSongVolume(float64 volume) { void Mixer::setSongVolume(float64 volume) {
_volumeSong.storeRelease(qRound(volume * kVolumeRound)); _volumeSong.storeRelease(qRound(volume * kVolumeRound));
} }

View File

@ -117,8 +117,6 @@ public:
void stop(const AudioMsgId &audio); void stop(const AudioMsgId &audio);
void stop(const AudioMsgId &audio, State state); void stop(const AudioMsgId &audio, State state);
void updatePlaybackSpeed();
// Video player audio stream interface. // Video player audio stream interface.
void feedFromVideo(VideoSoundPart &&part); void feedFromVideo(VideoSoundPart &&part);
int64 getVideoCorrectedTime(const AudioMsgId &id, TimeMs frameMs, TimeMs systemMs); int64 getVideoCorrectedTime(const AudioMsgId &id, TimeMs frameMs, TimeMs systemMs);
@ -144,6 +142,9 @@ public:
void setVideoVolume(float64 volume); void setVideoVolume(float64 volume);
float64 getVideoVolume() const; float64 getVideoVolume() const;
// Thread: Any. Locks AudioMutex.
void setVoicePlaybackSpeed(float64 speed);
~Mixer(); ~Mixer();
private slots: private slots:
@ -183,7 +184,7 @@ private:
void started(); void started();
bool isStreamCreated() const; bool isStreamCreated() const;
void ensureStreamCreated(); void ensureStreamCreated(AudioMsgId::Type type);
int getNotQueuedBufferIndex(); int getNotQueuedBufferIndex();
@ -215,7 +216,7 @@ private:
TimeMs lastUpdateCorrectedMs = 0; TimeMs lastUpdateCorrectedMs = 0;
private: private:
void createStream(); void createStream(AudioMsgId::Type type);
void destroyStream(); void destroyStream();
void resetStream(); void resetStream();
@ -223,6 +224,8 @@ private:
// Thread: Any. Must be locked: AudioMutex. // Thread: Any. Must be locked: AudioMutex.
void setStoppedState(Track *current, State state = State::Stopped); void setStoppedState(Track *current, State state = State::Stopped);
void updatePlaybackSpeed(Track *track);
void updatePlaybackSpeed(Track *track, bool doubled);
Track *trackForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type) Track *trackForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type)
const Track *trackForType(AudioMsgId::Type type, int index = -1) const; const Track *trackForType(AudioMsgId::Type type, int index = -1) const;
@ -239,6 +242,7 @@ private:
QAtomicInt _volumeVideo; QAtomicInt _volumeVideo;
QAtomicInt _volumeSong; QAtomicInt _volumeSong;
QAtomicInt _voicePlaybackSpeed;
friend class Fader; friend class Fader;
friend class Loaders; friend class Loaders;

View File

@ -206,7 +206,7 @@ void Loaders::loadData(AudioMsgId audio, TimeMs positionMs) {
track->fadeStartPosition = position; track->fadeStartPosition = position;
} }
if (samplesCount) { if (samplesCount) {
track->ensureStreamCreated(); track->ensureStreamCreated(type);
auto bufferIndex = track->getNotQueuedBufferIndex(); auto bufferIndex = track->getNotQueuedBufferIndex();

View File

@ -133,10 +133,11 @@ Widget::Widget(QWidget *parent) : RpWidget(parent)
updatePlaybackSpeedIcon(); updatePlaybackSpeedIcon();
_playbackSpeed->setClickedCallback([=] { _playbackSpeed->setClickedCallback([=] {
Global::SetVoiceMsgPlaybackSpeed(Global::VoiceMsgPlaybackSpeed() == 1.f ? 2.f : 1.f); const auto updated = (3. - Global::VoiceMsgPlaybackSpeed());
mixer()->updatePlaybackSpeed(); Global::SetVoiceMsgPlaybackSpeed(updated);
mixer()->setVoicePlaybackSpeed(updated);
updatePlaybackSpeedIcon(); updatePlaybackSpeedIcon();
Local::writeSettings(); Local::writeUserSettings();
}); });
subscribe(instance()->repeatChangedNotifier(), [this](AudioMsgId::Type type) { subscribe(instance()->repeatChangedNotifier(), [this](AudioMsgId::Type type) {
@ -369,10 +370,9 @@ void Widget::updateRepeatTrackIcon() {
_repeatTrack->setRippleColorOverride(repeating ? nullptr : &st::mediaPlayerRepeatDisabledRippleBg); _repeatTrack->setRippleColorOverride(repeating ? nullptr : &st::mediaPlayerRepeatDisabledRippleBg);
} }
void Widget::updatePlaybackSpeedIcon() void Widget::updatePlaybackSpeedIcon() {
{
const auto playbackSpeed = Global::VoiceMsgPlaybackSpeed(); const auto playbackSpeed = Global::VoiceMsgPlaybackSpeed();
const auto isDefaultSpeed = playbackSpeed == 1.f; const auto isDefaultSpeed = std::round(playbackSpeed) == 1.f;
_playbackSpeed->setIconOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIcon : nullptr, isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIconOver : nullptr); _playbackSpeed->setIconOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIcon : nullptr, isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIconOver : nullptr);
_playbackSpeed->setRippleColorOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledRippleBg : nullptr); _playbackSpeed->setRippleColorOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledRippleBg : nullptr);
} }

View File

@ -510,6 +510,9 @@ void Messenger::startMtp() {
if (_authSession) { if (_authSession) {
// Skip all pending self updates so that we won't Local::writeSelf. // Skip all pending self updates so that we won't Local::writeSelf.
Notify::peerUpdatedSendDelayed(); Notify::peerUpdatedSendDelayed();
Media::Player::mixer()->setVoicePlaybackSpeed(
Global::VoiceMsgPlaybackSpeed());
} }
} }
@ -1114,6 +1117,8 @@ void Messenger::loggedOut() {
} }
clearPasscodeLock(); clearPasscodeLock();
Media::Player::mixer()->stopAndClear(); Media::Player::mixer()->stopAndClear();
Global::SetVoiceMsgPlaybackSpeed(1.);
Media::Player::mixer()->setVoicePlaybackSpeed(1.);
if (const auto w = getActiveWindow()) { if (const auto w = getActiveWindow()) {
w->tempDirDelete(Local::ClearManagerAll); w->tempDirDelete(Local::ClearManagerAll);
w->setupIntro(); w->setupIntro();

View File

@ -1751,11 +1751,11 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
} break; } break;
case dbiPlaybackSpeed: { case dbiPlaybackSpeed: {
quint32 v; qint32 v;
stream >> v; stream >> v;
if (!_checkStreamStatus(stream)) return false; if (!_checkStreamStatus(stream)) return false;
Global::SetVoiceMsgPlaybackSpeed(v); Global::SetVoiceMsgPlaybackSpeed((v == 2) ? 2. : 1.);
} break; } break;
default: default:
@ -1975,7 +1975,7 @@ void _writeUserSettings() {
? userDataInstance->serialize() ? userDataInstance->serialize()
: QByteArray(); : QByteArray();
uint32 size = 22 * (sizeof(quint32) + sizeof(qint32)); uint32 size = 23 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark()); size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32); size += sizeof(quint32) + sizeof(qint32);
@ -2028,6 +2028,7 @@ void _writeUserSettings() {
if (!userData.isEmpty()) { if (!userData.isEmpty()) {
data.stream << quint32(dbiAuthSessionSettings) << userData; data.stream << quint32(dbiAuthSessionSettings) << userData;
} }
data.stream << quint32(dbiPlaybackSpeed) << qint32(std::round(Global::VoiceMsgPlaybackSpeed()));
{ {
data.stream << quint32(dbiRecentEmoji) << recentEmojiPreloadData; data.stream << quint32(dbiRecentEmoji) << recentEmojiPreloadData;
@ -2605,7 +2606,6 @@ void writeSettings() {
data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber(); data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber();
data.stream << quint32(dbiTxtDomainString) << Global::TxtDomainString(); data.stream << quint32(dbiTxtDomainString) << Global::TxtDomainString();
data.stream << quint32(dbiAnimationsDisabled) << qint32(anim::Disabled() ? 1 : 0); data.stream << quint32(dbiAnimationsDisabled) << qint32(anim::Disabled() ? 1 : 0);
data.stream << quint32(dbiPlaybackSpeed) << quint32(Global::VoiceMsgPlaybackSpeed());
data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList); data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList);
data.stream << qint32(proxies.size()); data.stream << qint32(proxies.size());