v8::Handle<v8::Value> Open(const v8::Arguments& args) { v8::HandleScope scope; PaError err; PaStreamParameters outputParameters; v8::Local<v8::Object> v8Buffer; v8::Local<v8::Object> v8Stream; PortAudioData* data; int sampleRate; char str[1000]; v8::Handle<v8::Value> initArgs[1]; v8::Handle<v8::Value> toEventEmitterArgs[1]; v8::Local<v8::Value> v8Val; v8::Handle<v8::Value> argv[2]; argv[0] = v8::Undefined(); argv[1] = v8::Undefined(); // options if(!args[0]->IsObject()) { return scope.Close(v8::ThrowException(v8::Exception::TypeError(v8::String::New("First argument must be an object")))); } v8::Local<v8::Object> options = args[0]->ToObject(); // callback if(!args[1]->IsFunction()) { return scope.Close(v8::ThrowException(v8::Exception::TypeError(v8::String::New("Second argument must be a function")))); } v8::Local<v8::Value> callback = args[1]; err = EnsureInitialized(); if(err != paNoError) { sprintf(str, "Could not initialize PortAudio %d", err); argv[0] = v8::Exception::TypeError(v8::String::New(str)); goto openDone; } if(!g_portAudioStreamInitialized) { v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(v8::String::NewSymbol("PortAudioStream")); g_streamConstructor = v8::Persistent<v8::Function>::New(t->GetFunction()); toEventEmitterArgs[0] = g_streamConstructor; v8Val = options->Get(v8::String::New("toEventEmitter")); v8::Function::Cast(*v8Val)->Call(options, 1, toEventEmitterArgs); g_portAudioStreamInitialized = true; } memset(&outputParameters, 0, sizeof(PaStreamParameters)); outputParameters.device = Pa_GetDefaultOutputDevice(); if (outputParameters.device == paNoDevice) { sprintf(str, "No default output device"); argv[0] = v8::Exception::TypeError(v8::String::New(str)); goto openDone; } v8Val = options->Get(v8::String::New("channelCount")); outputParameters.channelCount = v8Val->ToInt32()->Value(); v8Val = options->Get(v8::String::New("sampleFormat")); switch(v8Val->ToInt32()->Value()) { case 8: outputParameters.sampleFormat = paInt8; break; case 16: outputParameters.sampleFormat = paInt16; break; case 24: outputParameters.sampleFormat = paInt24; break; case 32: outputParameters.sampleFormat = paInt32; break; default: argv[0] = v8::Exception::TypeError(v8::String::New("Invalid sampleFormat")); goto openDone; } outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; v8Val = options->Get(v8::String::New("sampleRate")); sampleRate = v8Val->ToInt32()->Value(); data = new PortAudioData(); data->readIdx = 0; data->writeIdx = 1; data->channelCount = outputParameters.channelCount; data->sampleFormat = outputParameters.sampleFormat; v8Stream = g_streamConstructor->NewInstance(); v8Stream->SetPointerInInternalField(0, data); v8Val = options->Get(v8::String::New("streamInit")); initArgs[0] = v8Stream; v8::Function::Cast(*v8Val)->Call(v8Stream, 1, initArgs); data->v8Stream = v8::Persistent<v8::Object>::New(v8Stream); data->v8Stream.MakeWeak(data, CleanupStreamData); data->v8Stream.MarkIndependent(); v8Buffer = v8Stream->Get(v8::String::New("buffer"))->ToObject(); data->buffer = (unsigned char*)node::Buffer::Data(v8Buffer); data->bufferLen = node::Buffer::Length(v8Buffer); err = Pa_OpenStream( &data->stream, NULL, // no input &outputParameters, sampleRate, FRAMES_PER_BUFFER, paClipOff, // we won't output out of range samples so don't bother clipping them nodePortAudioCallback, data); if(err != paNoError) { sprintf(str, "Could not open stream %d", err); argv[0] = v8::Exception::TypeError(v8::String::New(str)); goto openDone; } v8Stream->Set(v8::String::New("write"), v8::FunctionTemplate::New(stream_write)->GetFunction()); v8Stream->Set(v8::String::New("writeByte"), v8::FunctionTemplate::New(stream_writeByte)->GetFunction()); v8Stream->Set(v8::String::New("start"), v8::FunctionTemplate::New(stream_start)->GetFunction()); v8Stream->Set(v8::String::New("stop"), v8::FunctionTemplate::New(stream_stop)->GetFunction()); argv[1] = v8Stream; openDone: v8::Function::Cast(*callback)->Call(v8::Context::GetCurrent()->Global(), 2, argv); return scope.Close(v8::Undefined()); }
v8::Local<v8::Object> create_instance(void *wrapper) { v8::Local<v8::Object> instance = js_template->NewInstance(); instance->SetInternalField(0, v8::External::New(wrapper)); return instance; }