Removed SongMsgId, unified working with voice/music files in audio.

This commit is contained in:
John Preston 2016-06-30 15:03:32 +03:00
parent d64892584d
commit 7ca5737bc0
13 changed files with 395 additions and 635 deletions

View File

@ -98,7 +98,6 @@ bool _checkALError() {
} }
Q_DECLARE_METATYPE(AudioMsgId); Q_DECLARE_METATYPE(AudioMsgId);
Q_DECLARE_METATYPE(SongMsgId);
Q_DECLARE_METATYPE(VoiceWaveform); Q_DECLARE_METATYPE(VoiceWaveform);
void audioInit() { void audioInit() {
if (!capture) { if (!capture) {
@ -209,7 +208,6 @@ void audioInit() {
if (!_checkALError()) return audioFinish(); if (!_checkALError()) return audioFinish();
qRegisterMetaType<AudioMsgId>(); qRegisterMetaType<AudioMsgId>();
qRegisterMetaType<SongMsgId>();
qRegisterMetaType<VoiceWaveform>(); qRegisterMetaType<VoiceWaveform>();
player = new AudioPlayer(); player = new AudioPlayer();
@ -263,7 +261,8 @@ void audioFinish() {
cSetHasAudioPlayer(false); cSetHasAudioPlayer(false);
} }
void AudioPlayer::Msg::clearData() { void AudioPlayer::AudioMsg::clear() {
audio = AudioMsgId();
file = FileLocation(); file = FileLocation();
data = QByteArray(); data = QByteArray();
position = duration = 0; position = duration = 0;
@ -293,26 +292,18 @@ _loader(new AudioPlayerLoaders(&_loaderThread)) {
connect(this, SIGNAL(suppressAll()), _fader, SLOT(onSuppressAll())); connect(this, SIGNAL(suppressAll()), _fader, SLOT(onSuppressAll()));
connect(this, SIGNAL(songVolumeChanged()), _fader, SLOT(onSongVolumeChanged())); connect(this, SIGNAL(songVolumeChanged()), _fader, SLOT(onSongVolumeChanged()));
connect(this, SIGNAL(loaderOnStart(const AudioMsgId&,qint64)), _loader, SLOT(onStart(const AudioMsgId&,qint64))); connect(this, SIGNAL(loaderOnStart(const AudioMsgId&,qint64)), _loader, SLOT(onStart(const AudioMsgId&,qint64)));
connect(this, SIGNAL(loaderOnStart(const SongMsgId&,qint64)), _loader, SLOT(onStart(const SongMsgId&,qint64)));
connect(this, SIGNAL(loaderOnCancel(const AudioMsgId&)), _loader, SLOT(onCancel(const AudioMsgId&))); connect(this, SIGNAL(loaderOnCancel(const AudioMsgId&)), _loader, SLOT(onCancel(const AudioMsgId&)));
connect(this, SIGNAL(loaderOnCancel(const SongMsgId&)), _loader, SLOT(onCancel(const SongMsgId&)));
connect(&_faderThread, SIGNAL(started()), _fader, SLOT(onInit())); connect(&_faderThread, SIGNAL(started()), _fader, SLOT(onInit()));
connect(&_loaderThread, SIGNAL(started()), _loader, SLOT(onInit())); connect(&_loaderThread, SIGNAL(started()), _loader, SLOT(onInit()));
connect(&_faderThread, SIGNAL(finished()), _fader, SLOT(deleteLater())); connect(&_faderThread, SIGNAL(finished()), _fader, SLOT(deleteLater()));
connect(&_loaderThread, SIGNAL(finished()), _loader, SLOT(deleteLater())); connect(&_loaderThread, SIGNAL(finished()), _loader, SLOT(deleteLater()));
connect(_loader, SIGNAL(needToCheck()), _fader, SLOT(onTimer())); connect(_loader, SIGNAL(needToCheck()), _fader, SLOT(onTimer()));
connect(_loader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&))); connect(_loader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
connect(_loader, SIGNAL(error(const SongMsgId&)), this, SLOT(onError(const SongMsgId&)));
connect(_fader, SIGNAL(needToPreload(const AudioMsgId&)), _loader, SLOT(onLoad(const AudioMsgId&))); connect(_fader, SIGNAL(needToPreload(const AudioMsgId&)), _loader, SLOT(onLoad(const AudioMsgId&)));
connect(_fader, SIGNAL(needToPreload(const SongMsgId&)), _loader, SLOT(onLoad(const SongMsgId&)));
connect(_fader, SIGNAL(playPositionUpdated(const AudioMsgId&)), this, SIGNAL(updated(const AudioMsgId&))); connect(_fader, SIGNAL(playPositionUpdated(const AudioMsgId&)), this, SIGNAL(updated(const AudioMsgId&)));
connect(_fader, SIGNAL(playPositionUpdated(const SongMsgId&)), this, SIGNAL(updated(const SongMsgId&)));
connect(_fader, SIGNAL(audioStopped(const AudioMsgId&)), this, SLOT(onStopped(const AudioMsgId&))); connect(_fader, SIGNAL(audioStopped(const AudioMsgId&)), this, SLOT(onStopped(const AudioMsgId&)));
connect(_fader, SIGNAL(audioStopped(const SongMsgId&)), this, SLOT(onStopped(const SongMsgId&)));
connect(_fader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&))); connect(_fader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
connect(_fader, SIGNAL(error(const SongMsgId&)), this, SLOT(onError(const SongMsgId&)));
connect(this, SIGNAL(stoppedOnError(const AudioMsgId&)), this, SIGNAL(stopped(const AudioMsgId&)), Qt::QueuedConnection); connect(this, SIGNAL(stoppedOnError(const AudioMsgId&)), this, SIGNAL(stopped(const AudioMsgId&)), Qt::QueuedConnection);
connect(this, SIGNAL(stoppedOnError(const SongMsgId&)), this, SIGNAL(stopped(const SongMsgId&)), Qt::QueuedConnection);
_loaderThread.start(); _loaderThread.start();
_faderThread.start(); _faderThread.start();
} }
@ -323,31 +314,23 @@ AudioPlayer::~AudioPlayer() {
player = 0; player = 0;
} }
for (int32 i = 0; i < AudioVoiceMsgSimultaneously; ++i) { auto clearAudioMsg = [](AudioMsg *msg) {
alSourceStop(_audioData[i].source); alSourceStop(msg->source);
if (alIsBuffer(_audioData[i].buffers[0])) { if (alIsBuffer(msg->buffers[0])) {
alDeleteBuffers(3, _audioData[i].buffers); alDeleteBuffers(3, msg->buffers);
for (int32 j = 0; j < 3; ++j) { for (int j = 0; j < 3; ++j) {
_audioData[i].buffers[j] = _audioData[i].samplesCount[j] = 0; msg->buffers[j] = msg->samplesCount[j] = 0;
} }
} }
if (alIsSource(_audioData[i].source)) { if (alIsSource(msg->source)) {
alDeleteSources(1, &_audioData[i].source); alDeleteSources(1, &msg->source);
_audioData[i].source = 0; msg->source = 0;
}
}
for (int32 i = 0; i < AudioSongSimultaneously; ++i) {
alSourceStop(_songData[i].source);
if (alIsBuffer(_songData[i].buffers[0])) {
alDeleteBuffers(3, _songData[i].buffers);
for (int32 j = 0; j < 3; ++j) {
_songData[i].buffers[j] = _songData[i].samplesCount[j] = 0;
}
}
if (alIsSource(_songData[i].source)) {
alDeleteSources(1, &_songData[i].source);
_songData[i].source = 0;
} }
};
for (int i = 0; i < AudioSimultaneousLimit; ++i) {
clearAudioMsg(dataForType(AudioMsgId::Type::Voice, i));
clearAudioMsg(dataForType(AudioMsgId::Type::Song, i));
} }
_faderThread.quit(); _faderThread.quit();
_loaderThread.quit(); _loaderThread.quit();
@ -357,28 +340,45 @@ AudioPlayer::~AudioPlayer() {
void AudioPlayer::onError(const AudioMsgId &audio) { void AudioPlayer::onError(const AudioMsgId &audio) {
emit stoppedOnError(audio); emit stoppedOnError(audio);
if (audio.type() == AudioMsgId::Type::Voice) {
emit unsuppressSong(); emit unsuppressSong();
} }
void AudioPlayer::onError(const SongMsgId &song) {
emit stoppedOnError(song);
} }
void AudioPlayer::onStopped(const AudioMsgId &audio) { void AudioPlayer::onStopped(const AudioMsgId &audio) {
emit stopped(audio); emit stopped(audio);
if (audio.type() == AudioMsgId::Type::Voice) {
emit unsuppressSong(); emit unsuppressSong();
} }
void AudioPlayer::onStopped(const SongMsgId &song) {
emit stopped(song);
} }
bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) { AudioPlayer::AudioMsg *AudioPlayer::dataForType(AudioMsgId::Type type, int index) {
Msg *data = 0; if (index < 0) index = *currentIndex(type);
switch (type) { switch (type) {
case OverviewVoiceFiles: data = &_audioData[_audioCurrent]; break; case AudioMsgId::Type::Voice: return &_audioData[index];
case OverviewFiles: data = &_songData[_songCurrent]; break; case AudioMsgId::Type::Song: return &_songData[index];
} }
return nullptr;
}
const AudioPlayer::AudioMsg *AudioPlayer::dataForType(AudioMsgId::Type type, int index) const {
return const_cast<AudioPlayer*>(this)->dataForType(type, index);
}
int *AudioPlayer::currentIndex(AudioMsgId::Type type) {
switch (type) {
case AudioMsgId::Type::Voice: return &_audioCurrent;
case AudioMsgId::Type::Song: return &_songCurrent;
}
return nullptr;
}
const int *AudioPlayer::currentIndex(AudioMsgId::Type type) const {
return const_cast<AudioPlayer*>(this)->currentIndex(type);
}
bool AudioPlayer::updateCurrentStarted(AudioMsgId::Type type, int32 pos) {
auto data = dataForType(type);
if (!data) return false; if (!data) return false;
if (pos < 0) { if (pos < 0) {
@ -389,10 +389,7 @@ bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) {
} }
if (!_checkALError()) { if (!_checkALError()) {
setStoppedState(data, AudioPlayerStoppedAtError); setStoppedState(data, AudioPlayerStoppedAtError);
switch (type) { onError(data->audio);
case OverviewVoiceFiles: onError(_audioData[_audioCurrent].audio); break;
case OverviewFiles: onError(_songData[_songCurrent].song); break;
}
return false; return false;
} }
} }
@ -400,12 +397,8 @@ bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) {
return true; return true;
} }
bool AudioPlayer::fadedStop(MediaOverviewType type, bool *fadedStart) { bool AudioPlayer::fadedStop(AudioMsgId::Type type, bool *fadedStart) {
Msg *current = 0; auto current = dataForType(type);
switch (type) {
case OverviewVoiceFiles: current = &_audioData[_audioCurrent]; break;
case OverviewFiles: current = &_songData[_songCurrent]; break;
}
if (!current) return false; if (!current) return false;
switch (current->state) { switch (current->state) {
@ -429,14 +422,18 @@ bool AudioPlayer::fadedStop(MediaOverviewType type, bool *fadedStart) {
} }
void AudioPlayer::play(const AudioMsgId &audio, int64 position) { void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
bool fadedStart = false;
auto type = audio.type();
AudioMsgId stopped; AudioMsgId stopped;
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
bool fadedStart = false; bool fadedStart = false;
AudioMsg *current = &_audioData[_audioCurrent]; auto current = dataForType(type);
if (!current) return;
if (current->audio != audio) { if (current->audio != audio) {
if (fadedStop(OverviewVoiceFiles, &fadedStart)) { if (fadedStop(type, &fadedStart)) {
stopped = current->audio; stopped = current->audio;
} }
if (current->audio) { if (current->audio) {
@ -444,110 +441,65 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
emit faderOnTimer(); emit faderOnTimer();
} }
int32 index = 0; auto foundCurrent = currentIndex(type);
for (; index < AudioVoiceMsgSimultaneously; ++index) { int index = 0;
if (_audioData[index].audio == audio) { for (; index < AudioSimultaneousLimit; ++index) {
_audioCurrent = index; if (dataForType(type, index)->audio == audio) {
*foundCurrent = index;
break; break;
} }
} }
if (index == AudioVoiceMsgSimultaneously && ++_audioCurrent >= AudioVoiceMsgSimultaneously) { if (index == AudioSimultaneousLimit && ++*foundCurrent >= AudioSimultaneousLimit) {
_audioCurrent -= AudioVoiceMsgSimultaneously; *foundCurrent -= AudioSimultaneousLimit;
} }
current = &_audioData[_audioCurrent]; current = dataForType(type);
} }
current->audio = audio; current->audio = audio;
current->file = audio.audio->location(true); current->file = audio.audio()->location(true);
current->data = audio.audio->data(); current->data = audio.audio()->data();
if (current->file.isEmpty() && current->data.isEmpty()) { if (current->file.isEmpty() && current->data.isEmpty()) {
if (audio.type() == AudioMsgId::Type::Song) {
setStoppedState(current);
if (!audio.audio()->loading()) {
DocumentOpenClickHandler::doOpen(audio.audio());
}
} else {
setStoppedState(current, AudioPlayerStoppedAtError); setStoppedState(current, AudioPlayerStoppedAtError);
onError(audio); onError(audio);
}
} else { } else {
current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying; current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying;
current->loading = true; current->loading = true;
emit loaderOnStart(audio, position); emit loaderOnStart(audio, position);
if (type == AudioMsgId::Type::Voice) {
emit suppressSong(); emit suppressSong();
} }
} }
if (stopped) emit updated(stopped);
}
void AudioPlayer::play(const SongMsgId &song, int64 position) {
SongMsgId stopped;
{
QMutexLocker lock(&playerMutex);
bool fadedStart = false;
SongMsg *current = &_songData[_songCurrent];
if (current->song != song) {
if (fadedStop(OverviewFiles, &fadedStart)) {
stopped = current->song;
}
if (current->song) {
emit loaderOnCancel(current->song);
emit faderOnTimer();
}
int32 index = 0;
for (; index < AudioSongSimultaneously; ++index) {
if (_songData[index].song == song) {
_songCurrent = index;
break;
}
}
if (index == AudioSongSimultaneously && ++_songCurrent >= AudioSongSimultaneously) {
_songCurrent -= AudioSongSimultaneously;
}
current = &_songData[_songCurrent];
}
current->song = song;
current->file = song.song->location(true);
current->data = song.song->data();
if (current->file.isEmpty() && current->data.isEmpty()) {
setStoppedState(current);
if (!song.song->loading()) {
DocumentOpenClickHandler::doOpen(song.song);
}
} else {
current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying;
current->loading = true;
emit loaderOnStart(song, position);
}
} }
if (stopped) emit updated(stopped); if (stopped) emit updated(stopped);
} }
bool AudioPlayer::checkCurrentALError(MediaOverviewType type) { bool AudioPlayer::checkCurrentALError(AudioMsgId::Type type) {
if (_checkALError()) return true; if (_checkALError()) return true;
switch (type) { auto data = dataForType(type);
case OverviewVoiceFiles: if (!data) {
setStoppedState(&_audioData[_audioCurrent], AudioPlayerStoppedAtError); setStoppedState(data, AudioPlayerStoppedAtError);
onError(_audioData[_audioCurrent].audio); onError(data->audio);
break;
case OverviewFiles:
setStoppedState(&_songData[_songCurrent], AudioPlayerStoppedAtError);
onError(_songData[_songCurrent].song);
break;
} }
return false; return false;
} }
void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) { void AudioPlayer::pauseresume(AudioMsgId::Type type, bool fast) {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
Msg *current = 0; auto current = dataForType(type);
float64 suppressGain = 1.; float64 suppressGain = 1.;
switch (type) { switch (type) {
case OverviewVoiceFiles: case AudioMsgId::Type::Voice: suppressGain = suppressAllGain; break;
current = &_audioData[_audioCurrent]; case AudioMsgId::Type::Song: suppressGain = suppressSongGain * cSongVolume(); break;
suppressGain = suppressAllGain;
break;
case OverviewFiles:
current = &_songData[_songCurrent];
suppressGain = suppressSongGain * cSongVolume();
break;
} }
switch (current->state) { switch (current->state) {
case AudioPlayerPausing: case AudioPlayerPausing:
case AudioPlayerPaused: case AudioPlayerPaused:
@ -575,14 +527,14 @@ void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) {
alSourcePlay(current->source); alSourcePlay(current->source);
if (!checkCurrentALError(type)) return; if (!checkCurrentALError(type)) return;
} }
if (type == OverviewVoiceFiles) emit suppressSong(); if (type == AudioMsgId::Type::Voice) emit suppressSong();
} break; } break;
case AudioPlayerStarting: case AudioPlayerStarting:
case AudioPlayerResuming: case AudioPlayerResuming:
case AudioPlayerPlaying: case AudioPlayerPlaying:
current->state = AudioPlayerPausing; current->state = AudioPlayerPausing;
updateCurrentStarted(type); updateCurrentStarted(type);
if (type == OverviewVoiceFiles) emit unsuppressSong(); if (type == AudioMsgId::Type::Voice) emit unsuppressSong();
break; break;
case AudioPlayerFinishing: current->state = AudioPlayerPausing; break; case AudioPlayerFinishing: current->state = AudioPlayerPausing; break;
} }
@ -592,23 +544,14 @@ void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) {
void AudioPlayer::seek(int64 position) { void AudioPlayer::seek(int64 position) {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
MediaOverviewType type = OverviewFiles; auto type = AudioMsgId::Type::Song;
Msg *current = 0; auto current = dataForType(type);
float64 suppressGain = 1.; float64 suppressGain = 1.;
AudioMsgId audio;
SongMsgId song;
switch (type) { switch (type) {
case OverviewVoiceFiles: case AudioMsgId::Type::Voice: suppressGain = suppressAllGain; break;
current = &_audioData[_audioCurrent]; case AudioMsgId::Type::Song: suppressGain = suppressSongGain * cSongVolume(); break;
audio = _audioData[_audioCurrent].audio;
suppressGain = suppressAllGain;
break;
case OverviewFiles:
current = &_songData[_songCurrent];
song = _songData[_songCurrent].song;
suppressGain = suppressSongGain * cSongVolume();
break;
} }
auto audio = current->audio;
bool isSource = alIsSource(current->source); bool isSource = alIsSource(current->source);
bool fastSeek = (position >= current->skipStart && position < current->duration - current->skipEnd - (current->skipEnd ? AudioVoiceMsgFrequency : 0)); bool fastSeek = (position >= current->skipStart && position < current->duration - current->skipEnd - (current->skipEnd ? AudioVoiceMsgFrequency : 0));
@ -637,7 +580,7 @@ void AudioPlayer::seek(int64 position) {
case AudioPlayerPlaying: case AudioPlayerPlaying:
current->state = AudioPlayerPausing; current->state = AudioPlayerPausing;
updateCurrentStarted(type); updateCurrentStarted(type);
if (type == OverviewVoiceFiles) emit unsuppressSong(); if (type == AudioMsgId::Type::Voice) emit unsuppressSong();
break; break;
case AudioPlayerFinishing: case AudioPlayerFinishing:
case AudioPlayerStopped: case AudioPlayerStopped:
@ -645,113 +588,80 @@ void AudioPlayer::seek(int64 position) {
case AudioPlayerStoppedAtError: case AudioPlayerStoppedAtError:
case AudioPlayerStoppedAtStart: case AudioPlayerStoppedAtStart:
lock.unlock(); lock.unlock();
switch (type) { return play(audio, position);
case OverviewVoiceFiles: if (audio) return play(audio, position);
case OverviewFiles: if (song) return play(song, position);
}
} }
emit faderOnTimer(); emit faderOnTimer();
} }
void AudioPlayer::stop(MediaOverviewType type) { void AudioPlayer::stop(AudioMsgId::Type type) {
switch (type) {
case OverviewVoiceFiles: {
AudioMsgId current; AudioMsgId current;
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
current = _audioData[_audioCurrent].audio; current = dataForType(type)->audio;
fadedStop(type); fadedStop(type);
} }
if (current) emit updated(current); if (current) emit updated(current);
} break;
case OverviewFiles: {
SongMsgId current;
{
QMutexLocker lock(&playerMutex);
current = _songData[_songCurrent].song;
fadedStop(type);
}
if (current) emit updated(current);
} break;
}
} }
void AudioPlayer::stopAndClear() { void AudioPlayer::stopAndClear() {
AudioMsg *current_audio = 0; AudioMsg *current_audio = nullptr, *current_song = nullptr;
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
current_audio = &_audioData[_audioCurrent]; if ((current_audio = dataForType(AudioMsgId::Type::Voice))) {
if (current_audio) {
setStoppedState(current_audio); setStoppedState(current_audio);
} }
} if ((current_song = dataForType(AudioMsgId::Type::Song))) {
SongMsg *current_song = 0;
{
QMutexLocker lock(&playerMutex);
current_song = &_songData[_songCurrent];
if (current_song) {
setStoppedState(current_song); setStoppedState(current_song);
} }
} }
if (current_song) { if (current_song) {
emit updated(current_song->song); emit updated(current_song->audio);
} }
if (current_audio) { if (current_audio) {
emit updated(current_audio->audio); emit updated(current_audio->audio);
} }
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
for (int32 index = 0; index < AudioVoiceMsgSimultaneously; ++index) { auto clearAndCancel = [this](AudioMsgId::Type type, int index) {
if (_audioData[index].audio) { auto data = dataForType(type, index);
emit loaderOnCancel(_audioData[index].audio); if (data->audio) {
emit loaderOnCancel(data->audio);
} }
_audioData[index].clear(); data->clear();
if (_songData[index].song) { };
emit loaderOnCancel(_songData[index].song); for (int index = 0; index < AudioSimultaneousLimit; ++index) {
} clearAndCancel(AudioMsgId::Type::Voice, index);
_songData[index].clear(); clearAndCancel(AudioMsgId::Type::Song, index);
} }
} }
} }
void AudioPlayer::currentState(AudioMsgId *audio, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) { void AudioPlayer::currentState(AudioMsgId *audio, AudioMsgId::Type type, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioMsg *current = &_audioData[_audioCurrent]; auto current = dataForType(type);
if (!current) return;
if (audio) *audio = current->audio; if (audio) *audio = current->audio;
return currentState(current, state, position, duration, frequency); return currentState(current, state, position, duration, frequency);
} }
void AudioPlayer::currentState(SongMsgId *song, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) { void AudioPlayer::currentState(AudioMsg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) {
QMutexLocker lock(&playerMutex);
SongMsg *current = &_songData[_songCurrent];
if (song) *song = current->song;
return currentState(current, state, position, duration, frequency);
}
void AudioPlayer::currentState(Msg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) {
if (state) *state = current->state; if (state) *state = current->state;
if (position) *position = current->position; if (position) *position = current->position;
if (duration) *duration = current->duration; if (duration) *duration = current->duration;
if (frequency) *frequency = current->frequency; if (frequency) *frequency = current->frequency;
} }
void AudioPlayer::setStoppedState(Msg *current, AudioPlayerState state) { void AudioPlayer::setStoppedState(AudioMsg *current, AudioPlayerState state) {
current->state = state; current->state = state;
current->position = 0; current->position = 0;
} }
void AudioPlayer::clearStoppedAtStart(const AudioMsgId &audio) { void AudioPlayer::clearStoppedAtStart(const AudioMsgId &audio) {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
if (_audioData[_audioCurrent].audio == audio && _audioData[_audioCurrent].state == AudioPlayerStoppedAtStart) { auto data = dataForType(audio.type());
setStoppedState(&_audioData[_audioCurrent]); if (data && data->audio == audio && data->state == AudioPlayerStoppedAtStart) {
} setStoppedState(data);
}
void AudioPlayer::clearStoppedAtStart(const SongMsgId &song) {
QMutexLocker lock(&playerMutex);
if (_songData[_songCurrent].song == song && _songData[_songCurrent].state == AudioPlayerStoppedAtStart) {
setStoppedState(&_songData[_songCurrent]);
} }
} }
@ -860,29 +770,26 @@ void AudioPlayerFader::onTimer() {
suppressSongGain = qMin(suppressAllGain, _suppressSongGain.current()); suppressSongGain = qMin(suppressAllGain, _suppressSongGain.current());
suppressSongChanged = (suppressSongGain != wasSong); suppressSongChanged = (suppressSongGain != wasSong);
} }
bool hasFading = (_suppressAll || _suppressSongAnim), hasPlaying = false; bool hasFading = (_suppressAll || _suppressSongAnim);
bool hasPlaying = false;
for (int32 i = 0; i < AudioVoiceMsgSimultaneously; ++i) { auto updatePlayback = [this, voice, &hasPlaying, &hasFading](AudioMsgId::Type type, int index, float64 suppressGain, bool suppressGainChanged) {
AudioPlayer::AudioMsg &m(voice->_audioData[i]); auto data = voice->dataForType(type, index);
if ((m.state & AudioPlayerStoppedMask) || m.state == AudioPlayerPaused || !m.source) continue; if ((data->state & AudioPlayerStoppedMask) || data->state == AudioPlayerPaused || !data->source) return;
int32 emitSignals = updateOnePlayback(&m, hasPlaying, hasFading, suppressAllGain, suppressAudioChanged); int32 emitSignals = updateOnePlayback(data, hasPlaying, hasFading, suppressGain, suppressGainChanged);
if (emitSignals & EmitError) emit error(m.audio); if (emitSignals & EmitError) emit error(data->audio);
if (emitSignals & EmitStopped) emit audioStopped(m.audio); if (emitSignals & EmitStopped) emit audioStopped(data->audio);
if (emitSignals & EmitPositionUpdated) emit playPositionUpdated(m.audio); if (emitSignals & EmitPositionUpdated) emit playPositionUpdated(data->audio);
if (emitSignals & EmitNeedToPreload) emit needToPreload(m.audio); if (emitSignals & EmitNeedToPreload) emit needToPreload(data->audio);
};
auto suppressGainForMusic = suppressSongGain * cSongVolume();
auto suppressGainForMusicChanged = suppressSongChanged || _songVolumeChanged;
for (int i = 0; i < AudioSimultaneousLimit; ++i) {
updatePlayback(AudioMsgId::Type::Voice, i, suppressAllGain, suppressAudioChanged);
updatePlayback(AudioMsgId::Type::Song, i, suppressGainForMusic, suppressGainForMusicChanged);
} }
for (int32 i = 0; i < AudioSongSimultaneously; ++i) {
AudioPlayer::SongMsg &m(voice->_songData[i]);
if ((m.state & AudioPlayerStoppedMask) || m.state == AudioPlayerPaused || !m.source) continue;
int32 emitSignals = updateOnePlayback(&m, hasPlaying, hasFading, suppressSongGain * cSongVolume(), suppressSongChanged || _songVolumeChanged);
if (emitSignals & EmitError) emit error(m.song);
if (emitSignals & EmitStopped) emit audioStopped(m.song);
if (emitSignals & EmitPositionUpdated) emit playPositionUpdated(m.song);
if (emitSignals & EmitNeedToPreload) emit needToPreload(m.song);
}
_songVolumeChanged = false; _songVolumeChanged = false;
if (!hasFading) { if (!hasFading) {
@ -907,7 +814,7 @@ void AudioPlayerFader::onTimer() {
} }
} }
int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged) { int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::AudioMsg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged) {
bool playing = false, fading = false; bool playing = false, fading = false;
ALint pos = 0; ALint pos = 0;
@ -1006,7 +913,7 @@ int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying,
return emitSignals; return emitSignals;
} }
void AudioPlayerFader::setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state) { void AudioPlayerFader::setStoppedState(AudioPlayer::AudioMsg *m, AudioPlayerState state) {
m->state = state; m->state = state;
m->position = 0; m->position = 0;
} }
@ -1478,53 +1385,38 @@ void AudioPlayerLoaders::onInit() {
} }
void AudioPlayerLoaders::onStart(const AudioMsgId &audio, qint64 position) { void AudioPlayerLoaders::onStart(const AudioMsgId &audio, qint64 position) {
_audio = AudioMsgId(); auto type = audio.type();
delete _audioLoader; clear(type);
_audioLoader = 0;
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioPlayer *voice = audioPlayer(); AudioPlayer *voice = audioPlayer();
if (!voice) return; if (!voice) return;
voice->_audioData[voice->_audioCurrent].loading = true; auto data = voice->dataForType(type);
if (!data) return;
data->loading = true;
} }
loadData(OverviewVoiceFiles, static_cast<const void*>(&audio), position); loadData(audio, position);
} }
void AudioPlayerLoaders::onStart(const SongMsgId &song, qint64 position) { void AudioPlayerLoaders::clear(AudioMsgId::Type type) {
_song = SongMsgId();
delete _songLoader;
_songLoader = 0;
{
QMutexLocker lock(&playerMutex);
AudioPlayer *voice = audioPlayer();
if (!voice) return;
voice->_songData[voice->_songCurrent].loading = true;
}
loadData(OverviewFiles, static_cast<const void*>(&song), position);
}
void AudioPlayerLoaders::clear(MediaOverviewType type) {
switch (type) { switch (type) {
case OverviewVoiceFiles: clearAudio(); break; case AudioMsgId::Type::Voice: clearAudio(); break;
case OverviewFiles: clearSong(); break; case AudioMsgId::Type::Song: clearSong(); break;
} }
} }
void AudioPlayerLoaders::setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state) { void AudioPlayerLoaders::setStoppedState(AudioPlayer::AudioMsg *m, AudioPlayerState state) {
m->state = state; m->state = state;
m->position = 0; m->position = 0;
} }
void AudioPlayerLoaders::emitError(MediaOverviewType type) { void AudioPlayerLoaders::emitError(AudioMsgId::Type type) {
switch (type) { switch (type) {
case OverviewVoiceFiles: emit error(clearAudio()); break; case AudioMsgId::Type::Voice: emit error(clearAudio()); break;
case OverviewFiles: emit error(clearSong()); break; case AudioMsgId::Type::Song: emit error(clearSong()); break;
} }
} }
@ -1532,29 +1424,26 @@ AudioMsgId AudioPlayerLoaders::clearAudio() {
AudioMsgId current = _audio; AudioMsgId current = _audio;
_audio = AudioMsgId(); _audio = AudioMsgId();
delete _audioLoader; delete _audioLoader;
_audioLoader = 0; _audioLoader = nullptr;
return current; return current;
} }
SongMsgId AudioPlayerLoaders::clearSong() { AudioMsgId AudioPlayerLoaders::clearSong() {
SongMsgId current = _song; AudioMsgId current = _song;
_song = SongMsgId(); _song = AudioMsgId();
delete _songLoader; delete _songLoader;
_songLoader = 0; _songLoader = nullptr;
return current; return current;
} }
void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) { void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) {
loadData(OverviewVoiceFiles, static_cast<const void*>(&audio), 0); loadData(audio, 0);
} }
void AudioPlayerLoaders::onLoad(const SongMsgId &song) { void AudioPlayerLoaders::loadData(const AudioMsgId &audio, qint64 position) {
loadData(OverviewFiles, static_cast<const void*>(&song), 0);
}
void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qint64 position) {
SetupError err = SetupNoErrorStarted; SetupError err = SetupNoErrorStarted;
AudioPlayerLoader *l = setupLoader(type, objId, err, position); auto type = audio.type();
AudioPlayerLoader *l = setupLoader(audio, err, position);
if (!l) { if (!l) {
if (err == SetupErrorAtStart) { if (err == SetupErrorAtStart) {
emitError(type); emitError(type);
@ -1572,7 +1461,7 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qin
if (errAtStart) { if (errAtStart) {
{ {
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioPlayer::Msg *m = checkLoader(type); AudioPlayer::AudioMsg *m = checkLoader(type);
if (m) m->state = AudioPlayerStoppedAtStart; if (m) m->state = AudioPlayerStoppedAtStart;
} }
emitError(type); emitError(type);
@ -1591,7 +1480,7 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qin
} }
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioPlayer::Msg *m = checkLoader(type); AudioPlayer::AudioMsg *m = checkLoader(type);
if (!m) { if (!m) {
clear(type); clear(type);
return; return;
@ -1662,8 +1551,8 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qin
audioPlayer()->resumeDevice(); audioPlayer()->resumeDevice();
switch (type) { switch (type) {
case OverviewVoiceFiles: alSourcef(m->source, AL_GAIN, suppressAllGain); break; case AudioMsgId::Type::Voice: alSourcef(m->source, AL_GAIN, suppressAllGain); break;
case OverviewFiles: alSourcef(m->source, AL_GAIN, suppressSongGain * cSongVolume()); break; case AudioMsgId::Type::Song: alSourcef(m->source, AL_GAIN, suppressSongGain * cSongVolume()); break;
} }
if (!_checkALError()) { if (!_checkALError()) {
setStoppedState(m, AudioPlayerStoppedAtError); setStoppedState(m, AudioPlayerStoppedAtError);
@ -1687,93 +1576,59 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qin
} }
} }
AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const void *objId, SetupError &err, qint64 position) { AudioPlayerLoader *AudioPlayerLoaders::setupLoader(const AudioMsgId &audio, SetupError &err, qint64 position) {
err = SetupErrorAtStart; err = SetupErrorAtStart;
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioPlayer *voice = audioPlayer(); AudioPlayer *voice = audioPlayer();
if (!voice) return nullptr; if (!voice) return nullptr;
bool isGoodId = false; auto data = voice->dataForType(audio.type());
AudioPlayer::Msg *m = 0; if (!data || data->audio != audio || !data->loading) {
AudioPlayerLoader **l = 0;
switch (type) {
case OverviewVoiceFiles: {
AudioPlayer::AudioMsg &msg(voice->_audioData[voice->_audioCurrent]);
const AudioMsgId &audio(*static_cast<const AudioMsgId*>(objId));
if (msg.audio != audio || !msg.loading) {
emit error(audio); emit error(audio);
break;
}
m = &msg;
l = &_audioLoader;
isGoodId = (_audio == audio);
} break;
case OverviewFiles: {
AudioPlayer::SongMsg &msg(voice->_songData[voice->_songCurrent]);
const SongMsgId &song(*static_cast<const SongMsgId*>(objId));
if (msg.song != song || !msg.loading) {
emit error(song);
break;
}
m = &msg;
l = &_songLoader;
isGoodId = (_song == song);
} break;
}
if (!l || !m) {
LOG(("Audio Error: trying to load part of audio, that is not current at the moment")); LOG(("Audio Error: trying to load part of audio, that is not current at the moment"));
err = SetupErrorNotPlaying; err = SetupErrorNotPlaying;
return nullptr; return nullptr;
} }
if (*l && (!isGoodId || !(*l)->check(m->file, m->data))) { bool isGoodId = false;
AudioPlayerLoader **l = nullptr;
switch (audio.type()) {
case AudioMsgId::Type::Voice: l = &_audioLoader; isGoodId = (_audio == audio); break;
case AudioMsgId::Type::Song: l = &_songLoader; isGoodId = (_song == audio); break;
}
if (*l && (!isGoodId || !(*l)->check(data->file, data->data))) {
delete *l; delete *l;
*l = 0; *l = nullptr;
switch (type) { switch (audio.type()) {
case OverviewVoiceFiles: _audio = AudioMsgId(); break; case AudioMsgId::Type::Voice: _audio = AudioMsgId(); break;
case OverviewFiles: _song = SongMsgId(); break; case AudioMsgId::Type::Song: _song = AudioMsgId(); break;
} }
} }
if (!*l) { if (!*l) {
switch (type) { switch (audio.type()) {
case OverviewVoiceFiles: _audio = *static_cast<const AudioMsgId*>(objId); break; case AudioMsgId::Type::Voice: _audio = audio; break;
case OverviewFiles: _song = *static_cast<const SongMsgId*>(objId); break; case AudioMsgId::Type::Song: _song = audio; break;
} }
// QByteArray header = m->data.mid(0, 8); *l = new FFMpegLoader(data->file, data->data);
// if (header.isEmpty()) {
// QFile f(m->fname);
// if (!f.open(QIODevice::ReadOnly)) {
// LOG(("Audio Error: could not open file '%1'").arg(m->fname));
// m->state = AudioPlayerStoppedAtStart;
// return nullptr;
// }
// header = f.read(8);
// }
// if (header.size() < 8) {
// LOG(("Audio Error: could not read header from file '%1', data size %2").arg(m->fname).arg(m->data.isEmpty() ? QFileInfo(m->fname).size() : m->data.size()));
// m->state = AudioPlayerStoppedAtStart;
// return nullptr;
// }
*l = new FFMpegLoader(m->file, m->data);
if (!(*l)->open(position)) { if (!(*l)->open(position)) {
m->state = AudioPlayerStoppedAtStart; data->state = AudioPlayerStoppedAtStart;
return nullptr; return nullptr;
} }
int64 duration = (*l)->duration(); int64 duration = (*l)->duration();
if (duration <= 0) { if (duration <= 0) {
m->state = AudioPlayerStoppedAtStart; data->state = AudioPlayerStoppedAtStart;
return nullptr; return nullptr;
} }
m->duration = duration; data->duration = duration;
m->frequency = (*l)->frequency(); data->frequency = (*l)->frequency();
if (!m->frequency) m->frequency = AudioVoiceMsgFrequency; if (!data->frequency) data->frequency = AudioVoiceMsgFrequency;
err = SetupNoErrorStarted; err = SetupNoErrorStarted;
} else { } else {
if (!m->skipEnd) { if (!data->skipEnd) {
err = SetupErrorLoadedFull; err = SetupErrorLoadedFull;
LOG(("Audio Error: trying to load part of audio, that is already loaded to the end")); LOG(("Audio Error: trying to load part of audio, that is already loaded to the end"));
return nullptr; return nullptr;
@ -1782,71 +1637,41 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
return *l; return *l;
} }
AudioPlayer::Msg *AudioPlayerLoaders::checkLoader(MediaOverviewType type) { AudioPlayer::AudioMsg *AudioPlayerLoaders::checkLoader(AudioMsgId::Type type) {
AudioPlayer *voice = audioPlayer(); AudioPlayer *voice = audioPlayer();
if (!voice) return 0; if (!voice) return 0;
auto data = voice->dataForType(type);
bool isGoodId = false; bool isGoodId = false;
AudioPlayer::Msg *m = 0; AudioPlayerLoader **l = nullptr;
AudioPlayerLoader **l = 0;
switch (type) { switch (type) {
case OverviewVoiceFiles: { case AudioMsgId::Type::Voice: l = &_audioLoader; isGoodId = (data->audio == _audio); break;
AudioPlayer::AudioMsg &msg(voice->_audioData[voice->_audioCurrent]); case AudioMsgId::Type::Song: l = &_songLoader; isGoodId = (data->audio == _song); break;
isGoodId = (msg.audio == _audio);
l = &_audioLoader;
m = &msg;
} break;
case OverviewFiles: {
AudioPlayer::SongMsg &msg(voice->_songData[voice->_songCurrent]);
isGoodId = (msg.song == _song);
l = &_songLoader;
m = &msg;
} break;
} }
if (!l || !m) return 0; if (!l || !data) return nullptr;
if (!isGoodId || !m->loading || !(*l)->check(m->file, m->data)) { if (!isGoodId || !data->loading || !(*l)->check(data->file, data->data)) {
LOG(("Audio Error: playing changed while loading")); LOG(("Audio Error: playing changed while loading"));
return 0; return nullptr;
} }
return m; return data;
} }
void AudioPlayerLoaders::onCancel(const AudioMsgId &audio) { void AudioPlayerLoaders::onCancel(const AudioMsgId &audio) {
if (_audio == audio) { switch (audio.type()) {
_audio = AudioMsgId(); case AudioMsgId::Type::Voice: if (_audio == audio) clear(audio.type()); break;
delete _audioLoader; case AudioMsgId::Type::Song: if (_song == audio) clear(audio.type()); break;
_audioLoader = 0;
} }
QMutexLocker lock(&playerMutex); QMutexLocker lock(&playerMutex);
AudioPlayer *voice = audioPlayer(); AudioPlayer *voice = audioPlayer();
if (!voice) return; if (!voice) return;
for (int32 i = 0; i < AudioVoiceMsgSimultaneously; ++i) { for (int i = 0; i < AudioSimultaneousLimit; ++i) {
AudioPlayer::AudioMsg &m(voice->_audioData[i]); auto data = voice->dataForType(audio.type(), i);
if (m.audio == audio) { if (data->audio == audio) {
m.loading = false; data->loading = false;
}
}
}
void AudioPlayerLoaders::onCancel(const SongMsgId &song) {
if (_song == song) {
_song = SongMsgId();
delete _songLoader;
_songLoader = 0;
}
QMutexLocker lock(&playerMutex);
AudioPlayer *voice = audioPlayer();
if (!voice) return;
for (int32 i = 0; i < AudioSongSimultaneously; ++i) {
AudioPlayer::SongMsg &m(voice->_songData[i]);
if (m.song == song) {
m.loading = false;
} }
} }
} }

View File

@ -54,18 +54,15 @@ public:
AudioPlayer(); AudioPlayer();
void play(const AudioMsgId &audio, int64 position = 0); void play(const AudioMsgId &audio, int64 position = 0);
void play(const SongMsgId &song, int64 position = 0); void pauseresume(AudioMsgId::Type type, bool fast = false);
void pauseresume(MediaOverviewType type, bool fast = false); void seek(int64 position); // type == AudioMsgId::Type::Song
void seek(int64 position); // type == OverviewFiles void stop(AudioMsgId::Type type);
void stop(MediaOverviewType type);
void stopAndClear(); void stopAndClear();
void currentState(AudioMsgId *audio, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0); void currentState(AudioMsgId *audio, AudioMsgId::Type type, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
void currentState(SongMsgId *song, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
void clearStoppedAtStart(const AudioMsgId &audio); void clearStoppedAtStart(const AudioMsgId &audio);
void clearStoppedAtStart(const SongMsgId &song);
void resumeDevice(); void resumeDevice();
@ -74,27 +71,15 @@ public:
public slots: public slots:
void onError(const AudioMsgId &audio); void onError(const AudioMsgId &audio);
void onError(const SongMsgId &song);
void onStopped(const AudioMsgId &audio); void onStopped(const AudioMsgId &audio);
void onStopped(const SongMsgId &song);
signals: signals:
void updated(const AudioMsgId &audio); void updated(const AudioMsgId &audio);
void updated(const SongMsgId &song);
void stopped(const AudioMsgId &audio); void stopped(const AudioMsgId &audio);
void stopped(const SongMsgId &song);
void stoppedOnError(const AudioMsgId &audio); void stoppedOnError(const AudioMsgId &audio);
void stoppedOnError(const SongMsgId &song);
void loaderOnStart(const AudioMsgId &audio, qint64 position); void loaderOnStart(const AudioMsgId &audio, qint64 position);
void loaderOnStart(const SongMsgId &song, qint64 position);
void loaderOnCancel(const AudioMsgId &audio); void loaderOnCancel(const AudioMsgId &audio);
void loaderOnCancel(const SongMsgId &song);
void faderOnTimer(); void faderOnTimer();
@ -106,68 +91,45 @@ signals:
private: private:
bool fadedStop(MediaOverviewType type, bool *fadedStart = 0); bool fadedStop(AudioMsgId::Type type, bool *fadedStart = 0);
bool updateCurrentStarted(MediaOverviewType type, int32 pos = -1); bool updateCurrentStarted(AudioMsgId::Type type, int32 pos = -1);
bool checkCurrentALError(MediaOverviewType type); bool checkCurrentALError(AudioMsgId::Type type);
struct Msg { struct AudioMsg {
Msg() : position(0) void clear();
, duration(0)
, frequency(AudioVoiceMsgFrequency)
, skipStart(0)
, skipEnd(0)
, loading(false)
, started(0)
, state(AudioPlayerStopped)
, source(0)
, nextBuffer(0) {
memset(buffers, 0, sizeof(buffers));
memset(samplesCount, 0, sizeof(samplesCount));
}
void clearData(); AudioMsgId audio;
FileLocation file; FileLocation file;
QByteArray data; QByteArray data;
int64 position, duration; int64 position = 0;
int32 frequency; int64 duration = 0;
int64 skipStart, skipEnd; int32 frequency = AudioVoiceMsgFrequency;
bool loading; int64 skipStart = 0;
int64 started; int64 skipEnd = 0;
AudioPlayerState state; bool loading = false;
int64 started = 0;
AudioPlayerState state = AudioPlayerStopped;
uint32 source; uint32 source = 0;
int32 nextBuffer; int32 nextBuffer = 0;
uint32 buffers[3]; uint32 buffers[3] = { 0 };
int64 samplesCount[3]; int64 samplesCount[3] = { 0 };
};
struct AudioMsg : public Msg {
AudioMsg() {
}
void clear() {
audio = AudioMsgId();
Msg::clearData();
}
AudioMsgId audio;
};
struct SongMsg : public Msg {
SongMsg() {
}
void clear() {
song = SongMsgId();
Msg::clearData();
}
SongMsgId song;
}; };
void currentState(Msg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency); void currentState(AudioMsg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency);
void setStoppedState(Msg *current, AudioPlayerState state = AudioPlayerStopped); void setStoppedState(AudioMsg *current, AudioPlayerState state = AudioPlayerStopped);
int32 _audioCurrent; AudioMsg *dataForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type)
AudioMsg _audioData[AudioVoiceMsgSimultaneously]; const AudioMsg *dataForType(AudioMsgId::Type type, int index = -1) const;
int *currentIndex(AudioMsgId::Type type);
const int *currentIndex(AudioMsgId::Type type) const;
int32 _songCurrent; int _audioCurrent;
SongMsg _songData[AudioSongSimultaneously]; AudioMsg _audioData[AudioSimultaneousLimit];
int _songCurrent;
AudioMsg _songData[AudioSimultaneousLimit];
QMutex _mutex; QMutex _mutex;
@ -228,13 +190,9 @@ public:
signals: signals:
void error(const AudioMsgId &audio); void error(const AudioMsgId &audio);
void error(const SongMsgId &audio);
void playPositionUpdated(const AudioMsgId &audio); void playPositionUpdated(const AudioMsgId &audio);
void playPositionUpdated(const SongMsgId &audio);
void audioStopped(const AudioMsgId &audio); void audioStopped(const AudioMsgId &audio);
void audioStopped(const SongMsgId &audio);
void needToPreload(const AudioMsgId &audio); void needToPreload(const AudioMsgId &audio);
void needToPreload(const SongMsgId &audio);
void stopPauseDevice(); void stopPauseDevice();
@ -258,8 +216,8 @@ private:
EmitPositionUpdated = 0x04, EmitPositionUpdated = 0x04,
EmitNeedToPreload = 0x08, EmitNeedToPreload = 0x08,
}; };
int32 updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged); int32 updateOnePlayback(AudioPlayer::AudioMsg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged);
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped); void setStoppedState(AudioPlayer::AudioMsg *m, AudioPlayerState state = AudioPlayerStopped);
QTimer _timer, _pauseTimer; QTimer _timer, _pauseTimer;
QMutex _pauseMutex; QMutex _pauseMutex;
@ -283,7 +241,6 @@ public:
signals: signals:
void error(const AudioMsgId &audio); void error(const AudioMsgId &audio);
void error(const SongMsgId &song);
void needToCheck(); void needToCheck();
public slots: public slots:
@ -291,27 +248,22 @@ public slots:
void onInit(); void onInit();
void onStart(const AudioMsgId &audio, qint64 position); void onStart(const AudioMsgId &audio, qint64 position);
void onStart(const SongMsgId &audio, qint64 position);
void onLoad(const AudioMsgId &audio); void onLoad(const AudioMsgId &audio);
void onLoad(const SongMsgId &audio);
void onCancel(const AudioMsgId &audio); void onCancel(const AudioMsgId &audio);
void onCancel(const SongMsgId &audio);
private: private:
AudioMsgId _audio; AudioMsgId _audio;
AudioPlayerLoader *_audioLoader; AudioPlayerLoader *_audioLoader;
SongMsgId _song; AudioMsgId _song;
AudioPlayerLoader *_songLoader; AudioPlayerLoader *_songLoader;
void emitError(MediaOverviewType type); void emitError(AudioMsgId::Type type);
void clear(MediaOverviewType type); void clear(AudioMsgId::Type type);
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped); void setStoppedState(AudioPlayer::AudioMsg *m, AudioPlayerState state = AudioPlayerStopped);
AudioMsgId clearAudio(); AudioMsgId clearAudio();
SongMsgId clearSong(); AudioMsgId clearSong();
enum SetupError { enum SetupError {
SetupErrorAtStart = 0, SetupErrorAtStart = 0,
@ -319,9 +271,9 @@ private:
SetupErrorLoadedFull = 2, SetupErrorLoadedFull = 2,
SetupNoErrorStarted = 3, SetupNoErrorStarted = 3,
}; };
void loadData(MediaOverviewType type, const void *objId, qint64 position); void loadData(const AudioMsgId &audio, qint64 position);
AudioPlayerLoader *setupLoader(MediaOverviewType type, const void *objId, SetupError &err, qint64 position); AudioPlayerLoader *setupLoader(const AudioMsgId &audio, SetupError &err, qint64 position);
AudioPlayer::Msg *checkLoader(MediaOverviewType type); AudioPlayer::AudioMsg *checkLoader(AudioMsgId::Type type);
}; };

View File

@ -100,8 +100,7 @@ enum {
// a new message from the same sender is attached to previous within 15 minutes // a new message from the same sender is attached to previous within 15 minutes
AttachMessageToPreviousSecondsDelta = 900, AttachMessageToPreviousSecondsDelta = 900,
AudioVoiceMsgSimultaneously = 4, AudioSimultaneousLimit = 4,
AudioSongSimultaneously = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos AudioCheckPositionTimeout = 100, // 100ms per check audio pos
AudioCheckPositionDelta = 2400, // update position called each 2400 samples AudioCheckPositionDelta = 2400, // update position called each 2400 samples
AudioFadeTimeout = 7, // 7ms AudioFadeTimeout = 7, // 7ms

View File

@ -4391,7 +4391,7 @@ bool HistoryDocument::updateStatusText() const {
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
@ -4420,22 +4420,22 @@ bool HistoryDocument::updateStatusText() const {
} }
} }
} else if (_data->song()) { } else if (_data->song()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == SongMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
} else { } else {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
} }
if (!showPause && (playing == SongMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) { if (!showPause && (playing == AudioMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) {
showPause = true; showPause = true;
} }
} else { } else {

View File

@ -859,7 +859,7 @@ bool File::updateStatusText() const {
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == AudioMsgId(document, FullMsgId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(document, FullMsgId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
@ -870,22 +870,22 @@ bool File::updateStatusText() const {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
} }
} else if (document->song()) { } else if (document->song()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == SongMsgId(document, FullMsgId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(document, FullMsgId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
} else { } else {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
} }
if (!showPause && (playing == SongMsgId(document, FullMsgId())) && App::main() && App::main()->player()->seekingSong(playing)) { if (!showPause && (playing == AudioMsgId(document, FullMsgId())) && App::main() && App::main()->player()->seekingSong(playing)) {
showPause = true; showPause = true;
} }
} else { } else {

View File

@ -92,8 +92,6 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
if (audioPlayer()) { if (audioPlayer()) {
connect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&))); connect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&)));
connect(audioPlayer(), SIGNAL(stopped(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&))); connect(audioPlayer(), SIGNAL(stopped(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&)));
connect(audioPlayer(), SIGNAL(updated(const SongMsgId&)), this, SLOT(documentPlayProgress(const SongMsgId&)));
connect(audioPlayer(), SIGNAL(stopped(const SongMsgId&)), this, SLOT(documentPlayProgress(const SongMsgId&)));
} }
connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted())); connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement())); connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement()));
@ -1533,46 +1531,22 @@ void MainWidget::ui_autoplayMediaInlineAsync(qint32 channelId, qint32 msgId) {
void MainWidget::audioPlayProgress(const AudioMsgId &audioId) { void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
AudioMsgId playing; AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state); int64 playingPosition = 0, playingDuration = 0;
if (playing == audioId && state == AudioPlayerStoppedAtStart) { int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, audioId.type(), &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == audioId && playingState == AudioPlayerStoppedAtStart) {
playingState = AudioPlayerStopped;
audioPlayer()->clearStoppedAtStart(audioId); audioPlayer()->clearStoppedAtStart(audioId);
DocumentData *audio = audioId.audio; DocumentData *audio = audioId.audio();
QString filepath = audio->filepath(DocumentData::FilePathResolveSaveFromData); QString filepath = audio->filepath(DocumentData::FilePathResolveSaveFromData);
if (!filepath.isEmpty()) { if (!filepath.isEmpty()) {
psOpenFile(filepath); psOpenFile(filepath);
} }
} }
if (HistoryItem *item = App::histItemById(audioId.contextId)) { if (playing == audioId && audioId.type() == AudioMsgId::Type::Song) {
Ui::repaintHistoryItem(item);
}
if (auto items = InlineBots::Layout::documentItems()) {
for (auto item : items->value(audioId.audio)) {
Ui::repaintInlineItem(item);
}
}
}
void MainWidget::documentPlayProgress(const SongMsgId &songId) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == songId && playingState == AudioPlayerStoppedAtStart) {
playingState = AudioPlayerStopped;
audioPlayer()->clearStoppedAtStart(songId);
DocumentData *document = songId.song;
QString filepath = document->filepath(DocumentData::FilePathResolveSaveFromData);
if (!filepath.isEmpty()) {
psOpenFile(filepath);
}
}
if (playing == songId) {
_player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
@ -1587,11 +1561,11 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
} }
} }
if (HistoryItem *item = App::histItemById(songId.contextId)) { if (HistoryItem *item = App::histItemById(audioId.contextId())) {
Ui::repaintHistoryItem(item); Ui::repaintHistoryItem(item);
} }
if (auto items = InlineBots::Layout::documentItems()) { if (auto items = InlineBots::Layout::documentItems()) {
for (auto item : items->value(songId.song)) { for (auto item : items->value(audioId.audio())) {
Ui::repaintInlineItem(item); Ui::repaintInlineItem(item);
} }
} }
@ -1628,12 +1602,12 @@ void MainWidget::documentLoadProgress(FileLoader *loader) {
App::wnd()->documentUpdated(document); App::wnd()->documentUpdated(document);
if (!document->loaded() && document->loading() && document->song() && audioPlayer()) { if (!document->loaded() && document->loading() && document->song() && audioPlayer()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing.song == document && !_player->isHidden()) { if (playing.audio() == document && !_player->isHidden()) {
_player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
} }
} }

