• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

melchor629 / node-flac-bindings / 15650914751

14 Jun 2025 10:05AM UTC coverage: 91.005% (-0.2%) from 91.222%
15650914751

push

github

melchor629
fix: variable i refactor

161 of 206 branches covered (78.16%)

Branch coverage included in aggregate %.

3 of 3 new or added lines in 1 file covered. (100.0%)

12 existing lines in 3 files now uncovered.

5019 of 5486 relevant lines covered (91.49%)

37227.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.17
/src/encoder/encoder-builder.cpp
1
#include "../mappings/mappings.hpp"
2
#include "encoder.hpp"
3

4
namespace flac_bindings {
5

6
  Function StreamEncoderBuilder::init(Napi::Env env, FlacAddon& addon) {
21✔
7
    EscapableHandleScope scope(env);
21✔
8

9
    auto constructor = DefineClass(
21✔
10
      env,
11
      "StreamEncoderBuilder",
12
      {
13
        InstanceMethod("getState", &StreamEncoderBuilder::getState),
21✔
14
        InstanceMethod("getVerify", &StreamEncoderBuilder::getVerify),
21✔
15
        InstanceMethod("getStreamableSubset", &StreamEncoderBuilder::getStreamableSubset),
21✔
16
        InstanceMethod("getChannels", &StreamEncoderBuilder::getChannels),
21✔
17
        InstanceMethod("getBitsPerSample", &StreamEncoderBuilder::getBitsPerSample),
21✔
18
        InstanceMethod("getSampleRate", &StreamEncoderBuilder::getSampleRate),
21✔
19
        InstanceMethod("getBlocksize", &StreamEncoderBuilder::getBlocksize),
21✔
20
        InstanceMethod("getDoMidSideStereo", &StreamEncoderBuilder::getDoMidSideStereo),
21✔
21
        InstanceMethod("getLooseMidSideStereo", &StreamEncoderBuilder::getLooseMidSideStereo),
21✔
22
        InstanceMethod("getMaxLpcOrder", &StreamEncoderBuilder::getMaxLpcOrder),
21✔
23
        InstanceMethod("getQlpCoeffPrecision", &StreamEncoderBuilder::getQlpCoeffPrecision),
21✔
24
        InstanceMethod("getDoQlpCoeffPrecSearch", &StreamEncoderBuilder::getDoQlpCoeffPrecSearch),
21✔
25
        InstanceMethod("getDoEscapeCoding", &StreamEncoderBuilder::getDoEscapeCoding),
21✔
26
        InstanceMethod(
21✔
27
          "getDoExhaustiveModelSearch",
28
          &StreamEncoderBuilder::getDoExhaustiveModelSearch),
29
        InstanceMethod(
21✔
30
          "getMinResidualPartitionOrder",
31
          &StreamEncoderBuilder::getMinResidualPartitionOrder),
32
        InstanceMethod(
21✔
33
          "getMaxResidualPartitionOrder",
34
          &StreamEncoderBuilder::getMaxResidualPartitionOrder),
35
        InstanceMethod(
21✔
36
          "getRiceParameterSearchDist",
37
          &StreamEncoderBuilder::getRiceParameterSearchDist),
38
        InstanceMethod("getLimitMinBitrate", &StreamEncoderBuilder::getLimitMinBitrate),
21✔
39
        InstanceMethod("getTotalSamplesEstimate", &StreamEncoderBuilder::getTotalSamplesEstimate),
21✔
40
        InstanceMethod("getNumThreads", &StreamEncoderBuilder::getNumThreads),
21✔
41

42
        InstanceMethod("setOggSerialNumber", &StreamEncoderBuilder::setOggSerialNumber),
21✔
43
        InstanceMethod("setVerify", &StreamEncoderBuilder::setVerify),
21✔
44
        InstanceMethod("setStreamableSubset", &StreamEncoderBuilder::setStreamableSubset),
21✔
45
        InstanceMethod("setChannels", &StreamEncoderBuilder::setChannels),
21✔
46
        InstanceMethod("setBitsPerSample", &StreamEncoderBuilder::setBitsPerSample),
21✔
47
        InstanceMethod("setSampleRate", &StreamEncoderBuilder::setSampleRate),
21✔
48
        InstanceMethod("setCompressionLevel", &StreamEncoderBuilder::setCompressionLevel),
21✔
49
        InstanceMethod("setBlocksize", &StreamEncoderBuilder::setBlocksize),
21✔
50
        InstanceMethod("setDoMidSideStereo", &StreamEncoderBuilder::setDoMidSideStereo),
21✔
51
        InstanceMethod("setLooseMidSideStereo", &StreamEncoderBuilder::setLooseMidSideStereo),
21✔
52
        InstanceMethod("setMaxLpcOrder", &StreamEncoderBuilder::setMaxLpcOrder),
21✔
53
        InstanceMethod("setQlpCoeffPrecision", &StreamEncoderBuilder::setQlpCoeffPrecision),
21✔
54
        InstanceMethod("setDoQlpCoeffPrecSearch", &StreamEncoderBuilder::setDoQlpCoeffPrecSearch),
21✔
55
        InstanceMethod("setDoEscapeCoding", &StreamEncoderBuilder::setDoEscapeCoding),
21✔
56
        InstanceMethod(
21✔
57
          "setDoExhaustiveModelSearch",
58
          &StreamEncoderBuilder::setDoExhaustiveModelSearch),
59
        InstanceMethod(
21✔
60
          "setMinResidualPartitionOrder",
61
          &StreamEncoderBuilder::setMinResidualPartitionOrder),
62
        InstanceMethod(
21✔
63
          "setMaxResidualPartitionOrder",
64
          &StreamEncoderBuilder::setMaxResidualPartitionOrder),
65
        InstanceMethod(
21✔
66
          "setRiceParameterSearchDist",
67
          &StreamEncoderBuilder::setRiceParameterSearchDist),
68
        InstanceMethod("setTotalSamplesEstimate", &StreamEncoderBuilder::setTotalSamplesEstimate),
21✔
69
        InstanceMethod("setMetadata", &StreamEncoderBuilder::setMetadata),
21✔
70
        InstanceMethod("setApodization", &StreamEncoderBuilder::setApodization),
21✔
71
        InstanceMethod("setLimitMinBitrate", &StreamEncoderBuilder::setLimitMinBitrate),
21✔
72
        InstanceMethod("setNumThreads", &StreamEncoderBuilder::setNumThreads),
21✔
73

74
        InstanceMethod("buildWithStream", &StreamEncoderBuilder::buildWithStream),
21✔
75
        InstanceMethod("buildWithOggStream", &StreamEncoderBuilder::buildWithOggStream),
21✔
76
        InstanceMethod("buildWithFile", &StreamEncoderBuilder::buildWithFile),
21✔
77
        InstanceMethod("buildWithOggFile", &StreamEncoderBuilder::buildWithOggFile),
21✔
78

79
        InstanceMethod("buildWithStreamAsync", &StreamEncoderBuilder::buildWithStreamAsync),
21✔
80
        InstanceMethod("buildWithOggStreamAsync", &StreamEncoderBuilder::buildWithOggStreamAsync),
21✔
81
        InstanceMethod("buildWithFileAsync", &StreamEncoderBuilder::buildWithFileAsync),
21✔
82
        InstanceMethod("buildWithOggFileAsync", &StreamEncoderBuilder::buildWithOggFileAsync),
21✔
83
      });
84

85
    constructor.Freeze();
21✔
86
    addon.encoderBuilderConstructor = Persistent(constructor);
21✔
87

88
    return scope.Escape(constructor).As<Function>();
42✔
89
  }
21✔
90

91
  StreamEncoderBuilder::StreamEncoderBuilder(const CallbackInfo& info):
43✔
92
      ObjectWrap<StreamEncoderBuilder>(info) {
43✔
93
    enc = FLAC__stream_encoder_new();
43✔
94
    if (enc == nullptr) {
43✔
95
      throw Error::New(info.Env(), "Could not allocate memory");
×
96
    }
97

98
    info.This().As<Object>().Set("__metadataArrayRef", info.Env().Null());
43✔
99
  }
43✔
100

UNCOV
101
  StreamEncoderBuilder::~StreamEncoderBuilder() {
×
UNCOV
102
    if (enc != nullptr) {
×
UNCOV
103
      FLAC__stream_encoder_delete(enc);
×
104
    }
UNCOV
105
  }
×
106

107
  // -- getters --
108

109
  Napi::Value StreamEncoderBuilder::getVerify(const CallbackInfo& info) {
1✔
110
    checkIfBuilt(info.Env());
1✔
111
    auto verify = FLAC__stream_encoder_get_verify(enc);
1✔
112
    return booleanToJs(info.Env(), verify);
1✔
113
  }
114

115
  Napi::Value StreamEncoderBuilder::getStreamableSubset(const CallbackInfo& info) {
×
116
    checkIfBuilt(info.Env());
×
117
    auto streamableSubset = FLAC__stream_encoder_get_streamable_subset(enc);
×
118
    return booleanToJs(info.Env(), streamableSubset);
×
119
  }
120

121
  Napi::Value StreamEncoderBuilder::getChannels(const CallbackInfo& info) {
1✔
122
    checkIfBuilt(info.Env());
1✔
123
    auto channels = FLAC__stream_encoder_get_channels(enc);
1✔
124
    return numberToJs(info.Env(), channels);
1✔
125
  }
126

127
  Napi::Value StreamEncoderBuilder::getBitsPerSample(const CallbackInfo& info) {
1✔
128
    checkIfBuilt(info.Env());
1✔
129
    auto bitsPerSample = FLAC__stream_encoder_get_bits_per_sample(enc);
1✔
130
    return numberToJs(info.Env(), bitsPerSample);
1✔
131
  }
132

133
  Napi::Value StreamEncoderBuilder::getSampleRate(const CallbackInfo& info) {
1✔
134
    checkIfBuilt(info.Env());
1✔
135
    auto sampleRate = FLAC__stream_encoder_get_sample_rate(enc);
1✔
136
    return numberToJs(info.Env(), sampleRate);
1✔
137
  }
138

139
  Napi::Value StreamEncoderBuilder::getBlocksize(const CallbackInfo& info) {
1✔
140
    checkIfBuilt(info.Env());
1✔
141
    auto blocksize = FLAC__stream_encoder_get_blocksize(enc);
1✔
142
    return numberToJs(info.Env(), blocksize);
1✔
143
  }
144

145
  Napi::Value StreamEncoderBuilder::getDoMidSideStereo(const CallbackInfo& info) {
1✔
146
    auto doMidStereo = FLAC__stream_encoder_get_do_mid_side_stereo(enc);
1✔
147
    return booleanToJs(info.Env(), doMidStereo);
1✔
148
  }
149

150
  Napi::Value StreamEncoderBuilder::getLooseMidSideStereo(const CallbackInfo& info) {
1✔
151
    checkIfBuilt(info.Env());
1✔
152
    auto looseMidStereo = FLAC__stream_encoder_get_loose_mid_side_stereo(enc);
1✔
153
    return booleanToJs(info.Env(), looseMidStereo);
1✔
154
  }
155

156
  Napi::Value StreamEncoderBuilder::getMaxLpcOrder(const CallbackInfo& info) {
1✔
157
    checkIfBuilt(info.Env());
1✔
158
    auto maxLpcOrder = FLAC__stream_encoder_get_max_lpc_order(enc);
1✔
159
    return numberToJs(info.Env(), maxLpcOrder);
1✔
160
  }
161

162
  Napi::Value StreamEncoderBuilder::getQlpCoeffPrecision(const CallbackInfo& info) {
1✔
163
    checkIfBuilt(info.Env());
1✔
164
    auto qlpCoeffPrecision = FLAC__stream_encoder_get_qlp_coeff_precision(enc);
1✔
165
    return numberToJs(info.Env(), qlpCoeffPrecision);
1✔
166
  }
167

168
  Napi::Value StreamEncoderBuilder::getDoQlpCoeffPrecSearch(const CallbackInfo& info) {
1✔
169
    checkIfBuilt(info.Env());
1✔
170
    auto doQlpCoeffPrecSearch = FLAC__stream_encoder_get_do_qlp_coeff_prec_search(enc);
1✔
171
    return booleanToJs(info.Env(), doQlpCoeffPrecSearch);
1✔
172
  }
173

174
  Napi::Value StreamEncoderBuilder::getDoEscapeCoding(const CallbackInfo& info) {
1✔
175
    checkIfBuilt(info.Env());
1✔
176
    auto doEscapeCoding = FLAC__stream_encoder_get_do_escape_coding(enc);
1✔
177
    return booleanToJs(info.Env(), doEscapeCoding);
1✔
178
  }
179

180
  Napi::Value StreamEncoderBuilder::getDoExhaustiveModelSearch(const CallbackInfo& info) {
1✔
181
    checkIfBuilt(info.Env());
1✔
182
    auto doExhaustiveModelSearch = FLAC__stream_encoder_get_do_exhaustive_model_search(enc);
1✔
183
    return booleanToJs(info.Env(), doExhaustiveModelSearch);
1✔
184
  }
185

186
  Napi::Value StreamEncoderBuilder::getMinResidualPartitionOrder(const CallbackInfo& info) {
1✔
187
    checkIfBuilt(info.Env());
1✔
188
    auto minResidualPartitionOrder = FLAC__stream_encoder_get_min_residual_partition_order(enc);
1✔
189
    return numberToJs(info.Env(), minResidualPartitionOrder);
1✔
190
  }
191

192
  Napi::Value StreamEncoderBuilder::getMaxResidualPartitionOrder(const CallbackInfo& info) {
1✔
193
    checkIfBuilt(info.Env());
1✔
194
    auto maxResidualPartitionOrder = FLAC__stream_encoder_get_max_residual_partition_order(enc);
1✔
195
    return numberToJs(info.Env(), maxResidualPartitionOrder);
1✔
196
  }
197

198
  Napi::Value StreamEncoderBuilder::getRiceParameterSearchDist(const CallbackInfo& info) {
1✔
199
    checkIfBuilt(info.Env());
1✔
200
    auto riceParameterSearchDist = FLAC__stream_encoder_get_rice_parameter_search_dist(enc);
1✔
201
    return numberToJs(info.Env(), riceParameterSearchDist);
1✔
202
  }
203

204
  Napi::Value StreamEncoderBuilder::getLimitMinBitrate(const CallbackInfo& info) {
1✔
205
    checkIfBuilt(info.Env());
1✔
206
#if FLAC_API_VERSION_CURRENT >= 12
207
    auto value = FLAC__stream_encoder_get_limit_min_bitrate(enc);
1✔
208
    return booleanToJs(info.Env(), value);
1✔
209
#else
210
    return throwUnsupportedVersion(info.Env());
211
#endif
212
  }
213

214
  Napi::Value StreamEncoderBuilder::getTotalSamplesEstimate(const CallbackInfo& info) {
1✔
215
    auto totalSamplesEstimate = FLAC__stream_encoder_get_total_samples_estimate(enc);
1✔
216
    return numberToJs(info.Env(), totalSamplesEstimate);
1✔
217
  }
218

219
  Napi::Value StreamEncoderBuilder::getNumThreads(const CallbackInfo& info) {
1✔
220
    checkIfBuilt(info.Env());
1✔
221
#if FLAC_API_VERSION_CURRENT >= 14
222
    auto value = FLAC__stream_encoder_get_num_threads(enc);
1✔
223
    return numberToJs(info.Env(), value);
1✔
224
#else
225
    return throwUnsupportedVersion(info.Env());
226
#endif
227
  }
228

229
  Napi::Value StreamEncoderBuilder::getState(const CallbackInfo& info) {
1✔
230
    checkIfBuilt(info.Env());
1✔
231
    auto state = FLAC__stream_encoder_get_state(enc);
1✔
232
    return numberToJs(info.Env(), state);
1✔
233
  }
234

235
  // -- setters --
236

237
  Napi::Value StreamEncoderBuilder::setVerify(const CallbackInfo& info) {
2✔
238
    checkIfBuilt(info.Env());
2✔
239

240
    auto verify = booleanFromJs<FLAC__bool>(info[0]);
2✔
241
    FLAC__stream_encoder_set_verify(enc, verify);
2✔
242
    return info.This();
2✔
243
  }
244

245
  Napi::Value StreamEncoderBuilder::setOggSerialNumber(const CallbackInfo& info) {
2✔
246
    checkIfBuilt(info.Env());
2✔
247

248
    auto oggSerialNumber = numberFromJs<long>(info[0]);
2✔
249
    FLAC__stream_encoder_set_ogg_serial_number(enc, oggSerialNumber);
2✔
250
    return info.This();
2✔
251
  }
252

253
  Napi::Value StreamEncoderBuilder::setStreamableSubset(const CallbackInfo& info) {
×
254
    checkIfBuilt(info.Env());
×
255

256
    auto streamableSubset = booleanFromJs<FLAC__bool>(info[0]);
×
257
    FLAC__stream_encoder_set_streamable_subset(enc, streamableSubset);
×
258
    return info.This();
×
259
  }
260

261
  Napi::Value StreamEncoderBuilder::setChannels(const CallbackInfo& info) {
69✔
262
    checkIfBuilt(info.Env());
69✔
263

264
    auto channels = numberFromJs<unsigned>(info[0]);
69✔
265
    FLAC__stream_encoder_set_channels(enc, channels);
69✔
266
    return info.This();
69✔
267
  }
268

269
  Napi::Value StreamEncoderBuilder::setBitsPerSample(const CallbackInfo& info) {
69✔
270
    checkIfBuilt(info.Env());
69✔
271

272
    auto bitsPerSample = numberFromJs<unsigned>(info[0]);
69✔
273
    FLAC__stream_encoder_set_bits_per_sample(enc, bitsPerSample);
69✔
274
    return info.This();
69✔
275
  }
276

277
  Napi::Value StreamEncoderBuilder::setSampleRate(const CallbackInfo& info) {
69✔
278
    checkIfBuilt(info.Env());
69✔
279

280
    auto sampleRate = numberFromJs<unsigned>(info[0]);
69✔
281
    FLAC__stream_encoder_set_sample_rate(enc, sampleRate);
69✔
282
    return info.This();
69✔
283
  }
284

285
  Napi::Value StreamEncoderBuilder::setCompressionLevel(const CallbackInfo& info) {
30✔
286
    checkIfBuilt(info.Env());
30✔
287

288
    auto compressionLevel = numberFromJs<unsigned>(info[0]);
30✔
289
    FLAC__stream_encoder_set_compression_level(enc, compressionLevel);
30✔
290
    return info.This();
30✔
291
  }
292

293
  Napi::Value StreamEncoderBuilder::setBlocksize(const CallbackInfo& info) {
1✔
294
    checkIfBuilt(info.Env());
1✔
295

296
    auto blocksize = numberFromJs<unsigned>(info[0]);
1✔
297
    FLAC__stream_encoder_set_blocksize(enc, blocksize);
1✔
298
    return info.This();
1✔
299
  }
300

301
  Napi::Value StreamEncoderBuilder::setDoMidSideStereo(const CallbackInfo& info) {
29✔
302
    checkIfBuilt(info.Env());
29✔
303

304
    auto doMidStereo = booleanFromJs<FLAC__bool>(info[0]);
29✔
305
    FLAC__stream_encoder_set_do_mid_side_stereo(enc, doMidStereo);
29✔
306
    return info.This();
29✔
307
  }
308

309
  Napi::Value StreamEncoderBuilder::setLooseMidSideStereo(const CallbackInfo& info) {
29✔
310
    checkIfBuilt(info.Env());
29✔
311

312
    auto looseMidStereo = booleanFromJs<FLAC__bool>(info[0]);
29✔
313
    FLAC__stream_encoder_set_loose_mid_side_stereo(enc, looseMidStereo);
29✔
314
    return info.This();
29✔
315
  }
316

317
  Napi::Value StreamEncoderBuilder::setMaxLpcOrder(const CallbackInfo& info) {
1✔
318
    checkIfBuilt(info.Env());
1✔
319

320
    auto maxLpcOrder = numberFromJs<unsigned>(info[0]);
1✔
321
    FLAC__stream_encoder_set_max_lpc_order(enc, maxLpcOrder);
1✔
322
    return info.This();
1✔
323
  }
324

325
  Napi::Value StreamEncoderBuilder::setQlpCoeffPrecision(const CallbackInfo& info) {
1✔
326
    checkIfBuilt(info.Env());
1✔
327

328
    auto qlpCoeffPrecision = numberFromJs<unsigned>(info[0]);
1✔
329
    FLAC__stream_encoder_set_qlp_coeff_precision(enc, qlpCoeffPrecision);
1✔
330
    return info.This();
1✔
331
  }
332

333
  Napi::Value StreamEncoderBuilder::setDoQlpCoeffPrecSearch(const CallbackInfo& info) {
1✔
334
    checkIfBuilt(info.Env());
1✔
335

336
    auto doQlpCoeffPrecSearch = booleanFromJs<FLAC__bool>(info[0]);
1✔
337
    FLAC__stream_encoder_set_do_qlp_coeff_prec_search(enc, doQlpCoeffPrecSearch);
1✔
338
    return info.This();
1✔
339
  }
340

341
  Napi::Value StreamEncoderBuilder::setDoEscapeCoding(const CallbackInfo& info) {
×
342
    checkIfBuilt(info.Env());
×
343

344
    auto doEscapeCoding = booleanFromJs<FLAC__bool>(info[0]);
×
345
    FLAC__stream_encoder_set_do_escape_coding(enc, doEscapeCoding);
×
346
    return info.This();
×
347
  }
348

349
  Napi::Value StreamEncoderBuilder::setDoExhaustiveModelSearch(const CallbackInfo& info) {
1✔
350
    checkIfBuilt(info.Env());
1✔
351

352
    auto doExhaustiveModelSearch = booleanFromJs<FLAC__bool>(info[0]);
1✔
353
    FLAC__stream_encoder_set_do_exhaustive_model_search(enc, doExhaustiveModelSearch);
1✔
354
    return info.This();
1✔
355
  }
356

357
  Napi::Value StreamEncoderBuilder::setMinResidualPartitionOrder(const CallbackInfo& info) {
1✔
358
    checkIfBuilt(info.Env());
1✔
359

360
    auto minResidualPartitionOrder = numberFromJs<unsigned>(info[0]);
1✔
361
    FLAC__stream_encoder_set_min_residual_partition_order(enc, minResidualPartitionOrder);
1✔
362
    return info.This();
1✔
363
  }
364

365
  Napi::Value StreamEncoderBuilder::setMaxResidualPartitionOrder(const CallbackInfo& info) {
1✔
366
    checkIfBuilt(info.Env());
1✔
367

368
    auto maxResidualPartitionOrder = numberFromJs<unsigned>(info[0]);
1✔
369
    FLAC__stream_encoder_set_max_residual_partition_order(enc, maxResidualPartitionOrder);
1✔
370
    return info.This();
1✔
371
  }
372

373
  Napi::Value StreamEncoderBuilder::setRiceParameterSearchDist(const CallbackInfo& info) {
×
374
    checkIfBuilt(info.Env());
×
375

376
    auto riceParameterSearchDist = numberFromJs<unsigned>(info[0]);
×
377
    FLAC__stream_encoder_set_rice_parameter_search_dist(enc, riceParameterSearchDist);
×
378
    return info.This();
×
379
  }
380

381
  Napi::Value StreamEncoderBuilder::setTotalSamplesEstimate(const CallbackInfo& info) {
4✔
382
    checkIfBuilt(info.Env());
4✔
383

384
    auto totalSamplesEstimate = numberFromJs<uint64_t>(info[0]);
4✔
385
    FLAC__stream_encoder_set_total_samples_estimate(enc, totalSamplesEstimate);
4✔
386
    return info.This();
4✔
387
  }
388

389
  Napi::Value StreamEncoderBuilder::setMetadata(const CallbackInfo& info) {
2✔
390
    checkIfBuilt(info.Env());
2✔
391

392
    std::vector<FLAC__StreamMetadata*> metadatas =
393
      arrayFromJs<FLAC__StreamMetadata*>(info[0], Metadata::fromJs);
2✔
394

395
    auto ret = FLAC__stream_encoder_set_metadata(enc, metadatas.data(), metadatas.size());
2✔
396
    if (!ret) {
2✔
397
      throw Error::New(info.Env(), "Could not set the metadata");
×
398
    }
399

400
    // Save all objects inside this to hold the references until the object is destroyed
401
    info.This().As<Napi::Object>().Set("__metadataArrayRef", info[0]);
2✔
402

403
    return info.This();
4✔
404
  }
2✔
405

406
  Napi::Value StreamEncoderBuilder::setApodization(const CallbackInfo& info) {
1✔
407
    checkIfBuilt(info.Env());
1✔
408

409
    auto apodization = stringFromJs(info[0]);
1✔
410
    FLAC__stream_encoder_set_apodization(enc, apodization.c_str());
1✔
411
    return info.This();
2✔
412
  }
1✔
413

414
  Napi::Value StreamEncoderBuilder::setLimitMinBitrate(const CallbackInfo& info) {
2✔
415
    checkIfBuilt(info.Env());
2✔
416

417
#if FLAC_API_VERSION_CURRENT >= 12
418
    auto value = booleanFromJs<FLAC__bool>(info[0]);
2✔
419
    FLAC__stream_encoder_set_limit_min_bitrate(enc, value);
2✔
420
    return info.This();
2✔
421
#else
422
    return throwUnsupportedVersion(info.Env());
423
#endif
424
  }
425

426
  Napi::Value StreamEncoderBuilder::setNumThreads(const CallbackInfo& info) {
3✔
427
    checkIfBuilt(info.Env());
3✔
428

429
#if FLAC_API_VERSION_CURRENT >= 14
430
    auto value = numberFromJs<FLAC__uint32>(info[0]);
3✔
431
    auto ret = FLAC__stream_encoder_set_num_threads(enc, value);
3✔
432
    if (ret == FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK) {
3✔
433
      return info.This();
3✔
434
    }
435

436
    const char* message = nullptr;
×
437
    if (ret == FLAC__STREAM_ENCODER_SET_NUM_THREADS_NOT_COMPILED_WITH_MULTITHREADING_ENABLED) {
×
438
      message = "Library was compiled without multithreading support";
×
439
    } else if (ret == FLAC__STREAM_ENCODER_SET_NUM_THREADS_TOO_MANY_THREADS) {
×
440
      message = "Too many threads, reduce the number of them";
×
441
    } else {
442
      message = "Unknown error";
×
443
    }
444

445
    auto error = Napi::Error::New(info.Env(), message);
×
446
    error.ThrowAsJavaScriptException();
×
447
    return info.Env().Undefined();
×
448
#else
449
    return throwUnsupportedVersion(info.Env());
450
#endif
451
  }
×
452

453
  // -- builder methods --
454

455
  Napi::Value StreamEncoderBuilder::buildWithStream(const CallbackInfo& info) {
2✔
456
    EscapableHandleScope scope(info.Env());
2✔
457
    checkIfBuilt(info.Env());
2✔
458

459
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Sync);
2✔
460
    maybeFunctionIntoRef(ctx->writeCbk, info[0]);
2✔
461
    maybeFunctionIntoRef(ctx->seekCbk, info[1]);
2✔
462
    maybeFunctionIntoRef(ctx->tellCbk, info[2]);
2✔
463
    maybeFunctionIntoRef(ctx->metadataCbk, info[3]);
2✔
464

465
    auto ret = FLAC__stream_encoder_init_stream(
8✔
466
      enc,
467
      ctx->writeCbk.IsEmpty() ? nullptr : StreamEncoder::writeCallback,
2✔
468
      ctx->seekCbk.IsEmpty() ? nullptr : StreamEncoder::seekCallback,
2✔
469
      ctx->tellCbk.IsEmpty() ? nullptr : StreamEncoder::tellCallback,
2✔
470
      ctx->metadataCbk.IsEmpty() ? nullptr : StreamEncoder::metadataCallback,
2✔
471
      ctx.get());
2✔
472

473
    checkInitStatus(info.Env(), ret);
2✔
474
    return scope.Escape(createEncoder(info.Env(), info.This(), ctx));
4✔
475
  }
