M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 4,6 4,7 @@
### Fixed
* Fixed BIWIN eMMC memory errors
+* Fixed freeze after changing Relaxation volume intensively
### Added
* Added new 32px and 170px fonts
M module-audio/Audio/decoder/DecoderFLAC.cpp => module-audio/Audio/decoder/DecoderFLAC.cpp +16 -6
@@ 10,6 10,7 @@
#define DR_FLAC_NO_OGG
#define DR_FLAC_NO_CRC
#define DR_FLAC_NO_SIMD
+
#include <src/dr_flac.h>
namespace audio
@@ 38,19 39,21 @@ namespace audio
drflac_close(flac);
}
- std::int32_t DecoderFLAC::decode(std::uint32_t samplesToRead, int16_t *pcmData)
+ std::int32_t DecoderFLAC::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
{
- if (!fileExists(fd)) {
- LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
- return fileDeletedRetCode;
- }
-
const auto samplesRead =
drflac_read_pcm_frames_s16(flac, samplesToRead / channelCount, reinterpret_cast<drflac_int16 *>(pcmData));
if (samplesRead > 0) {
/* Calculate frame duration in seconds */
position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
}
+ else if (!fileExists(fd)) {
+ /* Unfortunately this second check of file existence is needed
+ * to verify whether lack of new samples was caused by EOF or by
+ * deletion of the file. */
+ LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
+ return fileDeletedRetCode;
+ }
return samplesRead * channelCount;
}
@@ 79,6 82,13 @@ namespace audio
std::size_t DecoderFLAC::drflacRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead)
{
const auto decoderContext = reinterpret_cast<DecoderFLAC *>(pUserData);
+
+ /* Check if the file exists - std::fread happily returns bytesToRead if
+ * requested to read from deleted file, what causes decoding library
+ * to enter infinite loop of reading. */
+ if (!fileExists(decoderContext->fd)) {
+ return 0;
+ }
return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
}
M module-audio/Audio/decoder/DecoderMP3.cpp => module-audio/Audio/decoder/DecoderMP3.cpp +14 -5
@@ 96,23 96,32 @@ namespace audio
std::int32_t DecoderMP3::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
{
- if (!fileExists(fd)) {
- LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
- return fileDeletedRetCode;
- }
-
const auto samplesRead = drmp3_read_pcm_frames_s16(
mp3.get(), samplesToRead / channelCount, reinterpret_cast<drmp3_int16 *>(pcmData));
if (samplesRead > 0) {
/* Calculate frame duration in seconds */
position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
}
+ else if (!fileExists(fd)) {
+ /* Unfortunately this second check of file existence is needed
+ * to verify whether lack of new samples was caused by EOF or by
+ * deletion of the file. */
+ LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
+ return fileDeletedRetCode;
+ }
return samplesRead * channelCount;
}
std::size_t DecoderMP3::drmp3Read(void *pUserData, void *pBufferOut, std::size_t bytesToRead)
{
const auto decoderContext = reinterpret_cast<DecoderMP3 *>(pUserData);
+
+ /* Check if the file exists - std::fread happily returns bytesToRead if
+ * requested to read from deleted file, what causes decoding library
+ * to enter infinite loop of reading. */
+ if (!fileExists(decoderContext->fd)) {
+ return 0;
+ }
return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
}
M module-audio/Audio/decoder/DecoderMP3.hpp => module-audio/Audio/decoder/DecoderMP3.hpp +4 -4
@@ 23,7 23,7 @@ namespace audio
// Callback for when data needs to be read from the client.
//
- // pUserData [in] The user data that was passed to drflac_open() and family.
+ // pUserData [in] The user data that was passed to drmp3_init() and family.
// pBufferOut [out] The output buffer.
// bytesToRead [in] The number of bytes to read.
//
@@ 35,15 35,15 @@ namespace audio
// Callback for when data needs to be seeked.
//
- // pUserData [in] The user data that was passed to drflac_open() and family.
+ // pUserData [in] The user data that was passed to drmp3_init() and family.
// offset [in] The number of bytes to move, relative to the origin. Will never be negative.
// origin [in] The origin of the seek - the current position or the start of the stream.
//
// Returns whether the seek was successful.
//
// The offset will never be negative. Whether it is relative to the beginning or current position is
- // determined by the "origin" parameter which will be either drflac_seek_origin_start or
- // drflac_seek_origin_current.
+ // determined by the "origin" parameter which will be either drmp3_seek_origin_start or
+ // drmp3_seek_origin_current.
static drmp3_bool32 drmp3Seek(void *pUserData, int offset, drmp3_seek_origin origin);
};
} // namespace audio
M module-audio/Audio/decoder/DecoderWAV.cpp => module-audio/Audio/decoder/DecoderWAV.cpp +38 -13
@@ 7,13 7,15 @@
#include <memory>
#define DR_WAV_IMPLEMENTATION
+#define DR_MP3_NO_STDIO
+
#include <src/dr_wav.h>
namespace audio
{
DecoderWAV::DecoderWAV(const std::string &filePath) : Decoder(filePath), wav(std::make_unique<drwav>())
{
- if (drwav_init_file(wav.get(), filePath.c_str(), nullptr) == DRWAV_FALSE) {
+ if (drwav_init(wav.get(), drwavRead, drwavSeek, this, nullptr) == DRWAV_FALSE) {
LOG_ERROR("Unable to init WAV decoder");
return;
}
@@ 32,16 34,23 @@ namespace audio
}
}
- std::int32_t DecoderWAV::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
+ void DecoderWAV::setPosition(float pos)
{
if (!isInitialized) {
LOG_ERROR("WAV decoder not initialized");
- return 0;
+ return;
}
+ drwav_seek_to_pcm_frame(wav.get(), wav->totalPCMFrameCount * pos);
- if (!fileExists(fd)) {
- LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
- return fileDeletedRetCode;
+ /* Calculate new position */
+ position = static_cast<float>(wav->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
+ }
+
+ std::int32_t DecoderWAV::decode(std::uint32_t samplesToRead, std::int16_t *pcmData)
+ {
+ if (!isInitialized) {
+ LOG_ERROR("WAV decoder not initialized");
+ return 0;
}
const auto samplesRead = drwav_read_pcm_frames_s16(wav.get(), samplesToRead / channelCount, pcmData);
@@ 49,18 58,34 @@ namespace audio
/* Calculate frame duration in seconds */
position += static_cast<float>(samplesRead) / static_cast<float>(sampleRate);
}
+ else if (!fileExists(fd)) {
+ /* Unfortunately this second check of file existence is needed
+ * to verify whether lack of new samples was caused by EOF or by
+ * deletion of the file. */
+ LOG_WARN("File '%s' was deleted during playback!", filePath.c_str());
+ return fileDeletedRetCode;
+ }
return samplesRead * channelCount;
}
- void DecoderWAV::setPosition(float pos)
+ std::size_t DecoderWAV::drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead)
{
- if (!isInitialized) {
- LOG_ERROR("WAV decoder not initialized");
- return;
+ const auto decoderContext = reinterpret_cast<DecoderWAV *>(pUserData);
+
+ /* Check if the file exists - std::fread happily returns bytesToRead if
+ * requested to read from deleted file, what causes decoding library
+ * to enter infinite loop of reading. */
+ if (!fileExists(decoderContext->fd)) {
+ return 0;
}
- drwav_seek_to_pcm_frame(wav.get(), wav->totalPCMFrameCount * pos);
+ return std::fread(pBufferOut, 1, bytesToRead, decoderContext->fd);
+ }
- /* Calculate new position */
- position = static_cast<float>(wav->totalPCMFrameCount) * pos / static_cast<float>(sampleRate);
+ drwav_bool32 DecoderWAV::drwavSeek(void *pUserData, int offset, drwav_seek_origin origin)
+ {
+ const auto decoderContext = reinterpret_cast<DecoderWAV *>(pUserData);
+ const auto seekError =
+ std::fseek(decoderContext->fd, offset, origin == drwav_seek_origin_start ? SEEK_SET : SEEK_CUR);
+ return (seekError == 0) ? DRWAV_TRUE : DRWAV_FALSE;
}
} // namespace audio
M module-audio/Audio/decoder/DecoderWAV.hpp => module-audio/Audio/decoder/DecoderWAV.hpp +25 -0
@@ 20,5 20,30 @@ namespace audio
private:
std::unique_ptr<drwav> wav;
+
+ // Callback for when data needs to be read from the client.
+ //
+ // pUserData [in] The user data that was passed to drwav_open() and family.
+ // pBufferOut [out] The output buffer.
+ // bytesToRead [in] The number of bytes to read.
+ //
+ // Returns the number of bytes actually read.
+ //
+ // A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback
+ // until either the entire bytesToRead is filled or you have reached the end of the stream.
+ static std::size_t drwavRead(void *pUserData, void *pBufferOut, std::size_t bytesToRead);
+
+ // Callback for when data needs to be seeked.
+ //
+ // pUserData [in] The user data that was passed to drwav_init() and family.
+ // offset [in] The number of bytes to move, relative to the origin. Will never be negative.
+ // origin [in] The origin of the seek - the current position or the start of the stream.
+ //
+ // Returns whether the seek was successful.
+ //
+ // The offset will never be negative. Whether it is relative to the beginning or current position is
+ // determined by the "origin" parameter which will be either drwav_seek_origin_start or
+ // drwav_seek_origin_current.
+ static drwav_bool32 drwavSeek(void *pUserData, int offset, drwav_seek_origin origin);
};
} // namespace audio