react-native-audio-api 0.9.0-nightly-96a5bcd-20251007 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/android/src/main/cpp/audioapi/android/core/{utils/AudioDecoder.cpp → AudioDecoder.cpp} +75 -79
  2. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +43 -99
  3. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +101 -1
  4. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +3 -0
  5. package/common/cpp/audioapi/core/AudioContext.cpp +2 -0
  6. package/common/cpp/audioapi/core/BaseAudioContext.cpp +35 -0
  7. package/common/cpp/audioapi/core/BaseAudioContext.h +12 -4
  8. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -0
  9. package/common/cpp/audioapi/core/utils/AudioDecoder.h +90 -36
  10. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +282 -241
  11. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +19 -57
  12. package/common/cpp/test/CMakeLists.txt +1 -1
  13. package/ios/audioapi/ios/core/AudioDecoder.mm +156 -0
  14. package/lib/commonjs/api.js +1 -14
  15. package/lib/commonjs/api.js.map +1 -1
  16. package/lib/commonjs/core/BaseAudioContext.js +18 -11
  17. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  18. package/lib/module/api.js +1 -2
  19. package/lib/module/api.js.map +1 -1
  20. package/lib/module/core/BaseAudioContext.js +18 -11
  21. package/lib/module/core/BaseAudioContext.js.map +1 -1
  22. package/lib/typescript/api.d.ts +1 -3
  23. package/lib/typescript/api.d.ts.map +1 -1
  24. package/lib/typescript/core/BaseAudioContext.d.ts +6 -3
  25. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  26. package/lib/typescript/interfaces.d.ts +3 -6
  27. package/lib/typescript/interfaces.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/api.ts +0 -5
  30. package/src/core/BaseAudioContext.ts +29 -26
  31. package/src/interfaces.ts +6 -18
  32. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +0 -107
  33. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +0 -28
  34. package/common/cpp/audioapi/core/types/AudioFormat.h +0 -16
  35. package/ios/audioapi/ios/core/utils/AudioDecoder.mm +0 -160
  36. package/lib/commonjs/core/AudioDecoder.js +0 -48
  37. package/lib/commonjs/core/AudioDecoder.js.map +0 -1
  38. package/lib/module/core/AudioDecoder.js +0 -42
  39. package/lib/module/core/AudioDecoder.js.map +0 -1
  40. package/lib/typescript/core/AudioDecoder.d.ts +0 -4
  41. package/lib/typescript/core/AudioDecoder.d.ts.map +0 -1
  42. package/src/core/AudioDecoder.ts +0 -78
@@ -1,20 +1,16 @@
1
1
  /*
2
- * This file dynamically links to the FFmpeg library, which is licensed under
3
- * the GNU Lesser General Public License (LGPL) version 2.1 or later.
2
+ * This file dynamically links to the FFmpeg library, which is licensed under the
3
+ * GNU Lesser General Public License (LGPL) version 2.1 or later.
4
4
  *
5
- * Our own code in this file is licensed under the MIT License and dynamic
6
- * linking allows you to use this code without your entire project being subject
7
- * to the terms of the LGPL. However, note that if you link statically to
8
- * FFmpeg, you must comply with the terms of the LGPL for FFmpeg itself.
5
+ * Our own code in this file is licensed under the MIT License and dynamic linking
6
+ * allows you to use this code without your entire project being subject to the
7
+ * terms of the LGPL. However, note that if you link statically to FFmpeg, you must
8
+ * comply with the terms of the LGPL for FFmpeg itself.
9
9
  */
10
10
 
11
- #include <audioapi/core/sources/AudioBuffer.h>
12
- #include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
13
- #include <audioapi/utils/AudioArray.h>
14
- #include <audioapi/utils/AudioBus.h>
15
- #include <functional>
11
+ #include "FFmpegDecoding.h"
16
12
 
17
- namespace audioapi::ffmpegdecoder {
13
+ namespace audioapi::ffmpegdecoding {
18
14
 
19
15
  int read_packet(void *opaque, uint8_t *buf, int buf_size) {
20
16
  MemoryIOContext *ctx = static_cast<MemoryIOContext *>(opaque);
@@ -55,87 +51,42 @@ int64_t seek_packet(void *opaque, int64_t offset, int whence) {
55
51
  return ctx->pos;
56
52
  }
57
53
 
58
- void convertFrameToBuffer(
59
- SwrContext *swr,
60
- AVFrame *frame,
61
- int output_channel_count,
62
- std::vector<float> &buffer,
63
- size_t &framesRead,
64
- uint8_t **&resampled_data,
65
- int &max_resampled_samples) {
66
- const int out_samples = swr_get_out_samples(swr, frame->nb_samples);
67
- if (out_samples > max_resampled_samples) {
68
- av_freep(&resampled_data[0]);
69
- av_freep(&resampled_data);
70
- max_resampled_samples = out_samples;
71
-
72
- if (av_samples_alloc_array_and_samples(
73
- &resampled_data,
74
- nullptr,
75
- output_channel_count,
76
- max_resampled_samples,
77
- AV_SAMPLE_FMT_FLT,
78
- 0) < 0) {
79
- return;
80
- }
81
- }
82
-
83
- int converted_samples = swr_convert(
84
- swr,
85
- resampled_data,
86
- max_resampled_samples,
87
- const_cast<const uint8_t **>(frame->data),
88
- frame->nb_samples);
89
-
90
- if (converted_samples > 0) {
91
- const size_t current_size = buffer.size();
92
- const size_t new_samples =
93
- static_cast<size_t>(converted_samples) * output_channel_count;
94
- buffer.resize(current_size + new_samples);
95
- memcpy(
96
- buffer.data() + current_size,
97
- resampled_data[0],
98
- new_samples * sizeof(float));
99
- framesRead += converted_samples;
100
- }
101
- }
102
-
103
- std::vector<float> readAllPcmFrames(
54
+ std::vector<int16_t> readAllPcmFrames(
104
55
  AVFormatContext *fmt_ctx,
105
56
  AVCodecContext *codec_ctx,
106
57
  int out_sample_rate,
107
- int output_channel_count,
108
58
  int audio_stream_index,
59
+ int channels,
109
60
  size_t &framesRead) {
110
- framesRead = 0;
111
- std::vector<float> buffer;
112
- auto swr = std::unique_ptr<SwrContext, std::function<void(SwrContext *)>>(
113
- swr_alloc(), [](SwrContext *ctx) { swr_free(&ctx); });
114
-
115
- if (swr == nullptr)
61
+ std::vector<int16_t> buffer;
62
+ SwrContext *swr_ctx = swr_alloc();
63
+ if (swr_ctx == nullptr) {
116
64
  return buffer;
65
+ }
117
66
 
118
- av_opt_set_chlayout(swr.get(), "in_chlayout", &codec_ctx->ch_layout, 0);
119
- av_opt_set_int(swr.get(), "in_sample_rate", codec_ctx->sample_rate, 0);
120
- av_opt_set_sample_fmt(swr.get(), "in_sample_fmt", codec_ctx->sample_fmt, 0);
67
+ av_opt_set_chlayout(swr_ctx, "in_chlayout", &codec_ctx->ch_layout, 0);
68
+ av_opt_set_int(swr_ctx, "in_sample_rate", codec_ctx->sample_rate, 0);
69
+ av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", codec_ctx->sample_fmt, 0);
121
70
 
122
71
  AVChannelLayout out_ch_layout;
123
- av_channel_layout_default(&out_ch_layout, output_channel_count);
124
- av_opt_set_chlayout(swr.get(), "out_chlayout", &out_ch_layout, 0);
125
- av_opt_set_int(swr.get(), "out_sample_rate", out_sample_rate, 0);
126
- av_opt_set_sample_fmt(swr.get(), "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
72
+ av_channel_layout_default(&out_ch_layout, channels);
73
+ av_opt_set_chlayout(swr_ctx, "out_chlayout", &out_ch_layout, 0);
74
+ av_opt_set_int(swr_ctx, "out_sample_rate", out_sample_rate, 0);
75
+ av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
127
76
 
128
- if (swr_init(swr.get()) < 0) {
77
+ if (swr_init(swr_ctx) < 0) {
78
+ swr_free(&swr_ctx);
129
79
  av_channel_layout_uninit(&out_ch_layout);
130
80
  return buffer;
131
81
  }
132
82
 
133
- auto packet = std::unique_ptr<AVPacket, std::function<void(AVPacket *)>>(
134
- av_packet_alloc(), [](AVPacket *p) { av_packet_free(&p); });
135
- auto frame = std::unique_ptr<AVFrame, std::function<void(AVFrame *)>>(
136
- av_frame_alloc(), [](AVFrame *p) { av_frame_free(&p); });
137
-
83
+ AVPacket *packet = av_packet_alloc();
84
+ AVFrame *frame = av_frame_alloc();
85
+
138
86
  if (packet == nullptr || frame == nullptr) {
87
+ if (packet != nullptr) av_packet_free(&packet);
88
+ if (frame != nullptr) av_frame_free(&frame);
89
+ swr_free(&swr_ctx);
139
90
  av_channel_layout_uninit(&out_ch_layout);
140
91
  return buffer;
141
92
  }
@@ -143,222 +94,312 @@ std::vector<float> readAllPcmFrames(
143
94
  // Allocate buffer for resampled data
144
95
  uint8_t **resampled_data = nullptr;
145
96
  int max_resampled_samples = 4096; // Initial size
146
- if (av_samples_alloc_array_and_samples(
147
- &resampled_data,
148
- nullptr,
149
- output_channel_count,
150
- max_resampled_samples,
151
- AV_SAMPLE_FMT_FLT,
152
- 0) < 0) {
97
+ int ret = av_samples_alloc_array_and_samples(
98
+ &resampled_data,
99
+ nullptr,
100
+ channels,
101
+ max_resampled_samples,
102
+ AV_SAMPLE_FMT_S16,
103
+ 0);
104
+
105
+ if (ret < 0) {
106
+ av_frame_free(&frame);
107
+ av_packet_free(&packet);
108
+ swr_free(&swr_ctx);
153
109
  av_channel_layout_uninit(&out_ch_layout);
154
110
  return buffer;
155
111
  }
156
112
 
157
- while (av_read_frame(fmt_ctx, packet.get()) >= 0) {
113
+ framesRead = 0;
114
+
115
+ while (av_read_frame(fmt_ctx, packet) >= 0) {
158
116
  if (packet->stream_index == audio_stream_index) {
159
- if (avcodec_send_packet(codec_ctx, packet.get()) == 0) {
160
- while (avcodec_receive_frame(codec_ctx, frame.get()) == 0) {
161
- convertFrameToBuffer(
162
- swr.get(),
163
- frame.get(),
164
- output_channel_count,
165
- buffer,
166
- framesRead,
117
+ if (avcodec_send_packet(codec_ctx, packet) == 0) {
118
+ while (avcodec_receive_frame(codec_ctx, frame) == 0) {
119
+ // Check if we need more buffer space
120
+ int out_samples = swr_get_out_samples(swr_ctx, frame->nb_samples);
121
+ if (out_samples > max_resampled_samples) {
122
+ if (resampled_data != nullptr) {
123
+ av_freep(&resampled_data[0]);
124
+ av_freep(&resampled_data);
125
+ }
126
+
127
+ max_resampled_samples = out_samples;
128
+ ret = av_samples_alloc_array_and_samples(
129
+ &resampled_data,
130
+ nullptr,
131
+ channels,
132
+ max_resampled_samples,
133
+ AV_SAMPLE_FMT_S16,
134
+ 0);
135
+
136
+ if (ret < 0) {
137
+ break; // Exit on allocation failure
138
+ }
139
+ }
140
+
141
+ int converted_samples = swr_convert(
142
+ swr_ctx,
167
143
  resampled_data,
168
- max_resampled_samples);
144
+ max_resampled_samples,
145
+ (const uint8_t **)frame->data,
146
+ frame->nb_samples);
147
+
148
+ if (converted_samples > 0) {
149
+ size_t current_size = buffer.size();
150
+ size_t new_samples = converted_samples * channels;
151
+ buffer.resize(current_size + new_samples);
152
+ memcpy(
153
+ buffer.data() + current_size,
154
+ resampled_data[0],
155
+ new_samples * sizeof(int16_t));
156
+
157
+ framesRead += converted_samples;
158
+ }
169
159
  }
170
160
  }
171
161
  }
172
- av_packet_unref(packet.get());
162
+ av_packet_unref(packet);
173
163
  }
174
164
 
175
165
  // Flush decoder
176
166
  avcodec_send_packet(codec_ctx, nullptr);
177
- while (avcodec_receive_frame(codec_ctx, frame.get()) == 0) {
178
- convertFrameToBuffer(
179
- swr.get(),
180
- frame.get(),
181
- output_channel_count,
182
- buffer,
183
- framesRead,
167
+ while (avcodec_receive_frame(codec_ctx, frame) == 0) {
168
+ int out_samples = swr_get_out_samples(swr_ctx, frame->nb_samples);
169
+ if (out_samples > max_resampled_samples) {
170
+ if (resampled_data != nullptr) {
171
+ av_freep(&resampled_data[0]);
172
+ av_freep(&resampled_data);
173
+ }
174
+
175
+ max_resampled_samples = out_samples;
176
+ ret = av_samples_alloc_array_and_samples(
177
+ &resampled_data,
178
+ nullptr,
179
+ channels,
180
+ max_resampled_samples,
181
+ AV_SAMPLE_FMT_S16,
182
+ 0);
183
+
184
+ if (ret < 0) {
185
+ break;
186
+ }
187
+ }
188
+
189
+ int converted_samples = swr_convert(
190
+ swr_ctx,
184
191
  resampled_data,
185
- max_resampled_samples);
192
+ max_resampled_samples,
193
+ (const uint8_t **)frame->data,
194
+ frame->nb_samples);
195
+
196
+ if (converted_samples > 0) {
197
+ size_t current_size = buffer.size();
198
+ size_t new_samples = converted_samples * channels;
199
+ buffer.resize(current_size + new_samples);
200
+ memcpy(
201
+ buffer.data() + current_size,
202
+ resampled_data[0],
203
+ new_samples * sizeof(int16_t));
204
+
205
+ framesRead += converted_samples;
206
+ }
186
207
  }
187
208
 
188
- av_freep(&resampled_data[0]);
189
- av_freep(&resampled_data);
209
+ if (resampled_data != nullptr) {
210
+ av_freep(&resampled_data[0]);
211
+ av_freep(&resampled_data);
212
+ }
213
+ swr_free(&swr_ctx);
190
214
  av_channel_layout_uninit(&out_ch_layout);
215
+ av_frame_free(&frame);
216
+ av_packet_free(&packet);
191
217
 
192
218
  return buffer;
193
219
  }
194
220
 
195
- inline int findAudioStreamIndex(AVFormatContext *fmt_ctx) {
196
- for (int i = 0; i < fmt_ctx->nb_streams; i++) {
197
- if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
198
- return i;
221
+ std::vector<int16_t> decodeWithMemoryBlock(const void *data, size_t size, const int channel_count, int sample_rate) {
222
+ if (data == nullptr || size == 0) {
223
+ return {};
199
224
  }
200
- }
201
- return -1;
202
- }
203
225
 
204
- bool setupDecoderContext(
205
- AVFormatContext *fmt_ctx,
206
- int &audio_stream_index,
207
- std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>
208
- &codec_ctx) {
209
- audio_stream_index = findAudioStreamIndex(fmt_ctx);
210
- if (audio_stream_index == -1) {
211
- return false;
212
- }
226
+ MemoryIOContext io_ctx;
227
+ io_ctx.data = static_cast<const uint8_t *>(data);
228
+ io_ctx.size = size;
229
+ io_ctx.pos = 0;
213
230
 
214
- AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
215
- const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
216
- if (codec == nullptr) {
217
- return false;
218
- }
231
+ constexpr size_t buffer_size = 4096;
232
+ uint8_t *io_buffer = static_cast<uint8_t *>(av_malloc(buffer_size));
233
+ if (io_buffer == nullptr) {
234
+ return {};
235
+ }
219
236
 
220
- AVCodecContext *raw_codec_ctx = avcodec_alloc_context3(codec);
221
- if (raw_codec_ctx == nullptr) {
222
- return false;
223
- }
237
+ AVIOContext *avio_ctx = avio_alloc_context(
238
+ io_buffer, buffer_size, 0, &io_ctx, read_packet, nullptr, seek_packet);
224
239
 
225
- codec_ctx.reset(raw_codec_ctx);
226
- if (avcodec_parameters_to_context(codec_ctx.get(), codecpar) < 0) {
227
- return false;
228
- }
229
- if (avcodec_open2(codec_ctx.get(), codec, nullptr) < 0) {
230
- return false;
231
- }
240
+ if (avio_ctx == nullptr) {
241
+ av_free(io_buffer);
242
+ return {};
243
+ }
232
244
 
233
- return true;
234
- }
245
+ // Create format context and set custom IO
246
+ AVFormatContext *fmt_ctx = avformat_alloc_context();
247
+ if (fmt_ctx == nullptr) {
248
+ avio_context_free(&avio_ctx);
249
+ return {};
250
+ }
251
+
252
+ fmt_ctx->pb = avio_ctx;
253
+
254
+ // Open input from memory
255
+ if (avformat_open_input(&fmt_ctx, nullptr, nullptr, nullptr) < 0) {
256
+ avformat_free_context(fmt_ctx);
257
+ avio_context_free(&avio_ctx);
258
+ return {};
259
+ }
235
260
 
236
- std::shared_ptr<AudioBuffer> decodeAudioFrames(
237
- AVFormatContext *fmt_ctx,
238
- AVCodecContext *codec_ctx,
239
- int audio_stream_index,
240
- int sample_rate) {
241
- size_t framesRead = 0;
242
- int output_sample_rate =
243
- (sample_rate > 0) ? sample_rate : codec_ctx->sample_rate;
244
- int output_channel_count = codec_ctx->ch_layout.nb_channels;
245
-
246
- std::vector<float> decoded_buffer = readAllPcmFrames(
247
- fmt_ctx,
248
- codec_ctx,
249
- output_sample_rate,
250
- output_channel_count,
251
- audio_stream_index,
252
- framesRead);
261
+ // Find stream info
262
+ if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
263
+ avformat_close_input(&fmt_ctx);
264
+ avio_context_free(&avio_ctx);
265
+ return {};
266
+ }
253
267
 
254
- if (framesRead == 0 || decoded_buffer.empty()) {
255
- return nullptr;
256
- }
268
+ int audio_stream_index = -1;
269
+ for (int i = 0; i < fmt_ctx->nb_streams; i++) {
270
+ if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
271
+ audio_stream_index = i;
272
+ break;
273
+ }
274
+ }
275
+
276
+ if (audio_stream_index == -1) {
277
+ avformat_close_input(&fmt_ctx);
278
+ avio_context_free(&avio_ctx);
279
+ return {};
280
+ }
257
281
 
258
- auto outputFrames = decoded_buffer.size() / output_channel_count;
259
- auto audioBus = std::make_shared<AudioBus>(
260
- outputFrames, output_channel_count, output_sample_rate);
282
+ AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
261
283
 
262
- for (int ch = 0; ch < output_channel_count; ++ch) {
263
- auto channelData = audioBus->getChannel(ch)->getData();
264
- for (int i = 0; i < outputFrames; ++i) {
265
- channelData[i] = decoded_buffer[i * output_channel_count + ch];
284
+ // Find decoder
285
+ const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
286
+ if (codec == nullptr) {
287
+ avformat_close_input(&fmt_ctx);
288
+ avio_context_free(&avio_ctx);
289
+ return {};
266
290
  }
267
- }
268
- return std::make_shared<AudioBuffer>(audioBus);
269
- }
270
291
 
271
- std::shared_ptr<AudioBuffer>
272
- decodeWithMemoryBlock(const void *data, size_t size, int sample_rate) {
273
- if (data == nullptr || size == 0) {
274
- return nullptr;
275
- }
292
+ // Allocate and setup codec context
293
+ AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
294
+ if (codec_ctx == nullptr) {
295
+ avformat_close_input(&fmt_ctx);
296
+ avio_context_free(&avio_ctx);
297
+ return {};
298
+ }
276
299
 
277
- MemoryIOContext io_ctx{static_cast<const uint8_t *>(data), size, 0};
300
+ if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
301
+ avcodec_free_context(&codec_ctx);
302
+ avformat_close_input(&fmt_ctx);
303
+ avio_context_free(&avio_ctx);
304
+ return {};
305
+ }
278
306
 
279
- constexpr size_t buffer_size = 4096;
280
- auto io_buffer = std::unique_ptr<uint8_t, decltype(&av_free)>(
281
- static_cast<uint8_t *>(av_malloc(buffer_size)), &av_free);
282
- if (io_buffer == nullptr) {
283
- return nullptr;
284
- }
307
+ if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
308
+ avcodec_free_context(&codec_ctx);
309
+ avformat_close_input(&fmt_ctx);
310
+ avio_context_free(&avio_ctx);
311
+ return {};
312
+ }
285
313
 
286
- auto avio_ctx =
287
- std::unique_ptr<AVIOContext, std::function<void(AVIOContext *)>>(
288
- avio_alloc_context(
289
- io_buffer.get(),
290
- buffer_size,
291
- 0,
292
- &io_ctx,
293
- read_packet,
294
- nullptr,
295
- seek_packet),
296
- [](AVIOContext *ctx) { avio_context_free(&ctx); });
297
- if (avio_ctx == nullptr) {
298
- return nullptr;
299
- }
314
+ // Get actual channel count from the decoded stream
315
+ int actual_channels = codec_ctx->ch_layout.nb_channels;
300
316
 
301
- AVFormatContext *raw_fmt_ctx = avformat_alloc_context();
302
- if (raw_fmt_ctx == nullptr) {
303
- return nullptr;
304
- }
305
- raw_fmt_ctx->pb = avio_ctx.get();
317
+ // Validate channel count
318
+ if (actual_channels <= 0 || actual_channels > 8) {
319
+ avcodec_free_context(&codec_ctx);
320
+ avformat_close_input(&fmt_ctx);
321
+ avio_context_free(&avio_ctx);
322
+ return {};
323
+ }
306
324
 
307
- if (avformat_open_input(&raw_fmt_ctx, nullptr, nullptr, nullptr) < 0) {
308
- avformat_free_context(raw_fmt_ctx);
309
- return nullptr;
310
- }
325
+ // Decode all frames
326
+ size_t framesRead = 0;
327
+ std::vector<int16_t> decoded_buffer = readAllPcmFrames(
328
+ fmt_ctx, codec_ctx, sample_rate, audio_stream_index, channel_count, framesRead);
311
329
 
312
- auto fmt_ctx =
313
- std::unique_ptr<AVFormatContext, decltype(&avformat_free_context)>(
314
- raw_fmt_ctx, &avformat_free_context);
330
+ // Cleanup - Note: avio_context_free will free the io_buffer
331
+ avcodec_free_context(&codec_ctx);
332
+ avformat_close_input(&fmt_ctx);
333
+ avio_context_free(&avio_ctx);
315
334
 
316
- if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
317
- return nullptr;
335
+ if (framesRead == 0 || decoded_buffer.empty()) {
336
+ return {};
337
+ }
338
+
339
+ return decoded_buffer;
340
+ }
341
+
342
+ std::vector<int16_t> decodeWithFilePath(const std::string &path, const int channel_count, int sample_rate) {
343
+ if (path.empty()) {
344
+ return {};
318
345
  }
319
346
 
320
- auto codec_ctx =
321
- std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>(
322
- nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
347
+ AVFormatContext *fmt_ctx = nullptr;
348
+ if (avformat_open_input(&fmt_ctx, path.c_str(), nullptr, nullptr) < 0) {
349
+ return {};
350
+ }
351
+ if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
352
+ avformat_close_input(&fmt_ctx);
353
+ return {};
354
+ }
323
355
  int audio_stream_index = -1;
324
- if (!setupDecoderContext(fmt_ctx.get(), audio_stream_index, codec_ctx)) {
325
- return nullptr;
356
+ for (int i = 0; i < fmt_ctx->nb_streams; i++) {
357
+ if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
358
+ audio_stream_index = i;
359
+ break;
360
+ }
361
+ }
362
+ if (audio_stream_index == -1) {
363
+ avformat_close_input(&fmt_ctx);
364
+ return {};
326
365
  }
327
366
 
328
- return decodeAudioFrames(
329
- fmt_ctx.get(), codec_ctx.get(), audio_stream_index, sample_rate);
330
- }
367
+ AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
368
+ const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
369
+ if (codec == nullptr) {
370
+ avformat_close_input(&fmt_ctx);
371
+ return {};
372
+ }
373
+ AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
374
+ if (codec_ctx == nullptr) {
375
+ avformat_close_input(&fmt_ctx);
376
+ return {};
377
+ }
331
378
 
332
- std::shared_ptr<AudioBuffer> decodeWithFilePath(
333
- const std::string &path,
334
- int sample_rate) {
335
- if (path.empty()) {
336
- return nullptr;
379
+ if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
380
+ avcodec_free_context(&codec_ctx);
381
+ avformat_close_input(&fmt_ctx);
382
+ return {};
337
383
  }
338
384
 
339
- AVFormatContext *raw_fmt_ctx = nullptr;
340
- if (avformat_open_input(&raw_fmt_ctx, path.c_str(), nullptr, nullptr) < 0)
341
- return nullptr;
385
+ if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
386
+ avcodec_free_context(&codec_ctx);
387
+ avformat_close_input(&fmt_ctx);
388
+ return {};
389
+ }
342
390
 
343
- auto fmt_ctx =
344
- std::unique_ptr<AVFormatContext, std::function<void(AVFormatContext *)>>(
345
- raw_fmt_ctx,
346
- [](AVFormatContext *ctx) { avformat_close_input(&ctx); });
391
+ size_t framesRead = 0;
392
+ std::vector<int16_t> decoded_buffer = readAllPcmFrames(
393
+ fmt_ctx, codec_ctx, sample_rate, audio_stream_index, channel_count, framesRead);
347
394
 
348
- if (avformat_find_stream_info(fmt_ctx.get(), nullptr) < 0) {
349
- return nullptr;
350
- }
395
+ avcodec_free_context(&codec_ctx);
396
+ avformat_close_input(&fmt_ctx);
351
397
 
352
- auto codec_ctx =
353
- std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>(
354
- nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
355
- int audio_stream_index = -1;
356
- if (!setupDecoderContext(fmt_ctx.get(), audio_stream_index, codec_ctx)) {
357
- return nullptr;
398
+ if (framesRead == 0 || decoded_buffer.empty()) {
399
+ return {};
358
400
  }
359
401
 
360
- return decodeAudioFrames(
361
- fmt_ctx.get(), codec_ctx.get(), audio_stream_index, sample_rate);
402
+ return decoded_buffer;
362
403
  }
363
404
 
364
405
  } // namespace audioapi::ffmpegdecoder