diff --git a/examples/play_ffmpeg.js b/examples/play_ffmpeg.js index 19c6ddf..5753b6a 100644 --- a/examples/play_ffmpeg.js +++ b/examples/play_ffmpeg.js @@ -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; diff --git a/examples/sample.mp3 b/examples/sample.mp3 deleted file mode 100644 index 5460855..0000000 Binary files a/examples/sample.mp3 and /dev/null differ diff --git a/examples/wakeup.mp3 b/examples/wakeup.mp3 new file mode 100644 index 0000000..9327319 Binary files /dev/null and b/examples/wakeup.mp3 differ diff --git a/lib/index.js b/lib/index.js index 7cc85b6..e25ee87 100644 --- a/lib/index.js +++ b/lib/index.js @@ -70,3 +70,4 @@ AirTunes.prototype.end = function() { }; module.exports = new AirTunes(); +module.exports.AirTunes = AirTunes; diff --git a/lib/rtsp.js b/lib/rtsp.js index aa32c09..6bd8135 100644 --- a/lib/rtsp.js +++ b/lib/rtsp.js @@ -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(); @@ -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); @@ -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; diff --git a/src/bindings.cc b/src/bindings.cc index c97a6ed..d8f8a50 100644 --- a/src/bindings.cc +++ b/src/bindings.cc @@ -12,7 +12,9 @@ void InitCoreAudio(Handle); #endif void Initialize(Handle target) { - HandleScope scope; + + Isolate* isolate = v8::Isolate::GetCurrent(); + HandleScope scope(isolate); InitCodec(target); #ifdef __APPLE__ diff --git a/src/codec.cc b/src/codec.cc index eb55530..f1956a8 100644 --- a/src/codec.cc +++ b/src/codec.cc @@ -55,17 +55,12 @@ void FillOutputAudioFormat(AudioFormatDescription *format) { format->mReserved = 0; } -void encoder_weak_callback (Persistent 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 NewEncoder(const Arguments& args) { - HandleScope scope; +//Handle NewEncoder(const Arguments& args) { +void NewEncoder(const FunctionCallbackInfo& args) { + Isolate* isolate = Isolate::GetCurrent(); + EscapableHandleScope scope(isolate); AudioFormatDescription outputFormat; FillOutputAudioFormat(&outputFormat); @@ -75,25 +70,26 @@ Handle NewEncoder(const Arguments& args) { encoder->SetFrameSize(kFramesPerPacket); encoder->InitializeEncoder(outputFormat); - Persistent encoderClass = Persistent::New(ObjectTemplate::New()); + Local encoderClass = ObjectTemplate::New(isolate); encoderClass->SetInternalFieldCount(1); - Persistent o = Persistent::New(encoderClass->NewInstance()); - o->SetPointerInInternalField(0, encoder); - o.MakeWeak(encoder, encoder_weak_callback); - return scope.Close(o); + Local obj = encoderClass->NewInstance(); + obj->SetAlignedPointerInInternalField(0, encoder); + + args.GetReturnValue().Set(obj); } -Handle EncodeALAC(const Arguments& args) { - HandleScope scope; +void EncodeALAC(const FunctionCallbackInfo& 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)); } Localwrapper = args[0]->ToObject(); - ALACEncoder *encoder = (ALACEncoder*)wrapper->GetPointerFromInternalField(0); + ALACEncoder *encoder = (ALACEncoder*)wrapper->GetAlignedPointerFromInternalField(0); Local pcmBuffer = args[1]; unsigned char* pcmData = (unsigned char*)Buffer::Data(pcmBuffer->ToObject()); @@ -110,15 +106,16 @@ Handle 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 EncryptAES(const Arguments& args) { - HandleScope scope; +void EncryptAES(const FunctionCallbackInfo& 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 alacBuffer = args[0]; @@ -146,7 +143,7 @@ Handle EncryptAES(const Arguments& args) { i += kBlockSize; } - return scope.Close(Null()); + args.GetReturnValue().Set(Null(isolate)); } void InitCodec(Handle target) { diff --git a/src/coreaudio.cc b/src/coreaudio.cc index 9537c72..41f3429 100644 --- a/src/coreaudio.cc +++ b/src/coreaudio.cc @@ -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 #include #include @@ -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 wrapper, void *arg) { - v8::HandleScope scope; - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) arg; + void coreAudio_weak_callback(const v8::WeakCallbackInfo &data) { + struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) data.GetParameter(); AudioQueueDispose(coreAudio->audioQueue, true); - wrapper.Dispose(); } void OnAudioQueueBufferConsumed(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { @@ -110,15 +118,20 @@ namespace nodeairtunes { pthread_mutex_unlock(&(coreAudio->queueBuffersMutex)); } - v8::Handle NewCoreAudio(const v8::Arguments& args) { - v8::HandleScope scope; + void NewCoreAudio(const v8::FunctionCallbackInfo& 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 coreAudioClass = v8::Persistent::New(v8::ObjectTemplate::New()); - coreAudioClass->SetInternalFieldCount(1); - v8::Persistent o = v8::Persistent::New(coreAudioClass->NewInstance()); - o->SetPointerInInternalField(0, coreAudio); - o.MakeWeak(coreAudio, coreAudio_weak_callback); + v8::Persistent o; + o.SetWeak( + coreAudio, + coreAudio_weak_callback, + v8::WeakCallbackType::kParameter + ); coreAudio->isPlaying = false; coreAudio->buffersUsed = 0; @@ -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; @@ -154,19 +168,20 @@ namespace nodeairtunes { coreAudio->inuse[i] = false; } - return scope.Close(o); + args.GetReturnValue().Set(o); } - v8::Handle EnqueuePacket(const v8::Arguments& args) { - v8::HandleScope scope; + void EnqueuePacket(const v8::FunctionCallbackInfo& 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::Localwrapper = args[0]->ToObject(); - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0); + v8::Local wrapper = args[0]->ToObject(); + struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper; v8::Local pcmBuffer = args[1]; unsigned char* pcmData = (unsigned char*) (Buffer::Data(pcmBuffer->ToObject())); @@ -204,23 +219,24 @@ namespace nodeairtunes { offset += copySize; } - return scope.Close(v8::Null()); + args.GetReturnValue().Set(v8::Null(isolate)); } - v8::Handle Play(const v8::Arguments& args) { - v8::HandleScope scope; + void Play(const v8::FunctionCallbackInfo& 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::Localwrapper = args[0]->ToObject(); - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0); + v8::Local 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(); @@ -237,19 +253,20 @@ namespace nodeairtunes { } } - return scope.Close(v8::Null()); + args.GetReturnValue().Set(v8::Null(isolate)); } - v8::Handle Stop(const v8::Arguments& args) { - v8::HandleScope scope; + void Stop(const v8::FunctionCallbackInfo& 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::Localwrapper = args[0]->ToObject(); - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0); + v8::Local wrapper = args[0]->ToObject(); + struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper; if (coreAudio->isPlaying) { if (AudioQueueStop(coreAudio->audioQueue, true)) { @@ -259,34 +276,36 @@ namespace nodeairtunes { } } - return scope.Close(v8::Null()); + args.GetReturnValue().Set(v8::Null(isolate)); } - v8::Handle SetVolume(const v8::Arguments& args) { - v8::HandleScope scope; + void SetVolume(const v8::FunctionCallbackInfo& 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::Localwrapper = args[0]->ToObject(); - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0); + v8::Local 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 GetBufferLevel(const v8::Arguments& args) { - v8::HandleScope scope; - v8::Localwrapper = args[0]->ToObject(); - struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) wrapper->GetPointerFromInternalField(0); - v8::Handle o= v8::Integer::New((int)((coreAudio->buffersUsed/(float)NUMBER_OF_BUFFERS)*100)); - - return scope.Close(o); + + void GetBufferLevel(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + + v8::Local wrapper = args[0]->ToObject(); + struct coreAudioObjects *coreAudio = (struct coreAudioObjects *) *wrapper; + v8::Local o = v8::Integer::New(isolate, (int)((coreAudio->buffersUsed/(float)NUMBER_OF_BUFFERS)*100)); + + args.GetReturnValue().Set(o); } void InitCoreAudio(v8::Handle target) {