2✔
476

477
  Napi::Value StreamEncoderBuilder::buildWithOggStream(const CallbackInfo& info) {
1✔
478
    EscapableHandleScope scope(info.Env());
1✔
479
    checkIfBuilt(info.Env());
1✔
480

481
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Sync);
1✔
482
    maybeFunctionIntoRef(ctx->readCbk, info[0]);
1✔
483
    maybeFunctionIntoRef(ctx->writeCbk, info[1]);
1✔
484
    maybeFunctionIntoRef(ctx->seekCbk, info[2]);
1✔
485
    maybeFunctionIntoRef(ctx->tellCbk, info[3]);
1✔
486
    maybeFunctionIntoRef(ctx->metadataCbk, info[4]);
1✔
487

488
    auto ret = FLAC__stream_encoder_init_ogg_stream(
5✔
489
      enc,
490
      ctx->readCbk.IsEmpty() ? nullptr : StreamEncoder::readCallback,
1✔
491
      ctx->writeCbk.IsEmpty() ? nullptr : StreamEncoder::writeCallback,
1✔
492
      ctx->seekCbk.IsEmpty() ? nullptr : StreamEncoder::seekCallback,
1✔
493
      ctx->tellCbk.IsEmpty() ? nullptr : StreamEncoder::tellCallback,
1✔
494
      ctx->metadataCbk.IsEmpty() ? nullptr : StreamEncoder::metadataCallback,
1✔
495
      ctx.get());
