3 #include "AudioConfig.h"
4 #include "AudioTools/CoreAudio/AudioTypes.h"
5 #include "AudioTools/CoreAudio/Buffers.h"
6 #include "AudioTools/CoreAudio/BaseConverter.h"
7 #include "AudioTools/CoreAudio/AudioLogger.h"
8 #include "AudioTools/CoreAudio/AudioStreams.h"
10 #define NOT_ENOUGH_MEMORY_MSG "Could not allocate enough memory: %d bytes"
50 LOGI(
"buffer_size=%d",buffer_size);
52 LOGE(NOT_ENOUGH_MEMORY_MSG, buffer_size);
88 p_converter =
nullptr;
94 p_converter = &converter;
100 LOGD(
"copy %d bytes %s", (
int) bytes, log_name);
101 if (!active)
return 0;
103 if (from==
nullptr && to==
nullptr)
return 0;
109 int to_write = to->availableForWrite();
110 if (check_available_for_write && to_write==0){
116 if (buffer.size() < bytes){
117 LOGI(
"Resize to %d", (
int) bytes);
118 buffer.resize(bytes);
122 size_t delayCount = 0;
124 if (check_available) {
127 size_t bytes_to_read = bytes;
128 size_t bytes_read = 0;
131 bytes_to_read = min(len,
static_cast<size_t>(buffer_size));
134 bytes_to_read = min((
int)bytes_to_read, to_write);
146 if (bytes_to_read>0){
147 bytes_read = from->readBytes((uint8_t*)&buffer[0], bytes_to_read);
154 if (p_converter!=
nullptr) p_converter->convert((uint8_t*)buffer.data(), result );
157 result =
write(bytes_read, delayCount);
160 if (onWrite!=
nullptr) onWrite(onWriteObj, &buffer[0], result);
163 LOGI(
"StreamCopy::copy %s %u -> %u -> %u bytes - in %u hops",log_name, (
unsigned int)bytes_to_read,(
unsigned int) bytes_read, (
unsigned int)result, (
unsigned int)delayCount);
170 delay(delay_on_no_data);
177 delay(delay_on_no_data);
178 LOGD(
"no data %s", log_name);
186 if (!active)
return 0;
188 for (
size_t j=0;j<pages;j++){
196 if (!active)
return 0;
202 size_t copyAll(
int retryCount=5,
int retryWaitMs=200){
204 if (!active)
return 0;
208 if (from==
nullptr || to ==
nullptr)
224 if (retry>retryCount){
235 if (availableCallback!=
nullptr){
236 result = availableCallback((
Stream*)from);
238 result = from->available();
241 LOGW(
"source not defined");
243 LOGD(
"available: %d", result);
249 delay_on_no_data = delayMs;
260 this->notifyMimeCallback = callback;
266 this->onWrite = onWrite;
267 this->onWriteObj = obj;
272 availableCallback = callback;
287 check_available_for_write = flag;
292 return check_available_for_write;
297 check_available = flag;
302 return check_available;
308 buffer.resize(buffer_size);
333 if (min_copy_size==0){
337 return min_copy_size;
342 min_copy_size = size;
347 is_sync_audio_info = active;
354 int buffer_size = DEFAULT_BUFFER_SIZE;
355 void (*onWrite)(
void*obj,
void*buffer,
size_t len) =
nullptr;
356 void (*notifyMimeCallback)(
const char*
mime) =
nullptr;
357 int (*availableCallback)(Stream*stream)=
nullptr;
358 void *onWriteObj =
nullptr;
359 bool is_first =
false;
360 bool check_available_for_write =
false;
361 bool check_available =
true;
362 const char* actual_mime =
nullptr;
363 int retryLimit = COPY_RETRY_LIMIT;
364 int delay_on_no_data = COPY_DELAY_ON_NODATA;
366 const char* log_name =
"";
367 int retry_delay = 10;
369 int min_copy_size = 1;
370 bool is_sync_audio_info =
false;
371 AudioInfoSupport *p_audio_info_support =
nullptr;
372 BaseConverter* p_converter =
nullptr;
375 void syncAudioInfo(){
377 if (is_sync_audio_info && from !=
nullptr && p_audio_info_support !=
nullptr){
379 AudioInfo info_to = p_audio_info_support->audioInfo();
380 if (info_from != info_to){
381 LOGI(
"--> StreamCopy: ");
382 p_audio_info_support->setAudioInfo(info_from);
388 size_t write(
size_t len,
size_t &delayCount ){
389 if (!buffer || len==0)
return 0;
390 LOGD(
"write: %d", (
int)len);
395 size_t written = to->write((
const uint8_t*)buffer.data()+total, open);
396 LOGD(
"write: %d -> %d", (
int) open, (
int) written);
403 if (written>0) retry = 0;
406 if (retry++ > retryLimit){
407 LOGE(
"write %s to target has failed after %d retries! (%ld bytes)", log_name, retry, open);
414 LOGI(
"try write %s - %d (open %ld bytes) ",log_name, retry, open);
425 if (is_first && len>4) {
426 const uint8_t *start = (
const uint8_t *) data;
427 actual_mime =
"audio/basic";
428 if (start[0]==0xFF && start[1]==0xF1){
429 actual_mime =
"audio/aac";
430 }
else if (memcmp(start,
"ID3",3) || start[0]==0xFF || start[0]==0xFE ){
431 actual_mime =
"audio/mpeg";
432 }
else if (memcmp(start,
"RIFF",4)){
433 actual_mime =
"audio/vnd.wave";
435 if (notifyMimeCallback!=
nullptr){
436 notifyMimeCallback(actual_mime);