View File

@ -445,7 +445,6 @@ public slots:
void documentLoadProgress(FileLoader *loader); void documentLoadProgress(FileLoader *loader);
void documentLoadFailed(FileLoader *loader, bool started); void documentLoadFailed(FileLoader *loader, bool started);
void documentLoadRetry(); void documentLoadRetry();
void documentPlayProgress(const SongMsgId &songId);
void inlineResultLoadProgress(FileLoader *loader); void inlineResultLoadProgress(FileLoader *loader);
void inlineResultLoadFailed(FileLoader *loader, bool started); void inlineResultLoadFailed(FileLoader *loader, bool started);

View File

@ -561,7 +561,7 @@ bool Voice::updateStatusText() const {
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
@ -865,22 +865,22 @@ bool Document::updateStatusText() const {
statusSize = _data->loadOffset(); statusSize = _data->loadOffset();
} else if (_data->loaded()) { } else if (_data->loaded()) {
if (_data->song()) { if (_data->song()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
if (playing == SongMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
} else { } else {
statusSize = FileStatusSizeLoaded; statusSize = FileStatusSizeLoaded;
} }
if (!showPause && (playing == SongMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) { if (!showPause && (playing == AudioMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) {
showPause = true; showPause = true;
} }
} else { } else {

View File

@ -2091,11 +2091,11 @@ int32 OverviewWidget::lastScrollTop() const {
int32 OverviewWidget::countBestScroll() const { int32 OverviewWidget::countBestScroll() const {
if (type() == OverviewMusicFiles && audioPlayer()) { if (type() == OverviewMusicFiles && audioPlayer()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing) { if (playing) {
int32 top = _inner.itemTop(playing.contextId); int32 top = _inner.itemTop(playing.contextId());
if (top >= 0) { if (top >= 0) {
return snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax()); return snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax());
} }

View File

@ -168,14 +168,14 @@ void PlayerWidget::mousePressEvent(QMouseEvent *e) {
emit audioPlayer()->songVolumeChanged(); emit audioPlayer()->songVolumeChanged();
rtlupdate(_volumeRect); rtlupdate(_volumeRect);
} else if (_over == OverPlayback) { } else if (_over == OverPlayback) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == _song && playingDuration) { if (playing == _song && playingDuration) {
if (playingState == AudioPlayerPlaying || playingState == AudioPlayerStarting || playingState == AudioPlayerResuming) { if (playingState == AudioPlayerPlaying || playingState == AudioPlayerStarting || playingState == AudioPlayerResuming) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} }
_down = OverPlayback; _down = OverPlayback;
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.); _downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
@ -186,7 +186,7 @@ void PlayerWidget::mousePressEvent(QMouseEvent *e) {
updateDownTime(); updateDownTime();
} }
} else if (_over == OverFull && _song) { } else if (_over == OverFull && _song) {
if (HistoryItem *item = App::histItemById(_song.contextId)) { if (HistoryItem *item = App::histItemById(_song.contextId())) {
App::main()->showMediaOverview(item->history()->peer, OverviewMusicFiles); App::main()->showMediaOverview(item->history()->peer, OverviewMusicFiles);
} }
} else if (_over == OverRepeat) { } else if (_over == OverRepeat) {
@ -271,12 +271,12 @@ void PlayerWidget::updateControls() {
void PlayerWidget::findCurrent() { void PlayerWidget::findCurrent() {
_index = -1; _index = -1;
if (!_history || !_song.contextId.msg) return; if (!_history || !_song.contextId().msg) return;
const History::MediaOverview *o = &(_msgmigrated ? _migrated : _history)->overview[OverviewMusicFiles]; const History::MediaOverview *o = &(_msgmigrated ? _migrated : _history)->overview[OverviewMusicFiles];
if ((_msgmigrated ? _migrated : _history)->channelId() == _song.contextId.channel) { if ((_msgmigrated ? _migrated : _history)->channelId() == _song.contextId().channel) {
for (int i = 0, l = o->size(); i < l; ++i) { for (int i = 0, l = o->size(); i < l; ++i) {
if (o->at(i) == _song.contextId.msg) { if (o->at(i) == _song.contextId().msg) {
_index = i; _index = i;
break; break;
} }
@ -311,7 +311,7 @@ void PlayerWidget::preloadNext() {
void PlayerWidget::startPlay(const FullMsgId &msgId) { void PlayerWidget::startPlay(const FullMsgId &msgId) {
if (HistoryItem *item = App::histItemById(msgId)) { if (HistoryItem *item = App::histItemById(msgId)) {
if (HistoryDocument *doc = static_cast<HistoryDocument*>(item->getMedia())) { if (HistoryDocument *doc = static_cast<HistoryDocument*>(item->getMedia())) {
audioPlayer()->play(SongMsgId(doc->getDocument(), item->fullId())); audioPlayer()->play(AudioMsgId(doc->getDocument(), item->fullId()));
updateState(); updateState();
} }
} }
@ -328,9 +328,9 @@ void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type)
if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == OverviewMusicFiles) { if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == OverviewMusicFiles) {
_index = -1; _index = -1;
History *history = _msgmigrated ? _migrated : _history; History *history = _msgmigrated ? _migrated : _history;
if (history->channelId() == _song.contextId.channel && _song.contextId.msg) { if (history->channelId() == _song.contextId().channel && _song.contextId().msg) {
for (int i = 0, l = history->overview[OverviewMusicFiles].size(); i < l; ++i) { for (int i = 0, l = history->overview[OverviewMusicFiles].size(); i < l; ++i) {
if (history->overview[OverviewMusicFiles].at(i) == _song.contextId.msg) { if (history->overview[OverviewMusicFiles].at(i) == _song.contextId().msg) {
_index = i; _index = i;
preloadNext(); preloadNext();
break; break;
@ -341,7 +341,7 @@ void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type)
} }
} }
bool PlayerWidget::seekingSong(const SongMsgId &song) const { bool PlayerWidget::seekingSong(const AudioMsgId &song) const {
return (_down == OverPlayback) && (song == _song); return (_down == OverPlayback) && (song == _song);
} }
@ -443,11 +443,11 @@ void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
Local::writeUserSettings(); Local::writeUserSettings();
} else if (_down == OverPlayback) { } else if (_down == OverPlayback) {
mouseMoveEvent(e); mouseMoveEvent(e);
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0; int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0; int32 playingFrequency = 0;
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == _song && playingDuration) { if (playing == _song && playingDuration) {
_downDuration = playingDuration; _downDuration = playingDuration;
audioPlayer()->seek(qRound(_downProgress * _downDuration)); audioPlayer()->seek(qRound(_downProgress * _downDuration));
@ -467,28 +467,28 @@ void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
void PlayerWidget::playPressed() { void PlayerWidget::playPressed() {
if (!_song || isHidden()) return; if (!_song || isHidden()) return;
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) { if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerPausing || playingState == AudioPlayerPaused || playingState == AudioPlayerPausedAtEnd) { if (playingState == AudioPlayerPausing || playingState == AudioPlayerPaused || playingState == AudioPlayerPausedAtEnd) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} }
} else { } else {
audioPlayer()->play(_song); audioPlayer()->play(_song);
if (App::main()) App::main()->documentPlayProgress(_song); if (App::main()) App::main()->audioPlayProgress(_song);
} }
} }
void PlayerWidget::pausePressed() { void PlayerWidget::pausePressed() {
if (!_song || isHidden()) return; if (!_song || isHidden()) return;
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) { if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerStarting || playingState == AudioPlayerResuming || playingState == AudioPlayerPlaying || playingState == AudioPlayerFinishing) { if (playingState == AudioPlayerStarting || playingState == AudioPlayerResuming || playingState == AudioPlayerPlaying || playingState == AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} }
} }
} }
@ -496,14 +496,14 @@ void PlayerWidget::pausePressed() {
void PlayerWidget::playPausePressed() { void PlayerWidget::playPausePressed() {
if (!_song || isHidden()) return; if (!_song || isHidden()) return;
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) { if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} else { } else {
audioPlayer()->play(_song); audioPlayer()->play(_song);
if (App::main()) App::main()->documentPlayProgress(_song); if (App::main()) App::main()->audioPlayProgress(_song);
} }
} }
@ -540,7 +540,7 @@ void PlayerWidget::nextPressed() {
void PlayerWidget::stopPressed() { void PlayerWidget::stopPressed() {
if (!_song || isHidden()) return; if (!_song || isHidden()) return;
audioPlayer()->stop(OverviewFiles); audioPlayer()->stop(AudioMsgId::Type::Song);
} }
void PlayerWidget::closePressed() { void PlayerWidget::closePressed() {
@ -581,19 +581,19 @@ void PlayerWidget::step_progress(float64 ms, bool timer) {
} }
void PlayerWidget::updateState() { void PlayerWidget::updateState() {
updateState(SongMsgId(), AudioPlayerStopped, 0, 0, 0); updateState(AudioMsgId(), AudioPlayerStopped, 0, 0, 0);
} }
void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency) { void PlayerWidget::updateState(AudioMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency) {
if (!playing) { if (!playing) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState, &playingPosition, &playingDuration, &playingFrequency);
} }
bool songChanged = false; bool songChanged = false;
if (playing && _song != playing) { if (playing && _song != playing) {
songChanged = true; songChanged = true;
_song = playing; _song = playing;
if (HistoryItem *item = App::histItemById(_song.contextId)) { if (HistoryItem *item = App::histItemById(_song.contextId())) {
_history = item->history(); _history = item->history();
if (_history->peer->migrateFrom()) { if (_history->peer->migrateFrom()) {
_migrated = App::history(_history->peer->migrateFrom()->id); _migrated = App::history(_history->peer->migrateFrom()->id);
@ -609,9 +609,9 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
_msgmigrated = false; _msgmigrated = false;
_index = -1; _index = -1;
} }
SongData *song = _song.song->song(); auto song = _song.audio()->song();
if (song->performer.isEmpty()) { if (song->performer.isEmpty()) {
_name.setText(st::linkFont, song->title.isEmpty() ? (_song.song->name.isEmpty() ? qsl("Unknown Track") : _song.song->name) : song->title, _textNameOptions); _name.setText(st::linkFont, song->title.isEmpty() ? (_song.audio()->name.isEmpty() ? qsl("Unknown Track") : _song.audio()->name) : song->title, _textNameOptions);
} else { } else {
TextCustomTagsMap custom; TextCustomTagsMap custom;
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
@ -630,7 +630,7 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
} }
display = display / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); display = display / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
} else if (_song) { } else if (_song) {
display = _song.song->song()->duration; display = _song.audio()->song()->duration;
} }
bool showPause = false, stopped = ((playingState & AudioPlayerStoppedMask) || playingState == AudioPlayerFinishing); bool showPause = false, stopped = ((playingState & AudioPlayerStoppedMask) || playingState == AudioPlayerFinishing);
bool wasPlaying = (_duration != 0); bool wasPlaying = (_duration != 0);
@ -641,14 +641,14 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
float64 progress = 0.; float64 progress = 0.;
int32 loaded; int32 loaded;
float64 loadProgress = 1.; float64 loadProgress = 1.;
if (duration || !_song || !_song.song || !_song.song->loading()) { if (duration || !_song || !_song.audio() || !_song.audio()->loading()) {
time = (_down == OverPlayback) ? _time : formatDurationText(display); time = (_down == OverPlayback) ? _time : formatDurationText(display);
progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.; progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.;
loaded = duration ? _song.song->size : 0; loaded = duration ? _song.audio()->size : 0;
} else { } else {
loaded = _song.song->loading() ? _song.song->loadOffset() : 0; loaded = _song.audio()->loading() ? _song.audio()->loadOffset() : 0;
time = formatDownloadText(loaded, _song.song->size); time = formatDownloadText(loaded, _song.audio()->size);
loadProgress = snap(float64(loaded) / qMax(_song.song->size, 1), 0., 1.); loadProgress = snap(float64(loaded) / qMax(_song.audio()->size, 1), 0., 1.);
} }
if (time != _time || showPause != _showPause) { if (time != _time || showPause != _showPause) {
if (_time != time) { if (_time != time) {
@ -688,8 +688,8 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
if (wasPlaying && playingState == AudioPlayerStoppedAtEnd) { if (wasPlaying && playingState == AudioPlayerStoppedAtEnd) {
if (_repeat) { if (_repeat) {
if (_song.song) { if (_song.audio()) {
audioPlayer()->play(_song); audioPlayer()->play(_song, OverviewMusicFiles);
updateState(); updateState();
} }
} else { } else {
@ -698,6 +698,6 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
} }
if (songChanged) { if (songChanged) {
emit playerSongChanged(_song.contextId); emit playerSongChanged(_song.contextId());
} }
} }

View File

@ -47,13 +47,13 @@ public:
void step_progress(float64 ms, bool timer); void step_progress(float64 ms, bool timer);
void step_state(uint64 ms, bool timer); void step_state(uint64 ms, bool timer);
void updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency); void updateState(AudioMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency);
void updateState(); void updateState();
void clearSelection(); void clearSelection();
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
bool seekingSong(const SongMsgId &song) const; bool seekingSong(const AudioMsgId &song) const;
void openPlayer(); void openPlayer();
bool isOpened() const; bool isOpened() const;
@ -115,7 +115,7 @@ private:
StateAnimations _stateAnimations; StateAnimations _stateAnimations;
Animation _a_state; Animation _a_state;
SongMsgId _song; AudioMsgId _song;
bool _msgmigrated = false; bool _msgmigrated = false;
int32 _index = -1; int32 _index = -1;
History *_migrated = nullptr; History *_migrated = nullptr;

View File

@ -954,9 +954,9 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
if (playVoice) { if (playVoice) {
AudioMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice, &playingState);
if (playing == AudioMsgId(data, msgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(data, msgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewVoiceFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Voice);
} else { } else {
AudioMsgId audio(data, msgId); AudioMsgId audio(data, msgId);
audioPlayer()->play(audio); audioPlayer()->play(audio);
@ -966,15 +966,15 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, ActionOnLoad action) {
} }
} }
} else if (playMusic) { } else if (playMusic) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing == SongMsgId(data, msgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(data, msgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} else { } else {
SongMsgId song(data, msgId); AudioMsgId song(data, msgId);
audioPlayer()->play(song); audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song); if (App::main()) App::main()->audioPlayProgress(song);
} }
} else if (playVideo) { } else if (playVideo) {
if (!data->data().isEmpty()) { if (!data->data().isEmpty()) {
@ -1243,9 +1243,9 @@ void DocumentData::performActionOnLoad() {
if (loaded()) { if (loaded()) {
AudioMsgId playing; AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped; AudioPlayerState state = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state); audioPlayer()->currentState(&playing, AudioMsgId::Type::Voice, &state);
if (playing == AudioMsgId(this, _actionOnLoadMsgId) && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) { if (playing == AudioMsgId(this, _actionOnLoadMsgId) && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewVoiceFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Voice);
} else { } else {
audioPlayer()->play(AudioMsgId(this, _actionOnLoadMsgId)); audioPlayer()->play(AudioMsgId(this, _actionOnLoadMsgId));
if (App::main()) App::main()->mediaMarkRead(this); if (App::main()) App::main()->mediaMarkRead(this);
@ -1253,15 +1253,15 @@ void DocumentData::performActionOnLoad() {
} }
} else if (playMusic) { } else if (playMusic) {
if (loaded()) { if (loaded()) {
SongMsgId playing; AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped; AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState); audioPlayer()->currentState(&playing, AudioMsgId::Type::Song, &playingState);
if (playing == SongMsgId(this, _actionOnLoadMsgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { if (playing == AudioMsgId(this, _actionOnLoadMsgId) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewFiles); audioPlayer()->pauseresume(AudioMsgId::Type::Song);
} else { } else {
SongMsgId song(this, _actionOnLoadMsgId); AudioMsgId song(this, _actionOnLoadMsgId);
audioPlayer()->play(song); audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song); if (App::main()) App::main()->audioPlayProgress(song);
} }
} }
} else if (playAnimation) { } else if (playAnimation) {

View File

@ -1229,51 +1229,62 @@ private:
VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit);
QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform); QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform);
struct SongMsgId { class AudioMsgId {
SongMsgId() : song(nullptr) { public:
} enum class Type {
SongMsgId(DocumentData *song, const FullMsgId &msgId) : song(song), contextId(msgId) { Unknown,
} Voice,
SongMsgId(DocumentData *song, ChannelId channelId, MsgId msgId) : song(song), contextId(channelId, msgId) { Song,
} Video,
explicit operator bool() const {
return song;
}
DocumentData *song;
FullMsgId contextId;
}; };
inline bool operator<(const SongMsgId &a, const SongMsgId &b) {
return quintptr(a.song) < quintptr(b.song) || (quintptr(a.song) == quintptr(b.song) && a.contextId < b.contextId); AudioMsgId() {
} }
inline bool operator==(const SongMsgId &a, const SongMsgId &b) { AudioMsgId(DocumentData *audio, const FullMsgId &msgId) : _audio(audio), _contextId(msgId) {
return a.song == b.song && a.contextId == b.contextId; setType();
} }
inline bool operator!=(const SongMsgId &a, const SongMsgId &b) { AudioMsgId(DocumentData *audio, ChannelId channelId, MsgId msgId) : _audio(audio), _contextId(channelId, msgId) {
return !(a == b); setType();
} }
struct AudioMsgId { Type type() const {
AudioMsgId() : audio(nullptr) { return _type;
} }
AudioMsgId(DocumentData *audio, const FullMsgId &msgId) : audio(audio), contextId(msgId) { DocumentData *audio() const {
return _audio;
} }
AudioMsgId(DocumentData *audio, ChannelId channelId, MsgId msgId) : audio(audio), contextId(channelId, msgId) { FullMsgId contextId() const {
return _contextId;
} }
explicit operator bool() const { explicit operator bool() const {
return audio; return _audio;
} }
DocumentData *audio;
FullMsgId contextId; private:
void setType() {
if (_audio->voice()) {
_type = Type::Voice;
} else if (_audio->song()) {
_type = Type::Song;
} else if (_audio->isVideo()) {
_type = Type::Video;
} else {
_type = Type::Unknown;
}
}
DocumentData *_audio = nullptr;
Type _type = Type::Unknown;
FullMsgId _contextId;
}; };
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) { inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
return quintptr(a.audio) < quintptr(b.audio) || (quintptr(a.audio) == quintptr(b.audio) && a.contextId < b.contextId); return quintptr(a.audio()) < quintptr(b.audio()) || (quintptr(a.audio()) == quintptr(b.audio()) && a.contextId() < b.contextId());
} }
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) { inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
return a.audio == b.audio && a.contextId == b.contextId; return a.audio() == b.audio() && a.contextId() == b.contextId();
} }
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) { inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
return !(a == b); return !(a == b);