1✔
496

497
    checkInitStatus(info.Env(), ret);
1✔
498
    return scope.Escape(createEncoder(info.Env(), info.This(), ctx));
2✔
499
  }
1✔
500

501
  Napi::Value StreamEncoderBuilder::buildWithFile(const CallbackInfo& info) {
10✔
502
    EscapableHandleScope scope(info.Env());
10✔
503
    checkIfBuilt(info.Env());
10✔
504

505
    auto path = stringFromJs(info[0]);
10✔
506
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Sync);
10✔
507
    maybeFunctionIntoRef(ctx->progressCbk, info[1]);
10✔
508

509
    auto ret = FLAC__stream_encoder_init_file(
10✔
510
      enc,
511
      path.c_str(),
512
      ctx->progressCbk.IsEmpty() ? nullptr : StreamEncoder::progressCallback,
10✔
513
      ctx.get());
10✔
514

515
    checkInitStatus(info.Env(), ret);
10✔
516
    return scope.Escape(createEncoder(info.Env(), info.This(), ctx));
20✔
517
  }
10✔
518

519
  Napi::Value StreamEncoderBuilder::buildWithOggFile(const CallbackInfo& info) {
1✔
520
    EscapableHandleScope scope(info.Env());
1✔
521
    checkIfBuilt(info.Env());
1✔
522

523
    auto path = stringFromJs(info[0]);
1✔
524
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Sync);
1✔
525
    maybeFunctionIntoRef(ctx->progressCbk, info[1]);
