Conversation
packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioFileSourceNode.h
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/Audio.tsx
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/Audio.tsx
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/Audio.tsx
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/Audio.tsx
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/Audio.tsx
Outdated
Show resolved
Hide resolved
packages/react-native-audio-api/src/development/react/Audio/types.ts
Outdated
Show resolved
Hide resolved
| void AudioFileSourceNodeHostObject::setOnPositionChangedCallbackId(uint64_t callbackId) { | ||
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | ||
|
|
||
| auto event = [sourceNode, callbackId](BaseAudioContext &) { | ||
| sourceNode->setOnPositionChangedCallbackId(callbackId); | ||
| }; | ||
|
|
||
| sourceNode->unregisterOnPositionChangedCallback(onPositionChangedCallbackId_); | ||
| sourceNode->scheduleAudioEvent(std::move(event)); | ||
| onPositionChangedCallbackId_ = callbackId; | ||
| } |
There was a problem hiding this comment.
| void AudioFileSourceNodeHostObject::setOnPositionChangedCallbackId(uint64_t callbackId) { | |
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | |
| auto event = [sourceNode, callbackId](BaseAudioContext &) { | |
| sourceNode->setOnPositionChangedCallbackId(callbackId); | |
| }; | |
| sourceNode->unregisterOnPositionChangedCallback(onPositionChangedCallbackId_); | |
| sourceNode->scheduleAudioEvent(std::move(event)); | |
| onPositionChangedCallbackId_ = callbackId; | |
| } | |
| void AudioFileSourceNodeHostObject::setOnPositionChangedCallbackId(uint64_t callbackId) { | |
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | |
| auto event = [sourceNode, callbackId, onPositionChangedCallbackId_ = this.onPositionChangedCallbackId_](BaseAudioContext &) { | |
| sourceNode->unregisterOnPositionChangedCallback(onPositionChangedCallbackId_); | |
| sourceNode->setOnPositionChangedCallbackId(callbackId); | |
| }; | |
| sourceNode->scheduleAudioEvent(std::move(event)); | |
| onPositionChangedCallbackId_ = callbackId; | |
| } |
There was a problem hiding this comment.
why? unregisterOnPositionChangedCallback(onPositionChangedCallbackId_) calls audioEventHandlerRegistry_->unregisterHandler(AudioEvent::ENDED, callbackId) that calls invokeAsync on JS thread
There was a problem hiding this comment.
but what if we call a callback in between unregistration and setOnPositionChangeCallback
in this case we try to invoke non existent callback
are we sure this will work fine?
There was a problem hiding this comment.
map with callback is accessed only inside invokeAsync block, so indeed it is thread safe
| void AudioFileSourceNodeHostObject::setOnEndedCallbackId(uint64_t callbackId) { | ||
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | ||
|
|
||
| auto event = [sourceNode, callbackId](BaseAudioContext &) { | ||
| sourceNode->setOnEndedCallbackId(callbackId); | ||
| }; | ||
|
|
||
| sourceNode->unregisterOnEndedCallback(onEndedCallbackId_); | ||
| sourceNode->scheduleAudioEvent(std::move(event)); | ||
| onEndedCallbackId_ = callbackId; | ||
| } |
There was a problem hiding this comment.
| void AudioFileSourceNodeHostObject::setOnEndedCallbackId(uint64_t callbackId) { | |
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | |
| auto event = [sourceNode, callbackId](BaseAudioContext &) { | |
| sourceNode->setOnEndedCallbackId(callbackId); | |
| }; | |
| sourceNode->unregisterOnEndedCallback(onEndedCallbackId_); | |
| sourceNode->scheduleAudioEvent(std::move(event)); | |
| onEndedCallbackId_ = callbackId; | |
| } | |
| void AudioFileSourceNodeHostObject::setOnEndedCallbackId(uint64_t callbackId) { | |
| auto sourceNode = std::static_pointer_cast<AudioFileSourceNode>(node_); | |
| auto event = [sourceNode, callbackId, onEndedCallbackId_ = this.onEndedCallbackId_](BaseAudioContext &) { | |
| sourceNode->unregisterOnEndedCallback(onEndedCallbackId_); | |
| sourceNode->setOnEndedCallbackId(callbackId); | |
| }; | |
| sourceNode->scheduleAudioEvent(std::move(event)); | |
| onEndedCallbackId_ = callbackId; | |
| } |
packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp
Show resolved
Hide resolved
| size_t frames = interleaved.size() / static_cast<size_t>(channels); | ||
| auto buf = std::make_shared<AudioBuffer>(frames, channels, static_cast<float>(sample_rate)); | ||
| for (int c = 0; c < channels; ++c) { | ||
| auto span = buf->getChannel(c)->span(); | ||
| for (size_t i = 0; i < frames; ++i) { | ||
| span[i] = interleaved[i * static_cast<size_t>(channels) + static_cast<size_t>(c)]; | ||
| } | ||
| } | ||
| return buf; |
There was a problem hiding this comment.
you can use AudioBuffer method deinterleaveFrom
| JSI_PROPERTY_GETTER_DECL(volume); | ||
| JSI_PROPERTY_SETTER_DECL(volume); | ||
| JSI_PROPERTY_GETTER_DECL(loop); | ||
| JSI_PROPERTY_SETTER_DECL(loop); | ||
| JSI_PROPERTY_GETTER_DECL(currentTime); | ||
| JSI_PROPERTY_GETTER_DECL(duration); | ||
| JSI_PROPERTY_SETTER_DECL(onPositionChanged); | ||
| JSI_PROPERTY_SETTER_DECL(onEnded); |
There was a problem hiding this comment.
| JSI_PROPERTY_GETTER_DECL(volume); | |
| JSI_PROPERTY_SETTER_DECL(volume); | |
| JSI_PROPERTY_GETTER_DECL(loop); | |
| JSI_PROPERTY_SETTER_DECL(loop); | |
| JSI_PROPERTY_GETTER_DECL(currentTime); | |
| JSI_PROPERTY_GETTER_DECL(duration); | |
| JSI_PROPERTY_SETTER_DECL(onPositionChanged); | |
| JSI_PROPERTY_SETTER_DECL(onEnded); | |
| JSI_PROPERTY_GETTER_DECL(volume); | |
| JSI_PROPERTY_GETTER_DECL(loop); | |
| JSI_PROPERTY_GETTER_DECL(currentTime); | |
| JSI_PROPERTY_GETTER_DECL(duration); | |
| JSI_PROPERTY_SETTER_DECL(volume); | |
| JSI_PROPERTY_SETTER_DECL(loop); | |
| JSI_PROPERTY_SETTER_DECL(onPositionChanged); | |
| JSI_PROPERTY_SETTER_DECL(onEnded); |
|
|
||
| JSI_PROPERTY_GETTER_IMPL(AudioFileSourceNodeHostObject, duration) { | ||
| auto node = std::static_pointer_cast<AudioFileSourceNode>(node_); | ||
| return {node->getDuration()}; |
There was a problem hiding this comment.
you can store duration in shadow state, as well as volume and loop.
| std::shared_ptr<AudioFileSourceNode> BaseAudioContext::createFileSource( | ||
| const AudioFileSourceOptions &options) { | ||
| auto fileSource = std::make_shared<AudioFileSourceNode>(shared_from_this(), options); | ||
| // graphManager_->addProcessingNode(fileSource); |
| ma_decoder_config config = | ||
| ma_decoder_config_init(ma_format_f32, 0, static_cast<ma_uint32>(context->getSampleRate())); | ||
| // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) | ||
| ma_decoding_backend_vtable *customBackends[] = { | ||
| ma_decoding_backend_libvorbis, ma_decoding_backend_libopus}; | ||
| // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) | ||
| config.ppCustomBackendVTables = customBackends; | ||
| config.customBackendCount = sizeof(customBackends) / sizeof(customBackends[0]); | ||
|
|
||
| maDecoder_ = std::make_unique<ma_decoder>(); | ||
| ma_result result; | ||
| if (useFilePath) { | ||
| result = ma_decoder_init_file(state->filePath.c_str(), &config, maDecoder_.get()); | ||
| } else { | ||
| result = ma_decoder_init_memory( | ||
| state->memoryData.data(), state->memoryData.size(), &config, maDecoder_.get()); | ||
| } | ||
|
|
||
| if (result == MA_SUCCESS) { | ||
| state->channels = static_cast<int>(maDecoder_->outputChannels); | ||
| state->sampleRate = static_cast<float>(maDecoder_->outputSampleRate); | ||
| ma_uint64 length = 0; | ||
| if (ma_decoder_get_length_in_pcm_frames(maDecoder_.get(), &length) == MA_SUCCESS) { | ||
| duration_ = static_cast<double>(length) / state->sampleRate; | ||
| } | ||
| } else { | ||
| ma_decoder_uninit(maDecoder_.get()); | ||
| maDecoder_.reset(); | ||
| } | ||
| } |
There was a problem hiding this comment.
is there any way to hide ma decoder initialization impl details inside MiniAudio Decoder class?
| ma_uint64 framesRead = 0; | ||
| ma_decoder_read_pcm_frames(maDecoder_.get(), buf, frameCount, &framesRead); |
There was a problem hiding this comment.
lets hide mini audio impl details
| for (size_t i = 0; i < frameCount; i++) { | ||
| for (int ch = 0; ch < numOutputChannels; ch++) { | ||
| int srcCh = ch < state.channels ? ch : state.channels - 1; | ||
| processingBuffer->getChannel(ch)->span()[destSampleOffset + i] = | ||
| vol * state.interleavedBuffer[i * state.channels + srcCh]; | ||
| } | ||
| } |
There was a problem hiding this comment.
use deinterleaveFrom AudioBuffer method
| AudioFileSourceNode::AudioFileSourceNode( | ||
| const std::shared_ptr<BaseAudioContext> &context, | ||
| const AudioFileSourceOptions &options) | ||
| : AudioNode(context, options), |
There was a problem hiding this comment.
I should inherit from AudioScheduledSourceNode
There was a problem hiding this comment.
it is highly misleading that AudioNode that is not a child of ASSN is a source
| ffmpegdecoder::FFmpegDecoder ffmpegDecoder_; | ||
| ffmpegdecoder::FFmpegDecoderConfig cfg; | ||
| #endif // RN_AUDIO_API_FFMPEG_DISABLED | ||
| std::atomic<bool> filePaused_{false}; |
There was a problem hiding this comment.
maybe it will be better to store state of node like in ASSN. why pause is not send via events queue? I do not think that atomic usage here is necessary. is there any reason behind it?
Closes #735
Introduced changes
Checklist