Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatible with node 0.12 #38

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions examples/play_ffmpeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ var airtunes = require('../lib/'),
spawn = require('child_process').spawn,
argv = require('optimist')
.usage('Usage: $0 --host [host] --port [num] --ffmpeg [path] --file [path] --volume [num] --password [string]')
.default('port', 5000)
.default('port', 5002)
.default('volume', 50)
.default('ffmpeg', '/usr/local/bin/ffmpeg')
.default('file', './sample.mp3')
.default('file', './wakeup.mp3')
.demand(['host'])
.argv;

Expand Down
Binary file removed examples/sample.mp3
Binary file not shown.
Binary file added examples/wakeup.mp3
Binary file not shown.
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ AirTunes.prototype.end = function() {
};

module.exports = new AirTunes();
module.exports.AirTunes = AirTunes;
20 changes: 11 additions & 9 deletions lib/rtsp.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ Client.prototype.startHandshake = function(udpServers, host, port) {
var self = this;

this.startTimeout();

this.controlPort = udpServers.control.port;
this.timingPort = udpServers.timing.port;


this.socket = net.connect(port, host, function() {
self.clearTimeout();
self.sendNextRequest();
Expand All @@ -68,16 +68,18 @@ Client.prototype.startHandshake = function(udpServers, host, port) {
* I assume that all responses have empty bodies.
*/
data = data.toString();
var endIndex = data.indexOf('\r\n\r\n');

if(endIndex < 0) {
blob += data;
blob += data;
var endIndex = blob.indexOf('\r\n\r\n');

if (endIndex < 0) {
return;
}

endIndex += 4; // the end of \r\n\r\n
endIndex += 4;

blob = blob.substring(0, endIndex);

blob += data.substring(0, endIndex);
self.processData(blob);

blob = data.substring(endIndex);
Expand Down Expand Up @@ -229,7 +231,7 @@ function parseResponse(blob) {

var headers = {};
lines.slice(1).forEach(function(line) {
var res = /([^:]+): (.*)/.exec(line);
var res = /([^:]+):\s*(.*)/.exec(line);

if(!res)
return;
Expand Down
4 changes: 3 additions & 1 deletion src/bindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ void InitCoreAudio(Handle<Object>);
#endif

void Initialize(Handle<Object> target) {
HandleScope scope;

Isolate* isolate = v8::Isolate::GetCurrent();
HandleScope scope(isolate);

InitCodec(target);
#ifdef __APPLE__
Expand Down
43 changes: 20 additions & 23 deletions src/codec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,12 @@ void FillOutputAudioFormat(AudioFormatDescription *format) {
format->mReserved = 0;
}

void encoder_weak_callback (Persistent<Value> wrapper, void *arg) {
HandleScope scope;
ALACEncoder *encoder = (ALACEncoder *)arg;
delete encoder;
wrapper.Dispose();
}

// Creates a new encoder instance and wraps it in a JavaScript object.
// This encoder is freed when the object is released by the GC.
Handle<Value> NewEncoder(const Arguments& args) {
HandleScope scope;
//Handle<Value> NewEncoder(const Arguments& args) {
void NewEncoder(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = Isolate::GetCurrent();
EscapableHandleScope scope(isolate);

AudioFormatDescription outputFormat;
FillOutputAudioFormat(&outputFormat);
Expand All @@ -75,25 +70,26 @@ Handle<Value> NewEncoder(const Arguments& args) {
encoder->SetFrameSize(kFramesPerPacket);
encoder->InitializeEncoder(outputFormat);

Persistent<ObjectTemplate> encoderClass = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
Local<ObjectTemplate> encoderClass = ObjectTemplate::New(isolate);
encoderClass->SetInternalFieldCount(1);
Persistent<Object> o = Persistent<Object>::New(encoderClass->NewInstance());
o->SetPointerInInternalField(0, encoder);
o.MakeWeak(encoder, encoder_weak_callback);

return scope.Close(o);
Local<Object> obj = encoderClass->NewInstance();
obj->SetAlignedPointerInInternalField(0, encoder);

args.GetReturnValue().Set(obj);
}

Handle<Value> EncodeALAC(const Arguments& args) {
HandleScope scope;
void EncodeALAC(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = Isolate::GetCurrent();
EscapableHandleScope scope(isolate);

if(args.Length() < 4) {
printf("expected: EncodeALAC(encoder, pcmData, pcmSize, alacData, alacSize)\n");
return scope.Close(Null());
args.GetReturnValue().Set(Null(isolate));
}

Local<Object>wrapper = args[0]->ToObject();
ALACEncoder *encoder = (ALACEncoder*)wrapper->GetPointerFromInternalField(0);
ALACEncoder *encoder = (ALACEncoder*)wrapper->GetAlignedPointerFromInternalField(0);

Local<Value> pcmBuffer = args[1];
unsigned char* pcmData = (unsigned char*)Buffer::Data(pcmBuffer->ToObject());
Expand All @@ -110,15 +106,16 @@ Handle<Value> EncodeALAC(const Arguments& args) {
int32_t alacSize = pcmSize;
encoder->Encode(inputFormat, outputFormat, pcmData, alacData, &alacSize);

return scope.Close(Integer::New(alacSize));
args.GetReturnValue().Set(Integer::New(isolate, alacSize));
}

Handle<Value> EncryptAES(const Arguments& args) {
HandleScope scope;
void EncryptAES(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = v8::Isolate::GetCurrent();
EscapableHandleScope scope(isolate);

if(args.Length() < 2) {
printf("expected: EncryptAES(alacData, alacSize)\n");
return scope.Close(Null());
args.GetReturnValue().Set(Null(isolate));
}

Local<Value> alacBuffer = args[0];
Expand Down Expand Up @@ -146,7 +143,7 @@ Handle<Value> EncryptAES(const Arguments& args) {
i += kBlockSize;
}

return scope.Close(Null());
args.GetReturnValue().Set(Null(isolate));
}

void InitCodec(Handle<Object> target) {
Expand Down
115 changes: 67 additions & 48 deletions src/coreaudio.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// Conversion to modern node (v4)
//
// TODO: understand. I have no idea what I'm doing here. HandleScope/Isolate?
//
// https://nodejs.org/api/addons.html
// https://developers.google.com/v8/embed?hl=en
// https://strongloop.com/strongblog/node-js-v0-12-c-apis-breaking/
// https://github.com/nodejs/nan/blob/master/doc/persistent.md


#include <node.h>
#include <node_buffer.h>
#include <v8.h>
Expand Down Expand Up @@ -43,11 +53,9 @@ namespace nodeairtunes {
};

// This will free the AudioQueue when the wraping JS object is released by the GC
void coreAudio_weak_callback(v8::Persistent<v8::Value> wrapper, void *arg) {
v8::HandleScope scope;
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) arg;
void coreAudio_weak_callback(const v8::WeakCallbackInfo<coreAudioObjects> &data) {
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) data.GetParameter();
AudioQueueDispose(coreAudio->audioQueue, true);
wrapper.Dispose();
}

void OnAudioQueueBufferConsumed(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
Expand Down Expand Up @@ -110,15 +118,20 @@ namespace nodeairtunes {
pthread_mutex_unlock(&(coreAudio->queueBuffersMutex));
}

v8::Handle<v8::Value> NewCoreAudio(const v8::Arguments& args) {
v8::HandleScope scope;
void NewCoreAudio(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

v8::HandleScope handle_scope(isolate);

struct coreAudioObjects *coreAudio
= (struct coreAudioObjects *) malloc(sizeof (*coreAudio));

struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) malloc(sizeof (*coreAudio));
v8::Persistent<v8::ObjectTemplate> coreAudioClass = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
coreAudioClass->SetInternalFieldCount(1);
v8::Persistent<v8::Object> o = v8::Persistent<v8::Object>::New(coreAudioClass->NewInstance());
o->SetPointerInInternalField(0, coreAudio);
o.MakeWeak(coreAudio, coreAudio_weak_callback);
v8::Persistent<v8::Object> o;
o.SetWeak(
coreAudio,
coreAudio_weak_callback,
v8::WeakCallbackType::kParameter
);

coreAudio->isPlaying = false;
coreAudio->buffersUsed = 0;
Expand All @@ -143,7 +156,8 @@ namespace nodeairtunes {
// Allocating AudioQueue

if ((LRet = AudioQueueNewOutput(&LFormat, OnAudioQueueBufferConsumed, coreAudio, NULL, NULL, 0, &(coreAudio->audioQueue)))) {
return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
return;
}

OSStatus status = 0;
Expand All @@ -154,19 +168,20 @@ namespace nodeairtunes {
coreAudio->inuse[i] = false;
}

return scope.Close(o);
args.GetReturnValue().Set(o);
}

v8::Handle<v8::Value> EnqueuePacket(const v8::Arguments& args) {
v8::HandleScope scope;
void EnqueuePacket(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

if (args.Length() < 3) {
printf("expected: EnqueuePacket(coreAudio, pcmData, pcmSize)\n");
return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
return;
}

v8::Local<v8::Object>wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0);
v8::Local<v8::Object> wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;

v8::Local<v8::Value> pcmBuffer = args[1];
unsigned char* pcmData = (unsigned char*) (Buffer::Data(pcmBuffer->ToObject()));
Expand Down Expand Up @@ -204,23 +219,24 @@ namespace nodeairtunes {
offset += copySize;
}

return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
}

v8::Handle<v8::Value> Play(const v8::Arguments& args) {
v8::HandleScope scope;
void Play(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

if (args.Length() < 2) {
printf("expected: Play(coreAudio, audioQueueTimeRef)\n");
return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
return;
}

v8::Local<v8::Object>wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0);
v8::Local<v8::Object> wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;

int64_t timeStamp = args[1]->IntegerValue();

AudioTimeStamp myAudioQueueStartTime = {0};
AudioTimeStamp myAudioQueueStartTime; // = {0};
Float64 theNumberOfSecondsInTheFuture = timeStamp/44100.0;

Float64 hostTimeFreq = CAHostTimeBase::GetFrequency();
Expand All @@ -237,19 +253,20 @@ namespace nodeairtunes {
}
}

return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
}

v8::Handle<v8::Value> Stop(const v8::Arguments& args) {
v8::HandleScope scope;
void Stop(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

if (args.Length() < 1) {
printf("expected: Play(coreAudio)\n");
return scope.Close(v8::Null());
printf("expected: Play(coreAudio)\n");
args.GetReturnValue().Set(v8::Null(isolate));
return;
}

v8::Local<v8::Object>wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0);
v8::Local<v8::Object> wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;

if (coreAudio->isPlaying) {
if (AudioQueueStop(coreAudio->audioQueue, true)) {
Expand All @@ -259,34 +276,36 @@ namespace nodeairtunes {
}
}

return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
}

v8::Handle<v8::Value> SetVolume(const v8::Arguments& args) {
v8::HandleScope scope;
void SetVolume(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

if (args.Length() < 1) {
printf("expected: Play(coreAudio)\n");
return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
return;
}

v8::Local<v8::Object>wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0);
v8::Local<v8::Object> wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
float volumeToSet=args[1]->IntegerValue()/100.0;

if (coreAudio->isPlaying)
AudioQueueSetParameter(coreAudio->audioQueue, kAudioQueueParam_Volume, volumeToSet);

return scope.Close(v8::Null());
args.GetReturnValue().Set(v8::Null(isolate));
}

v8::Handle<v8::Value> GetBufferLevel(const v8::Arguments& args) {
v8::HandleScope scope;
v8::Local<v8::Object>wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0);
v8::Handle<v8::Integer> o= v8::Integer::New((int)((coreAudio->buffersUsed/(float)NUMBER_OF_BUFFERS)*100));

return scope.Close(o);

void GetBufferLevel(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();

v8::Local<v8::Object> wrapper = args[0]->ToObject();
struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper;
v8::Local<v8::Integer> o = v8::Integer::New(isolate, (int)((coreAudio->buffersUsed/(float)NUMBER_OF_BUFFERS)*100));

args.GetReturnValue().Set(o);
}

void InitCoreAudio(v8::Handle<v8::Object> target) {
Expand Down