1✔
526

527
    auto ret = FLAC__stream_encoder_init_ogg_file(
1✔
528
      enc,
529
      path.c_str(),
530
      ctx->progressCbk.IsEmpty() ? nullptr : StreamEncoder::progressCallback,
1✔
531
      ctx.get());
1✔
532

533
    checkInitStatus(info.Env(), ret);
1✔
534
    return scope.Escape(createEncoder(info.Env(), info.This(), ctx));
2✔
535
  }
1✔
536

537
  // -- async builders --
538

539
  Napi::Value StreamEncoderBuilder::buildWithStreamAsync(const CallbackInfo& info) {
7✔
540
    EscapableHandleScope scope(info.Env());
7✔
541
    checkIfBuilt(info.Env());
7✔
542

543
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Async);
7✔
544
    maybeFunctionIntoRef(ctx->writeCbk, info[0]);
7✔
545
    maybeFunctionIntoRef(ctx->seekCbk, info[1]);
7✔
546
    maybeFunctionIntoRef(ctx->tellCbk, info[2]);
7✔
547
    maybeFunctionIntoRef(ctx->metadataCbk, info[3]);
7✔
548

549
    // why no mutex? JS runs in a single thread, and the check has already been done
550
    AsyncEncoderWork* work = AsyncEncoderWork::forInitStream({info.This()}, ctx, *this);
