-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathspeakers.cpp
173 lines (137 loc) · 5.72 KB
/
speakers.cpp
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "rae_hw/peripherals/speakers.hpp"
namespace rae_hw {
SpeakersNode::SpeakersNode(const rclcpp::NodeOptions& options) : rclcpp_lifecycle::LifecycleNode("speakers_node", options) {}
SpeakersNode::~SpeakersNode() {
cleanup();
}
void SpeakersNode::cleanup() {
delete[] buffer;
mpg123_close(mh);
mpg123_delete(mh);
mpg123_exit();
}
CallbackReturn SpeakersNode::on_configure(const rclcpp_lifecycle::State& /*previous_state*/) {
// Initialize ALSA or any other audio setup code here
// Create Audio Service
play_audio_service_ = create_service<rae_msgs::srv::PlayAudio>(
"play_audio", std::bind(&SpeakersNode::play_audio_service_callback, this, std::placeholders::_1, std::placeholders::_2));
// Any other initialization code here
RCLCPP_INFO(this->get_logger(), "Speakers node configured!");
return CallbackReturn::SUCCESS;
}
CallbackReturn SpeakersNode::on_activate(const rclcpp_lifecycle::State& /*previous_state*/) {
RCLCPP_INFO(this->get_logger(), "Speakers node activating!");
return CallbackReturn::SUCCESS;
}
CallbackReturn SpeakersNode::on_deactivate(const rclcpp_lifecycle::State& /*previous_state*/) {
RCLCPP_INFO(this->get_logger(), "Speakers node deactivating!");
return CallbackReturn::SUCCESS;
}
CallbackReturn SpeakersNode::on_shutdown(const rclcpp_lifecycle::State& /*previous_state*/) {
RCLCPP_INFO(this->get_logger(), "Speakers node shutting down!");
cleanup();
return CallbackReturn::SUCCESS;
}
void SpeakersNode::play_audio_service_callback(const std::shared_ptr<rae_msgs::srv::PlayAudio::Request> request,
const std::shared_ptr<rae_msgs::srv::PlayAudio::Response> response) {
const std::string& file_location = request->file_location;
// Check if the file ends with ".wav"
if(file_location.size() >= 4 && file_location.substr(file_location.size() - 4) == ".wav") {
// Call the play_wav function
play_wav(file_location.c_str());
response->success = true;
return;
}
// Check if the file ends with ".mp3"
if(file_location.size() >= 4 && file_location.substr(file_location.size() - 4) == ".mp3") {
// Call the play_mp3 function
play_mp3(file_location.c_str());
response->success = true;
return;
}
// Unsupported file format
RCLCPP_ERROR(this->get_logger(), "Unsupported file format: %s", file_location.c_str());
response->success = false;
}
void SpeakersNode::play_mp3(const char* mp3_file) {
// Initialize libmpg123
mpg123_init();
mh = mpg123_new(NULL, NULL);
long rate; // Set your desired sample rate here
int channels, encoding;
if(mpg123_open(mh, mp3_file) != MPG123_OK || mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK) {
RCLCPP_ERROR(this->get_logger(), "Cant read MP3 file");
return;
}
// Open ALSA device
if(snd_pcm_open(&alsaHandle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
RCLCPP_ERROR(this->get_logger(), "Failed to open ALSA playback device.");
return;
}
// Set ALSA parameters
snd_pcm_set_params(alsaHandle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 2, 50000);
size_t buffer_size = mpg123_outblock(mh) * 4;
unsigned char* buffer = new unsigned char[buffer_size];
size_t err;
while(mpg123_read(mh, buffer, buffer_size, &err) == MPG123_OK) {
if(snd_pcm_writei(alsaHandle, buffer, buffer_size / (2 * channels)) < 0) {
std::cerr << "Error in snd_pcm_writei: " << snd_strerror(err) << std::endl;
}
}
// Cleanup
delete[] buffer;
snd_pcm_close(alsaHandle);
mpg123_close(mh);
mpg123_delete(mh);
mpg123_exit();
return;
}
void SpeakersNode::play_wav(const char* wav_file) {
// Open WAV file
SF_INFO sfinfo;
SNDFILE* file = sf_open(wav_file, SFM_READ, &sfinfo);
if(!file) {
RCLCPP_ERROR(this->get_logger(), "Failed to open WAV file: %s", wav_file);
return;
}
// Open ALSA device
if(snd_pcm_open(&alsaHandle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {
RCLCPP_ERROR(this->get_logger(), "Failed to open ALSA playback device.");
return;
}
// Set ALSA parameters
snd_pcm_set_params(alsaHandle, SND_PCM_FORMAT_S32_LE, SND_PCM_ACCESS_RW_INTERLEAVED, sfinfo.channels, sfinfo.samplerate, 2, 50000);
// Read and play WAV file
const int BUFFER_SIZE = 4096;
int32_t* buffer_wav = new int32_t[BUFFER_SIZE * sfinfo.channels]; // Use int32_t for 32-bit format
sf_count_t readCount;
const float gain = 16.0f; // Adjust this factor for desired gain
while((readCount = sf_readf_int(file, buffer_wav, BUFFER_SIZE)) > 0) {
// Apply gain to the samples
for(int i = 0; i < readCount * sfinfo.channels; ++i) {
float sample = static_cast<float>(buffer_wav[i]) / std::numeric_limits<int32_t>::max();
sample *= gain; // Apply gain
buffer_wav[i] = static_cast<int32_t>(sample * std::numeric_limits<int32_t>::max());
}
// Write the processed buffer to the playback device
if(snd_pcm_writei(alsaHandle, buffer_wav, readCount) < 0) {
std::cerr << "Error in snd_pcm_writei: " << snd_strerror(readCount) << std::endl;
break;
}
}
// Cleanup
delete[] buffer_wav;
sf_close(file);
snd_pcm_close(alsaHandle);
return;
}
} // namespace rae_hw
int main(int argc, char* argv[]) {
rclcpp::init(argc, argv);
auto node = std::make_shared<rae_hw::SpeakersNode>(rclcpp::NodeOptions());
rclcpp::executors::StaticSingleThreadedExecutor executor;
executor.add_node(node->get_node_base_interface());
executor.spin();
rclcpp::shutdown();
return 0;
}