1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#include "fatfs_audio_input.hpp<D-c>ccc
#include <cstdint>
#include <memory>
#include "esp_heap_caps.h"
#include "audio_element.hpp"
#include "freertos/portmacro.h"
#include "include/audio_element.hpp"
namespace audio {
static const TickType_t kMaxWaitTicks = portMAX_DELAY;
// Large output buffer size, so that we can keep a get as much of the input file
// into memory as soon as possible.
static constexpr std::size_t kOutputBufferSize = 1024 * 128;
static constexpr std::size_t kQueueItemSize = sizeof(IAudioElement::Command);
FatfsAudioInput::FatfsAudioInput(std::shared_ptr<drivers::SdStorage> storage)
: IAudioElement(), storage_(storage) {
working_buffer_ = heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_SPIRAM);
output_buffer_memory_ =
heap_caps_malloc(kOutputBufferSize + 1, MALLOC_CAP_SPIRAM);
output_buffer_ =
xMessageBufferCreateStatic(kOutputBufferSize, output_buffer_memory_,
&output_buffer_metadata_);
}
FatfsAudioInput::~FatfsAudioInput() {
free(working_buffer_);
vMessageBufferDelete(output_buffer_);
free(output_buffer_memory_);
}
auto FatfsAudioInput::InputBuffer() -> MessageBufferHandle_t {
return input_buffer_;
}
auto FatfsAudioInput::OutputBuffer() -> MessageBufferHandle_t {
return output_buffer_;
}
auto FatfsAudioInput::ProcessElementCommand(void* command) -> ProcessResult {
InputCommand *real = std::reinterpret_cast<InputCommand*>(command);
if (uxQueueSpacesAvailable(output_queue_) < 2) {
return OUTPUT_FULL;
}
if (is_file_open_) {
f_close(¤t_file_);
}
FRESULT res = f_open(¤t_file_, real->filename.c_str(), FA_READ);
if (res != FR_OK) {
delete real;
return ERROR;
}
if (real->seek_to && f_lseek(¤t_file_, real->seek_to) {
return ERROR;
}
is_file_open_ = true;
if (real->interrupt) {
Command sequence_update;
sequence_update.type = SEQUENCE_NUMBER;
sequence_update.sequence_number = current_sequence_++;
xQueueSendToFront(output_queue_, &sequence_update, kMaxWaitTicks);
}
OutputCommand *data = new OutputCommand;
data->extension = "mp3";
Command file_info;
file_info.type = ELEMENT;
file_info.sequence_number = current_sequence_;
file_info.data = &data;
xQueueSendToBack(output_queue_, &file_info, kMaxWaitTicks);
delete real;
return OK;
}
auto FatfsAudioInput::SkipElementCommand(void* command) -> void {
InputCommand *real = std::reinterpret_cast<input_key_service_add_key*>(command);
delete real;
}
auto FatfsAudioInput::ProcessData(uint8_t* data, uint16_t length) -> void {
// Not used, since we have no input stream.
}
auto FatfsAudioInput::ProcessIdle() -> ProcessResult {
if (!is_file_open_) {
return OK;
}
if (xStreamBufferSpacesAvailable(output_buffer) < kMaxFrameSize) {
return OUTPUT_FULL;
}
UINT bytes_read = 0;
FRESULT result = f_read(¤t_file_, working_buffer_, kMaxFrameSize, &bytes_read);
if (!FR_OK) {
return ERROR;
}
xStreamBufferSend(&output_buffer_, working_buffer_, bytes_read, kMaxWaitTicks);
if (f_eof(¤t_file_)) {
f_close(¤t_file_);
is_file_open_ = false;
}
return OK;
}
} // namespace audio
|