7✔
551
    workInProgress = true;
7✔
552
    ctx->workInProgress = true;
7✔
553
    work->Queue();
7✔
554
    return scope.Escape(work->getPromise());
14✔
555
  }
7✔
556

557
  Napi::Value StreamEncoderBuilder::buildWithOggStreamAsync(const CallbackInfo& info) {
5✔
558
    EscapableHandleScope scope(info.Env());
5✔
559
    checkIfBuilt(info.Env());
5✔
560

561
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Async);
5✔
562
    maybeFunctionIntoRef(ctx->readCbk, info[0]);
5✔
563
    maybeFunctionIntoRef(ctx->writeCbk, info[1]);
5✔
564
    maybeFunctionIntoRef(ctx->seekCbk, info[2]);
5✔
565
    maybeFunctionIntoRef(ctx->tellCbk, info[3]);
5✔
566
    maybeFunctionIntoRef(ctx->metadataCbk, info[4]);
5✔
567

568
    AsyncEncoderWork* work = AsyncEncoderWork::forInitOggStream({info.This()}, ctx, *this);
5✔
569
    workInProgress = true;
5✔
570
    ctx->workInProgress = true;
5✔
571
    work->Queue();
5✔
572
    return scope.Escape(work->getPromise());
10✔
573
  }
