3#include "AudioTools/CoreAudio/AudioLogger.h"
4#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
5#include "AudioTools/CoreAudio/AudioStreams.h"
6#include "AudioTools/CoreAudio/AudioTypes.h"
7#include "AudioTools/CoreAudio/BaseConverter.h"
8#include "AudioTools/CoreAudio/Buffers.h"
9#include "AudioToolsConfig.h"
11#define NOT_ENOUGH_MEMORY_MSG "Could not allocate enough memory: %d bytes"
27 : _allocator(allocator), buffer_size(
bufferSize) {
34 : _allocator(allocator), buffer_size(
bufferSize) {
41 : _allocator(allocator), buffer_size(
bufferSize) {
48 : _allocator(allocator), buffer_size(
bufferSize) {
58 if (p_mime_detector !=
nullptr) {
59 p_mime_detector->
begin();
63 LOGI(
"buffer_size=%d", buffer_size);
65 LOGE(NOT_ENOUGH_MEMORY_MSG, buffer_size);
85 this->from_audio = &from;
101 p_converter =
nullptr;
108 p_converter = &converter;
115 LOGD(
"copy %d bytes %s", (
int)bytes, log_name);
116 if (!active)
return 0;
118 if (from ==
nullptr && to ==
nullptr)
return 0;
121 if (bytes == 0)
return 0;
128 int to_write = to->availableForWrite();
129 if (check_available_for_write && to_write == 0) {
135 if (buffer.size() < bytes) {
136 LOGI(
"Resize to %d", (
int)bytes);
137 buffer.resize(bytes);
141 size_t delayCount = 0;
143 if (check_available) {
146 size_t bytes_to_read = len;
147 size_t bytes_read = 0;
150 bytes_to_read = min(len,
static_cast<size_t>(buffer_size));
152 if (check_available_for_write && to_write > 0) {
153 bytes_to_read = min((
int)bytes_to_read, to_write);
165 if (bytes_to_read > 0) {
166 bytes_read = from->readBytes((uint8_t *)&buffer[0], bytes_to_read);
170 if (p_mime_detector !=
nullptr) {
171 p_mime_detector->
write(buffer.data(), bytes_to_read);
175 if (p_converter !=
nullptr)
176 p_converter->convert((uint8_t *)buffer.data(), bytes_read);
179 result =
write(bytes_read, delayCount);
182 if (onWrite !=
nullptr) onWrite(onWriteObj, &buffer[0], result);
185 LOGI(
"StreamCopy::copy %s %u -> %u -> %u bytes - in %u hops", log_name,
186 (
unsigned int)bytes_to_read, (
unsigned int)bytes_read,
187 (
unsigned int)result, (
unsigned int)delayCount);
194 delay(delay_on_no_data);
201 delay(delay_on_no_data);
202 LOGD(
"no data %s", log_name);
210 if (!active)
return 0;
212 for (
size_t j = 0; j < pages; j++) {
221 if (!active)
return 0;
227 size_t copyAll(
int retryCount = 5,
int retryWaitMs = 200) {
229 if (!active)
return 0;
233 if (from ==
nullptr || to ==
nullptr)
return result;
248 if (retry > retryCount) {
258 if (from !=
nullptr) {
259 if (availableCallback !=
nullptr) {
260 result = availableCallback((
Stream *)from);
262 result = from->available();
265 LOGW(
"source not defined");
267 LOGD(
"available: %d", result);
278 this->onWrite = onWrite;
279 this->onWriteObj = obj;
284 availableCallback = callback;
296 check_available_for_write = flag;
328 if (min_copy_size == 0 && from_audio !=
nullptr) {
332 return min_copy_size;
352 int buffer_size = DEFAULT_BUFFER_SIZE;
353 void (*onWrite)(
void *obj,
void *buffer,
size_t len) =
nullptr;
354 int (*availableCallback)(Stream *stream) =
nullptr;
355 void *onWriteObj =
nullptr;
356 bool check_available_for_write =
false;
357 bool check_available =
true;
358 int retryLimit = COPY_RETRY_LIMIT;
359 int delay_on_no_data = COPY_DELAY_ON_NODATA;
361 const char *log_name =
"";
362 int retry_delay = 10;
364 int min_copy_size = 1;
365 bool is_sync_audio_info =
false;
366 AudioInfoSupport *p_audio_info_support =
nullptr;
367 BaseConverter *p_converter =
nullptr;
368 MimeDetector *p_mime_detector =
nullptr;
370 void syncAudioInfo() {
372 if (is_sync_audio_info && from_audio !=
nullptr &&
373 p_audio_info_support !=
nullptr) {
375 AudioInfo info_to = p_audio_info_support->audioInfo();
376 if (info_from != info_to) {
377 LOGI(
"--> StreamCopy: ");
378 p_audio_info_support->setAudioInfo(info_from);
384 size_t write(
size_t len,
size_t &delayCount) {
385 if (!buffer || len == 0)
return 0;
386 LOGD(
"write: %d", (
int)len);
391 size_t written = to->write((
const uint8_t *)buffer.data() + total, open);
392 LOGD(
"write: %d -> %d", (
int)open, (
int)written);
399 if (written > 0) retry = 0;
402 if (retry++ > retryLimit) {
403 LOGE(
"write %s to target has failed after %d retries! (%ld bytes)",
404 log_name, retry, open);
411 LOGI(
"try write %s - %d (open %ld bytes) ", log_name, retry, open);