/** * Mix PCM data from a given data source to a destination buffer * (which already contains PCM data). The data which is read from the source * buffer is and byte-swapped. * * Use this function, if the source is big endian and the destination * is little endian, or vice versa. * * Performs cipping, if necessary. */ inline void ByteSwapAndMixPCM(int16_t *dest, const int16_t *src, size_t num_frames, unsigned vol_percent) { MixPCM(dest, num_frames, vol_percent, [&src](size_t i) { return static_cast<int32_t>(GenericByteSwap16(src[i])); }); }
/** * Mix PCM data from a given data source to a destination buffer * (which already contains PCM data). * * Performs cipping, if necessary. */ inline void MixPCM(int16_t *dest, const int16_t *src, size_t num_frames, unsigned vol_percent) { MixPCM(dest, num_frames, vol_percent, [&src](size_t i) { return src[i]; }); }
size_t PCMMixerDataSource::GetData(int16_t *buffer, size_t n) { size_t copied_count = 0; PCMDataSource *sources_to_remove[MAX_MIXER_SOURCES_COUNT]; unsigned sources_to_remove_count = 0; const std::lock_guard<Mutex> protect(lock); for (unsigned i = 0; i < MAX_MIXER_SOURCES_COUNT; ++i) { PCMDataSource *source = sources[i]; if (nullptr != source) { bool do_byte_swap = ::IsBigEndian() != source->IsBigEndian(); if (0 == copied_count) { copied_count = source->GetData(buffer, n); if (0 == copied_count) { sources_to_remove[sources_to_remove_count++] = source; } else { if (do_byte_swap) ByteSwapAndLowerVolume(buffer, copied_count, vol_percent); else LowerVolume(buffer, copied_count, vol_percent); } } else { int16_t temp_buffer[1024]; size_t current_src_copied_count = 0; bool current_src_end = false; while (!current_src_end && (current_src_copied_count < copied_count)) { size_t bytes_to_read = std::min(copied_count - current_src_copied_count, ARRAY_SIZE(temp_buffer)); size_t iteration_read_count = source->GetData(temp_buffer, bytes_to_read); if (do_byte_swap) ByteSwapAndMixPCM(buffer + current_src_copied_count, temp_buffer, iteration_read_count, vol_percent); else MixPCM(buffer + current_src_copied_count, temp_buffer, iteration_read_count, vol_percent); current_src_copied_count += iteration_read_count; current_src_end = (iteration_read_count < bytes_to_read); } if (!current_src_end && (copied_count < n)) { size_t bytes_to_read = n - copied_count; size_t rest_read_count = source->GetData(buffer + copied_count, bytes_to_read); if (do_byte_swap) ByteSwapAndLowerVolume(buffer + copied_count, rest_read_count, vol_percent); else LowerVolume(buffer + copied_count, rest_read_count, vol_percent); copied_count += rest_read_count; current_src_end = (rest_read_count < bytes_to_read); } if (current_src_end) { sources_to_remove[sources_to_remove_count++] = source; } } } } if (sources_to_remove_count > 0) { for (unsigned i = 0; i < sources_to_remove_count; ++i) { for (unsigned j = 0; j < MAX_MIXER_SOURCES_COUNT; ++j) { if (sources_to_remove[i] == sources[j]) sources[j] = nullptr; } } } return copied_count; }