5✔
574

575
  Napi::Value StreamEncoderBuilder::buildWithFileAsync(const CallbackInfo& info) {
11✔
576
    EscapableHandleScope scope(info.Env());
11✔
577
    checkIfBuilt(info.Env());
11✔
578

579
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Async);
11✔
580
    maybeFunctionIntoRef(ctx->progressCbk, info[1]);
11✔
581

582
    auto path = stringFromJs(info[0]);
11✔
583
    AsyncEncoderWork* work = AsyncEncoderWork::forInitFile({info.This()}, path, ctx, *this);
11✔
584
    workInProgress = true;
11✔
585
    ctx->workInProgress = true;
11✔
586
    work->Queue();
11✔
587
    return scope.Escape(work->getPromise());
22✔
588
  }
11✔
589

590
  Napi::Value StreamEncoderBuilder::buildWithOggFileAsync(const CallbackInfo& info) {
5✔
591
    EscapableHandleScope scope(info.Env());
5✔
592
    checkIfBuilt(info.Env());
5✔
593

594
    auto ctx = std::make_shared<EncoderWorkContext>(enc, EncoderWorkContext::ExecutionMode::Async);
5✔
595
    maybeFunctionIntoRef(ctx->progressCbk, info[1]);
5✔
596

597
    auto path = stringFromJs(info[0]);
5✔
598
    AsyncEncoderWork* work = AsyncEncoderWork::forInitOggFile({info.This()}, path, ctx, *this);
5✔
599
    workInProgress = true;
5✔
600
    ctx->workInProgress = true;
5✔
601
    work->Queue();
5✔
602
    return scope.Escape(work->getPromise());
10✔
603
  }
