Код: Выделить всё
#include
#include
#include
#include
#include
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define NOTIFY_CHARACTERISTIC_UUID "abc3483e-36e1-4688-b7f5-ea07361b26a8"
#define WRITE_CHARACTERISTIC_UUID "3cba5540-1d0b-4b0b-929f-81c2ec474cf4"
#define SAMPLE_RATE 16000U
#define SAMPLE_BITS 16
#define RECORD_TIME 5 // seconds
bool deviceConnected = false;
bool captureRequest = false;
bool recordingRequest = false;
int maxPacketSize = 509; // BLE packet size limit
I2SClass I2S;
BLEServer *pServer;
BLECharacteristic *pNotifyCharacteristic;
BLECharacteristic *pWriteCharacteristic;
// BLE Callbacks to track connection/disconnection
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("Device connected!");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("Device disconnected!");
BLEDevice::startAdvertising();
}
};
// BLE Write Callback
class MyWriteCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = pCharacteristic->getValue();
if (value == "START_RECORDING") {
Serial.println("Recording request received.");
recordingRequest = true; // Set flag to start recording
}
}
};
// Function to record and stream audio over BLE for 20 seconds
void recordAndStreamAudio() {
uint32_t record_size = (SAMPLE_RATE * SAMPLE_BITS / 8) * RECORD_TIME; // 20 seconds buffer
uint8_t *rec_buffer = (uint8_t *)ps_malloc(record_size); // Allocate buffer for recording
if (rec_buffer == NULL) {
Serial.println("Audio buffer malloc failed!");
return;
}
Serial.printf("Recording for %d seconds...\n", RECORD_TIME);
// Start recording
uint32_t sample_size = I2S.readBytes((char*)rec_buffer, record_size);
if (sample_size == 0) {
Serial.println("Recording failed!");
free(rec_buffer);
return;
} else {
Serial.printf("Recorded %d bytes\n", sample_size);
}
// Stream recorded audio in chunks over BLE
size_t offset = 0;
while (offset < sample_size) {
size_t chunk_size = min((size_t)maxPacketSize, (size_t)(sample_size - offset));
uint8_t* chunk_data = rec_buffer + offset;
pNotifyCharacteristic->setValue(chunk_data, chunk_size);
pNotifyCharacteristic->notify();
offset += chunk_size;
delay(30); // Small delay to avoid overwhelming BLE
}
// Send "END" to signal the end of transmission
const char* terminator = "END_AUDIO";
pNotifyCharacteristic->setValue((uint8_t*)terminator, 9);
pNotifyCharacteristic->notify();
free(rec_buffer); // Release buffer memory
Serial.println("Audio sent successfully over BLE.");
}
void setup() {
Serial.begin(115200);
// Initialize BLE
BLEDevice::init("Mira_Glasses");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
// Notify Characteristic for sending audio data
pNotifyCharacteristic = pService->createCharacteristic(
NOTIFY_CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_NOTIFY);
pNotifyCharacteristic->addDescriptor(new BLE2902());
// Write Characteristic for receiving recording requests
pWriteCharacteristic = pService->createCharacteristic(
WRITE_CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_WRITE);
pWriteCharacteristic->setCallbacks(new MyWriteCallbacks());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
BLEDevice::startAdvertising();
Serial.println("Waiting for client to connect...");
// Setup I2S
I2S.setPinsPdmRx(42, 41);
if (!I2S.begin(I2S_MODE_PDM_RX, SAMPLE_RATE, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
Serial.println("Failed to initialize I2S!");
while (1);
}
}
void loop() {
if (deviceConnected && recordingRequest) {
recordAndStreamAudio(); // Record and stream audio when request is received
recordingRequest = false; // Reset the request flag after recording
}
}
Код: Выделить всё
package
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
import android.util.Log
private lateinit var audioTrack: AudioTrack
private const val SAMPLE_RATE = 16000
private const val CHANNEL_CONFIG = AudioFormat.CHANNEL_OUT_MONO
private const val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
fun initAudioTrack() {
val bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT)
audioTrack = AudioTrack( AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
CHANNEL_CONFIG,
AUDIO_FORMAT,
bufferSize,
AudioTrack.MODE_STREAM
)
audioTrack.play()
}
fun playAudio(pcmData: ByteArray) {
// Write the PCM data to AudioTrack for playback
val written = audioTrack.write(pcmData, 0, pcmData.size)
if (written < 0) {
Log.e("AudioTrack", "Error writing audio data: $written")
}
}
fun releaseAudioTrack() {
audioTrack.stop()
audioTrack.release()
}
Моя цель — воспроизводить потоковые аудиоданные в реальном времени. Мое устройство IoT — Little Endian, и я думаю, что Android также работает на Little Endian, так что, вероятно, это не может быть причиной шума.
Я считаю, что такие параметры конфигурации, как частота дискретизации, канал и т. д. одинаковы на устройствах IoT и Android, поэтому они должны работать должным образом, но почему они не работают?
Спасибо
Подробнее здесь: https://stackoverflow.com/questions/790 ... s-properly