-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathaudio_server.h
185 lines (150 loc) · 6.31 KB
/
audio_server.h
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
174
175
176
177
178
179
180
181
182
183
184
185
#include <driver/i2s.h>
#include <WebServer.h>
//---- I2S Configuration ------------
// I2S pins
#define I2S_WS 2
#define I2S_SCK 14
#define I2S_SD 15
//CAMERA_MODEL_XIAO_ESP32S3
//#define I2S_WS 42
//#define I2S_SCK -1
//#define I2S_SD 41
// I2S peripheral to use (0 or 1)
#define I2S_PORT I2S_NUM_1
//CAMERA_MODEL_XIAO_ESP32S3
//#define I2S_PORT I2S_NUM_0
//---- Sampling ------------
#define SAMPLE_RATE 22050 // Sample rate of the audio
#define SAMPLE_BITS 32 // Bits per sample of the audio
//CAMERA_MODEL_XIAO_ESP32S3
//#define SAMPLE_BITS 16
#define DMA_BUF_COUNT 2
#define DMA_BUF_LEN 1024
WebServer Audioserver(82);
WebServer VideoAudioserver(83);
//---- Audio WAV configuration ------------
const int sampleRate = SAMPLE_RATE; // Sample rate of the audio
const int bitsPerSample = SAMPLE_BITS; // Bits per sample of the audio
const int numChannels = 1; // Number of audio channels (1 for mono, 2 for stereo)
const int bufferSize = DMA_BUF_LEN; // Buffer size for I2S data transfer
struct WAVHeader {
char chunkId[4]; // 4 bytes
uint32_t chunkSize; // 4 bytes
char format[4]; // 4 bytes
char subchunk1Id[4]; // 4 bytes
uint32_t subchunk1Size; // 4 bytes
uint16_t audioFormat; // 2 bytes
uint16_t numChannels; // 2 bytes
uint32_t sampleRate; // 4 bytes
uint32_t byteRate; // 4 bytes
uint16_t blockAlign; // 2 bytes
uint16_t bitsPerSample; // 2 bytes
char subchunk2Id[4]; // 4 bytes
uint32_t subchunk2Size; // 4 bytes
};
void initializeWAVHeader(WAVHeader &header, uint32_t sampleRate, uint16_t bitsPerSample, uint16_t numChannels) {
strncpy(header.chunkId, "RIFF", 4);
strncpy(header.format, "WAVE", 4);
strncpy(header.subchunk1Id, "fmt ", 4);
strncpy(header.subchunk2Id, "data", 4);
header.chunkSize = 0; // Placeholder for Chunk Size (to be updated later)
header.subchunk1Size = 16; // PCM format size (constant for uncompressed audio)
header.audioFormat = 1; // PCM audio format (constant for uncompressed audio)
header.numChannels = numChannels;
header.sampleRate = sampleRate;
header.bitsPerSample = bitsPerSample;
header.byteRate = (sampleRate * bitsPerSample * numChannels) / 8;
header.blockAlign = (bitsPerSample * numChannels) / 8;
header.subchunk2Size = 0; // Placeholder for data size (to be updated later)
}
void mic_i2s_init() {
i2s_config_t i2sConfig = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), // Use RX mode for audio input
//CAMERA_MODEL_XIAO_ESP32S3
//.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = SAMPLE_RATE ,
.bits_per_sample = i2s_bits_per_sample_t(SAMPLE_BITS),
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Mono audio
//CAMERA_MODEL_XIAO_ESP32S3
//.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0,
.dma_buf_count = DMA_BUF_COUNT,
.dma_buf_len = DMA_BUF_LEN,
.use_apll = true
};
i2s_driver_install(I2S_PORT, &i2sConfig, 0, NULL);
i2s_pin_config_t pinConfig = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS ,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
i2s_set_pin(I2S_PORT, &pinConfig);
}
void handleAudioStream() {
mic_i2s_init();
WAVHeader wavHeader;
initializeWAVHeader(wavHeader, sampleRate, bitsPerSample, numChannels);
// Get access to the client object
WiFiClient Audioclient = Audioserver.client();
// Send the 200 OK response with the headers
Audioclient.print("HTTP/1.1 200 OK\r\n");
Audioclient.print("Content-Type: audio/wav\r\n");
Audioclient.print("Access-Control-Allow-Origin: *\r\n");
Audioclient.print("\r\n");
// Send the initial part of the WAV header
Audioclient.write(reinterpret_cast<const uint8_t*>(&wavHeader), sizeof(wavHeader));
uint8_t buffer[bufferSize];
size_t bytesRead = 0;
//uint32_t totalDataSize = 0; // Total size of audio data sent
while (true) {
if (!Audioclient.connected()) {
//i2s_driver_uninstall(I2S_PORT);
Serial.println("Audioclient disconnected");
break;
}
// Read audio data from I2S DMA
i2s_read(I2S_PORT, buffer, bufferSize, &bytesRead, portMAX_DELAY);
// Send audio data
if (bytesRead > 0) {
Audioclient.write(buffer, bytesRead);
//totalDataSize += bytesRead;
//Serial.println(totalDataSize);
}
}
}
void audio_http_stream() {
Audioserver.on("/audio", HTTP_GET, handleAudioStream);
Audioserver.begin();
}
void handleVideAudio(){
String ip = WiFi.localIP().toString();
String content = "<!DOCTYPE html><html lang=\"en\">";
content += "<head><meta charset=\"UTF-8\">";
content += "<title>ESP32-CAM + Livestream Audio</title>";
content += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
content += "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">";
content += "<style>";
content += "body { background-color: #FFF; }";
content += ".container1 { display: flex; flex-direction: row; justify-content: center; align-items: center; height: 100%; }";
content += ".container2 { display: flex; flex-direction: row; justify-content: center; align-items: center; height: 100%; }";
content += ".block { width: 200px; height: 200px; background-color: gray; margin: 10px; display: flex; justify-content: center; align-items: center; }";
content += "#video { border: 0; }";
content += "#audio { border: 0; }";
content += "#tbl { background-color: #000; }";
content += "</style></head><body>";
content += "<h1>ESP32-CAM + Livestream Audio</h1>";
content += "<div class=\"container1\" style=\"overflow-x:auto;\">";
content += "<table id=\"tbl\" style=\"overflow-x:auto;\"><tr>";
content += "<td><iframe id=\"video\" src=\"http://" + ip + ":81/stream\" allow=\"camera\" width=\"640\" height=\"480\"></iframe></td>";
content += "</tr><tr>";
content += "<td><video controls autoplay width=\"640\" height=\"60\" id=\"audio\"><source src=\"http://" + ip + ":82/audio\" type=\"audio/wav\"></video></td>";
content += "</tr></table></div>";
content += "</body></html>";
VideoAudioserver.send(200, "text/html", content);
}
void VideoAudio_http(){
VideoAudioserver.on("/", HTTP_GET, handleVideAudio);
VideoAudioserver.begin();
}