forked from xdissent/node-pcm-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
unzipper.cc
107 lines (82 loc) · 3.39 KB
/
unzipper.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "unzipper.h"
using namespace pcmutils;
void Unzipper::Init(Handle<Object> exports) {
Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(String::NewSymbol("Unzipper"));
NODE_SET_PROTOTYPE_METHOD(tpl, "unzip", Unzip);
Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
exports->Set(String::NewSymbol("Unzipper"), constructor);
}
Handle<Value> Unzipper::New(const Arguments& args) {
HandleScope scope;
if (!args.IsConstructCall())
return ThrowException(Exception::TypeError(String::New("Use the new operator")));
REQUIRE_ARGUMENTS(2);
Unzipper* unz = new Unzipper();
unz->Wrap(args.This());
unz->channels = args[0]->Int32Value();
unz->alignment = args[1]->Int32Value();
unz->frameAlignment = unz->channels * unz->alignment;
unz->unzipping = false;
unz->channelBuffers = Persistent<Array>::New(Array::New(unz->channels));
for (int i = 0; i < unz->channels; i++) {
size_t blen = unz->alignment * UNZ_BUFFER_FRAMES;
Buffer* b = Buffer::New(blen);
unz->channelBuffers->Set(i, b->handle_);
}
return args.This();
}
Handle<Value> Unzipper::Unzip(const Arguments& args) {
HandleScope scope;
REQUIRE_ARGUMENTS(2);
REQUIRE_ARGUMENT_FUNCTION(1, callback);
Unzipper* unz = ObjectWrap::Unwrap<Unzipper>(args.Holder());
COND_ERR_CALL(unz->unzipping, callback, "Still unzipping");
UnzipBaton* baton = new UnzipBaton(unz, callback, args[0]->ToObject());
unz->unzipping = true;
BeginUnzip(baton);
return scope.Close(args.Holder());
}
void Unzipper::BeginUnzip(Baton* baton) {
uv_queue_work(uv_default_loop(), &baton->request, DoUnzip, (uv_after_work_cb)AfterUnzip);
}
void Unzipper::DoUnzip(uv_work_t* req) {
UnzipBaton* baton = static_cast<UnzipBaton*>(req->data);
Unzipper* unz = baton->unz;
int sample = 0;
int limitFrames = baton->unzippedFrames + UNZ_BUFFER_FRAMES;
for (; baton->unzippedFrames < limitFrames && baton->unzippedFrames < baton->totalFrames; baton->unzippedFrames++) {
for (int channel = 0; channel < unz->channels; channel++) {
memcpy(
baton->channelData[channel] + (sample * unz->alignment),
baton->chunkData + (baton->unzippedFrames * unz->frameAlignment) + (channel * unz->alignment),
unz->alignment
);
}
sample++;
}
}
void Unzipper::AfterUnzip(uv_work_t* req) {
HandleScope scope;
UnzipBaton* baton = static_cast<UnzipBaton*>(req->data);
Unzipper* unz = baton->unz;
// Copy buffers because we may clobber them soon.
Local<Array> channelBuffersCopy = Local<Array>::New(Array::New(unz->channels));
for (int i = 0; i < unz->channels; i++) {
// Yes, copy is ok
size_t blen = unz->alignment * UNZ_BUFFER_FRAMES;
Buffer* b = Buffer::New(Buffer::Data(unz->channelBuffers->Get(i)->ToObject()), blen);
channelBuffersCopy->Set(i, b->handle_);
}
if (baton->unzippedFrames < baton->totalFrames) {
Local<Value> argv[3] = { Local<Value>::New(Null()), Local<Value>::New(channelBuffersCopy), Local<Value>::New(Boolean::New(false)) };
TRY_CATCH_CALL(unz->handle_, baton->callback, 3, argv);
BeginUnzip(baton);
return;
}
unz->unzipping = false;
Local<Value> argv[3] = { Local<Value>::New(Null()), Local<Value>::New(channelBuffersCopy), Local<Value>::New(Boolean::New(true)) };
TRY_CATCH_CALL(unz->handle_, baton->callback, 3, argv);
delete baton;
}