5✔
604

605
  // -- helpers --
606

607
  Napi::Value StreamEncoderBuilder::createEncoder(
41✔
608
    Napi::Env env,
609
    Napi::Value self,
610
    std::shared_ptr<EncoderWorkContext> ctx) {
611
    EscapableHandleScope scope(env);
41✔
612
    auto addon = env.GetInstanceData<FlacAddon>();
41✔
613

614
    auto metadataArrayReference = self.As<Napi::Object>().Get("__metadataArrayRef");
41✔
615
    auto encoderJs = addon->encoderConstructor.New({self, metadataArrayReference});
41✔
616

617
    auto encoder = StreamEncoder::Unwrap(encoderJs);
41✔
618
    encoder->enc = enc;
41✔
619
    encoder->ctx = ctx;
41✔
620

621
    // encoder is built, cannot be used in builder
622
    enc = nullptr;
41✔
623
    workInProgress = false;
41✔
624

625
    return scope.Escape(encoderJs);
82✔
626
  }
41✔
627

628
  void StreamEncoderBuilder::checkIfBuilt(Napi::Env env) {
377✔
629
    // if null, means one of the buildWith* methods have been called (see above)
630
    if (enc == nullptr) {
377✔
631
      throw Error::New(env, "Encoder has been built - cannot call any method");
×
632
    }
633

634
    // if workInProgress is true, then fail too
635
    if (workInProgress.load()) {
377✔
636
      throw Error::New(env, "There is a pending Promise running, wait until is resolved");
×
637
    }
638
  }
377✔
639

640
  void StreamEncoderBuilder::checkInitStatus(Napi::Env env, FLAC__StreamEncoderInitStatus status) {
42✔
641
    // set work to false, because when this method is called, no more background work is being done
642
    workInProgress = false;
42✔
643

644
    if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
42✔
645
      const char* statusString;
646
      // remove prefix FLAC__STREAM_ENCODER_INIT_STATUS_
647
      statusString = FLAC__StreamEncoderInitStatusString[status] + 33;
1✔
648

649
      auto error = Error::New(env, "Encoder initialization failed: "s + statusString);
1✔
650
      error.Set("status", numberToJs(env, status));
1✔
651
      error.Set("statusString", String::New(env, statusString));
1✔
652
      throw error;
1✔
653
    }
1✔
654
  }
41✔
655

656
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc