From: Andrew Gundersen Date: Mon, 26 Jul 2021 19:08:25 +0000 (-0500) Subject: initial commit X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=1d75db5bdefa782fc2e62cdd387ebd1de9c8cc59;p=nodeaudio initial commit --- 1d75db5bdefa782fc2e62cdd387ebd1de9c8cc59 diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c72e823 Binary files /dev/null and b/.DS_Store differ diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..32a4bc7 --- /dev/null +++ b/binding.gyp @@ -0,0 +1,16 @@ +{ + "targets": [ + { + "target_name": "nodeaudio", + "sources": [ "src/nodeaudio.c", "src/audio_handler.c", "src/frame_buffer.c" ], + "include_dirs": [ + "/usr/local/include" + ], + "link_settings": { + "libraries": [ + "-lportaudio" + ] + } + } + ] +} diff --git a/binding.js b/binding.js new file mode 100644 index 0000000..846d64e --- /dev/null +++ b/binding.js @@ -0,0 +1,28 @@ +const nodeAudio = require('bindings')('nodeaudio.node'); +console.log("Imported nodeAudio"); + +const wait = async (callback, seconds) => { + await setTimeout(() => { + callback(); + }, seconds); +} + +const recordThenPlay = async (recSeconds) => { + + console.log("Initializing nodeAudio"); + nodeAudio.initialize(); + + nodeAudio.fill_input_buffer(); + + console.log(`Recording for ${recSeconds} seconds`); + const audio = await wait(nodeAudio.return_input_buffer, recSeconds); + + console.log("Playing audio"); + nodeAudio.feed_output_buffer(audio); + + console.log("Shutting down audio"); + nodeAudio.terminate(); + +} + +recordThenPlay(5); \ No newline at end of file diff --git a/build/Makefile b/build/Makefile new file mode 100644 index 0000000..11b7aff --- /dev/null +++ b/build/Makefile @@ -0,0 +1,342 @@ +# We borrow heavily from the kernel build setup, though we are simpler since +# we don't have Kconfig tweaking settings on us. + +# The implicit make rules have it looking for RCS files, among other things. +# We instead explicitly write all the rules we care about. +# It's even quicker (saves ~200ms) to pass -r on the command line. +MAKEFLAGS=-r + +# The source directory tree. +srcdir := .. +abs_srcdir := $(abspath $(srcdir)) + +# The name of the builddir. +builddir_name ?= . + +# The V=1 flag on command line makes us verbosely print command lines. +ifdef V + quiet= +else + quiet=quiet_ +endif + +# Specify BUILDTYPE=Release on the command line for a release build. +BUILDTYPE ?= Release + +# Directory all our build output goes into. +# Note that this must be two directories beneath src/ for unit tests to pass, +# as they reach into the src/ directory for data with relative paths. +builddir ?= $(builddir_name)/$(BUILDTYPE) +abs_builddir := $(abspath $(builddir)) +depsdir := $(builddir)/.deps + +# Object output directory. +obj := $(builddir)/obj +abs_obj := $(abspath $(obj)) + +# We build up a list of every single one of the targets so we can slurp in the +# generated dependency rule Makefiles in one pass. +all_deps := + + + +CC.target ?= $(CC) +CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS) +CXX.target ?= $(CXX) +CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS) +LINK.target ?= $(LINK) +LDFLAGS.target ?= $(LDFLAGS) +AR.target ?= $(AR) + +# C++ apps need to be linked with g++. +LINK ?= $(CXX.target) + +# TODO(evan): move all cross-compilation logic to gyp-time so we don't need +# to replicate this environment fallback in make as well. +CC.host ?= gcc +CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host) +CXX.host ?= g++ +CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host) +LINK.host ?= $(CXX.host) +LDFLAGS.host ?= +AR.host ?= ar + +# Define a dir function that can handle spaces. +# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions +# "leading spaces cannot appear in the text of the first argument as written. +# These characters can be put into the argument value by variable substitution." +empty := +space := $(empty) $(empty) + +# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces +replace_spaces = $(subst $(space),?,$1) +unreplace_spaces = $(subst ?,$(space),$1) +dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) + +# Flags to make gcc output dependency info. Note that you need to be +# careful here to use the flags that ccache and distcc can understand. +# We write to a dep file on the side first and then rename at the end +# so we can't end up with a broken dep file. +depfile = $(depsdir)/$(call replace_spaces,$@).d +DEPFLAGS = -MMD -MF $(depfile).raw + +# We have to fixup the deps output in a few ways. +# (1) the file output should mention the proper .o file. +# ccache or distcc lose the path to the target, so we convert a rule of +# the form: +# foobar.o: DEP1 DEP2 +# into +# path/to/foobar.o: DEP1 DEP2 +# (2) we want missing files not to cause us to fail to build. +# We want to rewrite +# foobar.o: DEP1 DEP2 \ +# DEP3 +# to +# DEP1: +# DEP2: +# DEP3: +# so if the files are missing, they're just considered phony rules. +# We have to do some pretty insane escaping to get those backslashes +# and dollar signs past make, the shell, and sed at the same time. +# Doesn't work with spaces, but that's fine: .d files have spaces in +# their names replaced with other characters. +define fixup_dep +# The depfile may not exist if the input file didn't have any #includes. +touch $(depfile).raw +# Fixup path as in (1). +sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,nodeaudio.target.mk)))),) + include nodeaudio.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/Users/adgundersen/Documents/Crimata/nodeaudio/build/config.gypi -I/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/adgundersen/Library/Caches/node-gyp/14.17.0" "-Dnode_gyp_dir=/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/Users/adgundersen/Library/Caches/node-gyp/14.17.0/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/adgundersen/Documents/Crimata/nodeaudio" "-Dnode_engine=v8" binding.gyp +Makefile: $(srcdir)/../../../Library/Caches/node-gyp/14.17.0/include/node/common.gypi $(srcdir)/../../../../../usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/build/Release/.deps/Release/nodeaudio.node.d b/build/Release/.deps/Release/nodeaudio.node.d new file mode 100644 index 0000000..5b7ce61 --- /dev/null +++ b/build/Release/.deps/Release/nodeaudio.node.d @@ -0,0 +1 @@ +cmd_Release/nodeaudio.node := c++ -bundle -undefined dynamic_lookup -Wl,-no_pie -Wl,-search_paths_first -mmacosx-version-min=10.13 -arch x86_64 -L./Release -stdlib=libc++ -o Release/nodeaudio.node Release/obj.target/nodeaudio/src/nodeaudio.o Release/obj.target/nodeaudio/src/audio_handler.o Release/obj.target/nodeaudio/src/frame_buffer.o -lportaudio diff --git a/build/Release/.deps/Release/obj.target/nodeaudio/src/audio_handler.o.d b/build/Release/.deps/Release/obj.target/nodeaudio/src/audio_handler.o.d new file mode 100644 index 0000000..c00d6b1 --- /dev/null +++ b/build/Release/.deps/Release/obj.target/nodeaudio/src/audio_handler.o.d @@ -0,0 +1,8 @@ +cmd_Release/obj.target/nodeaudio/src/audio_handler.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/audio_handler.o.d.raw -c -o Release/obj.target/nodeaudio/src/audio_handler.o ../src/audio_handler.c +Release/obj.target/nodeaudio/src/audio_handler.o: ../src/audio_handler.c \ + /usr/local/include/portaudio.h ../src/audio_handler.h \ + ../src/frame_buffer.h +../src/audio_handler.c: +/usr/local/include/portaudio.h: +../src/audio_handler.h: +../src/frame_buffer.h: diff --git a/build/Release/.deps/Release/obj.target/nodeaudio/src/frame_buffer.o.d b/build/Release/.deps/Release/obj.target/nodeaudio/src/frame_buffer.o.d new file mode 100644 index 0000000..73580ee --- /dev/null +++ b/build/Release/.deps/Release/obj.target/nodeaudio/src/frame_buffer.o.d @@ -0,0 +1,5 @@ +cmd_Release/obj.target/nodeaudio/src/frame_buffer.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/frame_buffer.o.d.raw -c -o Release/obj.target/nodeaudio/src/frame_buffer.o ../src/frame_buffer.c +Release/obj.target/nodeaudio/src/frame_buffer.o: ../src/frame_buffer.c \ + ../src/frame_buffer.h +../src/frame_buffer.c: +../src/frame_buffer.h: diff --git a/build/Release/.deps/Release/obj.target/nodeaudio/src/nodeaudio.o.d b/build/Release/.deps/Release/obj.target/nodeaudio/src/nodeaudio.o.d new file mode 100644 index 0000000..5cb2f97 --- /dev/null +++ b/build/Release/.deps/Release/obj.target/nodeaudio/src/nodeaudio.o.d @@ -0,0 +1,13 @@ +cmd_Release/obj.target/nodeaudio/src/nodeaudio.o := cc '-DNODE_GYP_MODULE_NAME=nodeaudio' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-DV8_DEPRECATION_WARNINGS' '-DV8_IMMINENT_DEPRECATION_WARNINGS' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include -I/usr/local/include -O3 -gdwarf-2 -mmacosx-version-min=10.13 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/nodeaudio/src/nodeaudio.o.d.raw -c -o Release/obj.target/nodeaudio/src/nodeaudio.o ../src/nodeaudio.c +Release/obj.target/nodeaudio/src/nodeaudio.o: ../src/nodeaudio.c \ + /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api.h \ + /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api.h \ + /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api_types.h \ + /Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api_types.h \ + ../src/audio_handler.h +../src/nodeaudio.c: +/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api.h: +/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api.h: +/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/js_native_api_types.h: +/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node/node_api_types.h: +../src/audio_handler.h: diff --git a/build/Release/nodeaudio.node b/build/Release/nodeaudio.node new file mode 100755 index 0000000..4eca0a8 Binary files /dev/null and b/build/Release/nodeaudio.node differ diff --git a/build/Release/obj.target/nodeaudio/src/audio_handler.o b/build/Release/obj.target/nodeaudio/src/audio_handler.o new file mode 100644 index 0000000..91855f3 Binary files /dev/null and b/build/Release/obj.target/nodeaudio/src/audio_handler.o differ diff --git a/build/Release/obj.target/nodeaudio/src/frame_buffer.o b/build/Release/obj.target/nodeaudio/src/frame_buffer.o new file mode 100644 index 0000000..9f7d1e1 Binary files /dev/null and b/build/Release/obj.target/nodeaudio/src/frame_buffer.o differ diff --git a/build/Release/obj.target/nodeaudio/src/nodeaudio.o b/build/Release/obj.target/nodeaudio/src/nodeaudio.o new file mode 100644 index 0000000..d77f7b9 Binary files /dev/null and b/build/Release/obj.target/nodeaudio/src/nodeaudio.o differ diff --git a/build/binding.Makefile b/build/binding.Makefile new file mode 100644 index 0000000..bfb1aa7 --- /dev/null +++ b/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= ./build/. +.PHONY: all +all: + $(MAKE) nodeaudio diff --git a/build/config.gypi b/build/config.gypi new file mode 100644 index 0000000..9a04c4b --- /dev/null +++ b/build/config.gypi @@ -0,0 +1,200 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [] + }, + "variables": { + "asan": 0, + "build_v8_with_gn": "false", + "coverage": "false", + "dcheck_always_on": 0, + "debug_nghttp2": "false", + "debug_node": "false", + "enable_lto": "false", + "enable_pgo_generate": "false", + "enable_pgo_use": "false", + "error_on_warn": "false", + "force_dynamic_crt": 0, + "host_arch": "x64", + "icu_gyp_path": "tools/icu/icu-system.gyp", + "icu_small": "false", + "icu_ver_major": "69", + "is_debug": 0, + "llvm_version": "12.0", + "napi_build_version": "8", + "node_byteorder": "little", + "node_debug_lib": "false", + "node_enable_d8": "false", + "node_install_npm": "true", + "node_module_version": 83, + "node_no_browser_globals": "false", + "node_prefix": "/usr/local/Cellar/node@14/14.17.0", + "node_release_urlbase": "", + "node_shared": "false", + "node_shared_brotli": "false", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_nghttp2": "false", + "node_shared_openssl": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_target_type": "executable", + "node_use_bundled_v8": "true", + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_node_code_cache": "true", + "node_use_node_snapshot": "true", + "node_use_openssl": "true", + "node_use_v8_platform": "true", + "node_with_ltcg": "false", + "node_without_node_options": "false", + "openssl_fips": "", + "openssl_is_fips": "false", + "ossfuzz": "false", + "shlib_suffix": "83.dylib", + "target_arch": "x64", + "v8_enable_31bit_smis_on_64bit_arch": 0, + "v8_enable_gdbjit": 0, + "v8_enable_i18n_support": 1, + "v8_enable_inspector": 1, + "v8_enable_lite_mode": 0, + "v8_enable_object_print": 1, + "v8_enable_pointer_compression": 0, + "v8_no_strict_aliasing": 1, + "v8_optimized_debug": 1, + "v8_promise_internal_field_count": 1, + "v8_random_seed": 0, + "v8_trace_maps": 0, + "v8_use_siphash": 1, + "want_separate_host_toolset": 0, + "xcode_version": "12.0", + "nodedir": "/Users/adgundersen/Library/Caches/node-gyp/14.17.0", + "standalone_static_library": 1, + "dry_run": "", + "legacy_bundling": "", + "save_dev": "", + "browser": "", + "commit_hooks": "true", + "only": "", + "viewer": "man", + "also": "", + "rollback": "true", + "sign_git_commit": "", + "audit": "true", + "usage": "", + "globalignorefile": "/usr/local/etc/npmignore", + "init_author_url": "", + "maxsockets": "50", + "shell": "/bin/zsh", + "metrics_registry": "https://registry.npmjs.org/", + "parseable": "", + "shrinkwrap": "true", + "init_license": "ISC", + "timing": "", + "if_present": "", + "cache_max": "Infinity", + "init_author_email": "", + "sign_git_tag": "", + "cert": "", + "git_tag_version": "true", + "local_address": "", + "long": "", + "preid": "", + "fetch_retries": "2", + "registry": "https://registry.npmjs.org/", + "key": "", + "message": "%s", + "versions": "", + "globalconfig": "/usr/local/etc/npmrc", + "always_auth": "", + "logs_max": "10", + "prefer_online": "", + "cache_lock_retries": "10", + "global_style": "", + "update_notifier": "true", + "audit_level": "low", + "heading": "npm", + "fetch_retry_mintimeout": "10000", + "offline": "", + "read_only": "", + "searchlimit": "20", + "access": "", + "json": "", + "allow_same_version": "", + "description": "true", + "engine_strict": "", + "https_proxy": "", + "init_module": "/Users/adgundersen/.npm-init.js", + "userconfig": "/Users/adgundersen/.npmrc", + "cidr": "", + "node_version": "14.17.0", + "user": "", + "auth_type": "legacy", + "editor": "vi", + "ignore_prepublish": "", + "save": "true", + "script_shell": "", + "tag": "latest", + "before": "", + "global": "", + "progress": "true", + "ham_it_up": "", + "optional": "true", + "searchstaleness": "900", + "bin_links": "true", + "force": "", + "save_prod": "", + "searchopts": "", + "depth": "Infinity", + "node_gyp": "/usr/local/Cellar/node@14/14.17.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", + "rebuild_bundle": "true", + "sso_poll_frequency": "500", + "unicode": "true", + "fetch_retry_maxtimeout": "60000", + "ca": "", + "save_prefix": "^", + "scripts_prepend_node_path": "warn-only", + "sso_type": "oauth", + "strict_ssl": "true", + "tag_version_prefix": "v", + "dev": "", + "fetch_retry_factor": "10", + "group": "20", + "save_exact": "", + "cache_lock_stale": "60000", + "prefer_offline": "", + "version": "", + "cache_min": "10", + "otp": "", + "cache": "/Users/adgundersen/.npm", + "searchexclude": "", + "color": "true", + "package_lock": "true", + "fund": "true", + "package_lock_only": "", + "save_optional": "", + "user_agent": "npm/6.14.13 node/v14.17.0 darwin x64", + "ignore_scripts": "", + "cache_lock_wait": "10000", + "production": "", + "save_bundle": "", + "send_metrics": "", + "init_version": "1.0.0", + "node_options": "", + "umask": "0022", + "scope": "", + "git": "git", + "init_author_name": "", + "onload_script": "", + "tmp": "/var/folders/8h/5gtb4v414sj09_yzw9rs5z7m0000gq/T", + "unsafe_perm": "true", + "prefix": "/usr/local", + "format_package_lock": "true", + "link": "" + } +} diff --git a/build/gyp-mac-tool b/build/gyp-mac-tool new file mode 100755 index 0000000..033b4e5 --- /dev/null +++ b/build/gyp-mac-tool @@ -0,0 +1,615 @@ +#!/usr/bin/env python +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +from __future__ import print_function + +import fcntl +import fnmatch +import glob +import json +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys +import tempfile + +PY3 = bytes != str + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest, convert_to_binary): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + # TODO(thakis): This copies file attributes like mtime, while the + # single-file branch below doesn't. This should probably be changed to + # be consistent with the single-file branch. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.storyboard': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest, convert_to_binary) + else: + shutil.copy(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + + # ibtool sometimes crashes with relative paths. See crbug.com/314728. + base = os.path.dirname(os.path.realpath(__file__)) + if os.path.relpath(source): + source = os.path.join(base, source) + if os.path.relpath(dest): + dest = os.path.join(base, dest) + + args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices', + '--output-format', 'human-readable-text', '--compile', dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _ConvertToBinary(self, dest): + subprocess.check_call([ + 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest]) + + def _CopyStringsFile(self, source, dest, convert_to_binary): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source, 'rb').read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'wb') + fp.write(s.decode(input_code).encode('UTF-16')) + fp.close() + + if convert_to_binary == 'True': + self._ConvertToBinary(dest) + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except Exception: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16" + elif header.startswith("\xFF\xFE"): + return "UTF-16" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). + plist = plistlib.readPlistFromString(lines) + if keys: + plist = dict(plist.items() + json.loads(keys[0]).items()) + lines = plistlib.writePlistToString(plist) + + # Go through all the environment variables and replace them as variables in + # the file. + IDENT_RE = re.compile(r'[/\s]') + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + evalue = os.environ[key] + lines = string.replace(lines, evar, evalue) + + # Xcode supports various suffices on environment variables, which are + # all undocumented. :rfc1034identifier is used in the standard project + # template these days, and :identifier was used earlier. They are used to + # convert non-url characters into things that look like valid urls -- + # except that the replacement character for :identifier, '_' isn't valid + # in a URL either -- oops, hence :rfc1034identifier was born. + evar = '${%s:identifier}' % key + evalue = IDENT_RE.sub('_', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + evar = '${%s:rfc1034identifier}' % key + evalue = IDENT_RE.sub('-', os.environ[key]) + lines = string.replace(lines, evar, evalue) + + # Remove any keys with values that haven't been replaced. + lines = lines.split('\n') + for i in range(len(lines)): + if lines[i].strip().startswith("${"): + lines[i] = None + lines[i - 1] = None + lines = '\n'.join(filter(lambda x: x is not None, lines)) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + if convert_to_binary == 'True': + self._ConvertToBinary(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no + symbols'.""" + libtool_re = re.compile(r'^.*libtool: file: .* has no symbols$') + libtool_re5 = re.compile( + r'^.*libtool: warning for library: ' + + r'.* the table of contents is empty ' + + r'\(no object file members in the library define global symbols\)$') + env = os.environ.copy() + # Ref: + # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c + # The problem with this flag is that it resets the file mtime on the file to + # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. + env['ZERO_AR_DATE'] = '1' + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) + _, err = libtoolout.communicate() + if PY3: + err = err.decode('utf-8') + for line in err.splitlines(): + if not libtool_re.match(line) and not libtool_re5.match(line): + print(line, file=sys.stderr) + # Unconditionally touch the output .a file on the command line if present + # and the command succeeded. A bit hacky. + if not libtoolout.returncode: + for i in range(len(cmd_list) - 1): + if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'): + os.utime(cmd_list[i+1], None) + break + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + def ExecCompileXcassets(self, keys, *inputs): + """Compiles multiple .xcassets files into a single .car file. + + This invokes 'actool' to compile all the inputs .xcassets files. The + |keys| arguments is a json-encoded dictionary of extra arguments to + pass to 'actool' when the asset catalogs contains an application icon + or a launch image. + + Note that 'actool' does not create the Assets.car file if the asset + catalogs does not contains imageset. + """ + command_line = [ + 'xcrun', 'actool', '--output-format', 'human-readable-text', + '--compress-pngs', '--notices', '--warnings', '--errors', + ] + is_iphone_target = 'IPHONEOS_DEPLOYMENT_TARGET' in os.environ + if is_iphone_target: + platform = os.environ['CONFIGURATION'].split('-')[-1] + if platform not in ('iphoneos', 'iphonesimulator'): + platform = 'iphonesimulator' + command_line.extend([ + '--platform', platform, '--target-device', 'iphone', + '--target-device', 'ipad', '--minimum-deployment-target', + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], '--compile', + os.path.abspath(os.environ['CONTENTS_FOLDER_PATH']), + ]) + else: + command_line.extend([ + '--platform', 'macosx', '--target-device', 'mac', + '--minimum-deployment-target', os.environ['MACOSX_DEPLOYMENT_TARGET'], + '--compile', + os.path.abspath(os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']), + ]) + if keys: + keys = json.loads(keys) + for key, value in keys.items(): + arg_name = '--' + key + if isinstance(value, bool): + if value: + command_line.append(arg_name) + elif isinstance(value, list): + for v in value: + command_line.append(arg_name) + command_line.append(str(v)) + else: + command_line.append(arg_name) + command_line.append(str(value)) + # Note: actool crashes if inputs path are relative, so use os.path.abspath + # to get absolute path name for inputs. + command_line.extend(map(os.path.abspath, inputs)) + subprocess.check_call(command_line) + + def ExecMergeInfoPlist(self, output, *inputs): + """Merge multiple .plist files into a single .plist file.""" + merged_plist = {} + for path in inputs: + plist = self._LoadPlistMaybeBinary(path) + self._MergePlist(merged_plist, plist) + plistlib.writePlist(merged_plist, output) + + def ExecCodeSignBundle(self, key, resource_rules, entitlements, provisioning): + """Code sign a bundle. + + This function tries to code sign an iOS bundle, following the same + algorithm as Xcode: + 1. copy ResourceRules.plist from the user or the SDK into the bundle, + 2. pick the provisioning profile that best match the bundle identifier, + and copy it into the bundle as embedded.mobileprovision, + 3. copy Entitlements.plist from user or SDK next to the bundle, + 4. code sign the bundle. + """ + resource_rules_path = self._InstallResourceRules(resource_rules) + substitutions, overrides = self._InstallProvisioningProfile( + provisioning, self._GetCFBundleIdentifier()) + entitlements_path = self._InstallEntitlements( + entitlements, substitutions, overrides) + subprocess.check_call([ + 'codesign', '--force', '--sign', key, '--resource-rules', + resource_rules_path, '--entitlements', entitlements_path, + os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['FULL_PRODUCT_NAME'])]) + + def _InstallResourceRules(self, resource_rules): + """Installs ResourceRules.plist from user or SDK into the bundle. + + Args: + resource_rules: string, optional, path to the ResourceRules.plist file + to use, default to "${SDKROOT}/ResourceRules.plist" + + Returns: + Path to the copy of ResourceRules.plist into the bundle. + """ + source_path = resource_rules + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'ResourceRules.plist') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], 'ResourceRules.plist') + shutil.copy2(source_path, target_path) + return target_path + + def _InstallProvisioningProfile(self, profile, bundle_identifier): + """Installs embedded.mobileprovision into the bundle. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple containing two dictionary: variables substitutions and values + to overrides when generating the entitlements file. + """ + source_path, provisioning_data, team_id = self._FindProvisioningProfile( + profile, bundle_identifier) + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['CONTENTS_FOLDER_PATH'], + 'embedded.mobileprovision') + shutil.copy2(source_path, target_path) + substitutions = self._GetSubstitutions(bundle_identifier, team_id + '.') + return substitutions, provisioning_data['Entitlements'] + + def _FindProvisioningProfile(self, profile, bundle_identifier): + """Finds the .mobileprovision file to use for signing the bundle. + + Checks all the installed provisioning profiles (or if the user specified + the PROVISIONING_PROFILE variable, only consult it) and select the most + specific that correspond to the bundle identifier. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple of the path to the selected provisioning profile, the data of + the embedded plist in the provisioning profile and the team identifier + to use for code signing. + + Raises: + SystemExit: if no .mobileprovision can be used to sign the bundle. + """ + profiles_dir = os.path.join( + os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles') + if not os.path.isdir(profiles_dir): + print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr) + sys.exit(1) + provisioning_profiles = None + if profile: + profile_path = os.path.join(profiles_dir, profile + '.mobileprovision') + if os.path.exists(profile_path): + provisioning_profiles = [profile_path] + if not provisioning_profiles: + provisioning_profiles = glob.glob( + os.path.join(profiles_dir, '*.mobileprovision')) + valid_provisioning_profiles = {} + for profile_path in provisioning_profiles: + profile_data = self._LoadProvisioningProfile(profile_path) + app_id_pattern = profile_data.get( + 'Entitlements', {}).get('application-identifier', '') + for team_identifier in profile_data.get('TeamIdentifier', []): + app_id = '%s.%s' % (team_identifier, bundle_identifier) + if fnmatch.fnmatch(app_id, app_id_pattern): + valid_provisioning_profiles[app_id_pattern] = ( + profile_path, profile_data, team_identifier) + if not valid_provisioning_profiles: + print('cannot find mobile provisioning for %s' % (bundle_identifier), file=sys.stderr) + sys.exit(1) + # If the user has multiple provisioning profiles installed that can be + # used for ${bundle_identifier}, pick the most specific one (ie. the + # provisioning profile whose pattern is the longest). + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) + return valid_provisioning_profiles[selected_key] + + def _LoadProvisioningProfile(self, profile_path): + """Extracts the plist embedded in a provisioning profile. + + Args: + profile_path: string, path to the .mobileprovision file + + Returns: + Content of the plist embedded in the provisioning profile as a dictionary. + """ + with tempfile.NamedTemporaryFile() as temp: + subprocess.check_call([ + 'security', 'cms', '-D', '-i', profile_path, '-o', temp.name]) + return self._LoadPlistMaybeBinary(temp.name) + + def _MergePlist(self, merged_plist, plist): + """Merge |plist| into |merged_plist|.""" + for key, value in plist.items(): + if isinstance(value, dict): + merged_value = merged_plist.get(key, {}) + if isinstance(merged_value, dict): + self._MergePlist(merged_value, value) + merged_plist[key] = merged_value + else: + merged_plist[key] = value + else: + merged_plist[key] = value + + def _LoadPlistMaybeBinary(self, plist_path): + """Loads into a memory a plist possibly encoded in binary format. + + This is a wrapper around plistlib.readPlist that tries to convert the + plist to the XML format if it can't be parsed (assuming that it is in + the binary format). + + Args: + plist_path: string, path to a plist file, in XML or binary format + + Returns: + Content of the plist as a dictionary. + """ + try: + # First, try to read the file using plistlib that only supports XML, + # and if an exception is raised, convert a temporary copy to XML and + # load that copy. + return plistlib.readPlist(plist_path) + except: + pass + with tempfile.NamedTemporaryFile() as temp: + shutil.copy2(plist_path, temp.name) + subprocess.check_call(['plutil', '-convert', 'xml1', temp.name]) + return plistlib.readPlist(temp.name) + + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): + """Constructs a dictionary of variable substitutions for Entitlements.plist. + + Args: + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + app_identifier_prefix: string, value for AppIdentifierPrefix + + Returns: + Dictionary of substitutions to apply when generating Entitlements.plist. + """ + return { + 'CFBundleIdentifier': bundle_identifier, + 'AppIdentifierPrefix': app_identifier_prefix, + } + + def _GetCFBundleIdentifier(self): + """Extracts CFBundleIdentifier value from Info.plist in the bundle. + + Returns: + Value of CFBundleIdentifier in the Info.plist located in the bundle. + """ + info_plist_path = os.path.join( + os.environ['TARGET_BUILD_DIR'], + os.environ['INFOPLIST_PATH']) + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) + return info_plist_data['CFBundleIdentifier'] + + def _InstallEntitlements(self, entitlements, substitutions, overrides): + """Generates and install the ${BundleName}.xcent entitlements file. + + Expands variables "$(variable)" pattern in the source entitlements file, + add extra entitlements defined in the .mobileprovision file and the copy + the generated plist to "${BundlePath}.xcent". + + Args: + entitlements: string, optional, path to the Entitlements.plist template + to use, defaults to "${SDKROOT}/Entitlements.plist" + substitutions: dictionary, variable substitutions + overrides: dictionary, values to add to the entitlements + + Returns: + Path to the generated entitlements file. + """ + source_path = entitlements + target_path = os.path.join( + os.environ['BUILT_PRODUCTS_DIR'], + os.environ['PRODUCT_NAME'] + '.xcent') + if not source_path: + source_path = os.path.join( + os.environ['SDKROOT'], + 'Entitlements.plist') + shutil.copy2(source_path, target_path) + data = self._LoadPlistMaybeBinary(target_path) + data = self._ExpandVariables(data, substitutions) + if overrides: + for key in overrides: + if key not in data: + data[key] = overrides[key] + plistlib.writePlist(data, target_path) + return target_path + + def _ExpandVariables(self, data, substitutions): + """Expands variables "$(variable)" in data. + + Args: + data: object, can be either string, list or dictionary + substitutions: dictionary, variable substitutions to perform + + Returns: + Copy of data where each references to "$(variable)" has been replaced + by the corresponding value found in substitutions, or left intact if + the key was not found. + """ + if isinstance(data, str): + for key, value in substitutions.items(): + data = data.replace('$(%s)' % key, value) + return data + if isinstance(data, list): + return [self._ExpandVariables(v, substitutions) for v in data] + if isinstance(data, dict): + return {k: self._ExpandVariables(data[k], substitutions) for k in data} + return data + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/build/nodeaudio.target.mk b/build/nodeaudio.target.mk new file mode 100644 index 0000000..d6d5c1c --- /dev/null +++ b/build/nodeaudio.target.mk @@ -0,0 +1,195 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := nodeaudio +DEFS_Debug := \ + '-DNODE_GYP_MODULE_NAME=nodeaudio' \ + '-DUSING_UV_SHARED=1' \ + '-DUSING_V8_SHARED=1' \ + '-DV8_DEPRECATION_WARNINGS=1' \ + '-DV8_DEPRECATION_WARNINGS' \ + '-DV8_IMMINENT_DEPRECATION_WARNINGS' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DOPENSSL_NO_PINSHARED' \ + '-DOPENSSL_THREADS' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' \ + '-DV8_ENABLE_CHECKS' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.13 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -std=gnu++1y \ + -stdlib=libc++ \ + -fno-rtti \ + -fno-exceptions \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include \ + -I/usr/local/include + +DEFS_Release := \ + '-DNODE_GYP_MODULE_NAME=nodeaudio' \ + '-DUSING_UV_SHARED=1' \ + '-DUSING_V8_SHARED=1' \ + '-DV8_DEPRECATION_WARNINGS=1' \ + '-DV8_DEPRECATION_WARNINGS' \ + '-DV8_IMMINENT_DEPRECATION_WARNINGS' \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DOPENSSL_NO_PINSHARED' \ + '-DOPENSSL_THREADS' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -O3 \ + -gdwarf-2 \ + -mmacosx-version-min=10.13 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -std=gnu++1y \ + -stdlib=libc++ \ + -fno-rtti \ + -fno-exceptions \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/include/node \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/src \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/config \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/openssl/openssl/include \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/uv/include \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/zlib \ + -I/Users/adgundersen/Library/Caches/node-gyp/14.17.0/deps/v8/include \ + -I/usr/local/include + +OBJS := \ + $(obj).target/$(TARGET)/src/nodeaudio.o \ + $(obj).target/$(TARGET)/src/audio_handler.o \ + $(obj).target/$(TARGET)/src/frame_buffer.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-no_pie \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.13 \ + -arch x86_64 \ + -L$(builddir) \ + -stdlib=libc++ + +LIBTOOLFLAGS_Debug := \ + -undefined dynamic_lookup \ + -Wl,-no_pie \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-no_pie \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.13 \ + -arch x86_64 \ + -L$(builddir) \ + -stdlib=libc++ + +LIBTOOLFLAGS_Release := \ + -undefined dynamic_lookup \ + -Wl,-no_pie \ + -Wl,-search_paths_first + +LIBS := \ + -lportaudio + +$(builddir)/nodeaudio.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/nodeaudio.node: LIBS := $(LIBS) +$(builddir)/nodeaudio.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/nodeaudio.node: TOOLSET := $(TOOLSET) +$(builddir)/nodeaudio.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/nodeaudio.node +# Add target alias +.PHONY: nodeaudio +nodeaudio: $(builddir)/nodeaudio.node + +# Short alias for building this executable. +.PHONY: nodeaudio.node +nodeaudio.node: $(builddir)/nodeaudio.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/nodeaudio.node + diff --git a/node_modules/bindings/README.md b/node_modules/bindings/README.md new file mode 100644 index 0000000..585cf51 --- /dev/null +++ b/node_modules/bindings/README.md @@ -0,0 +1,97 @@ +node-bindings +============= +### Helper module for loading your native module's .node file + +This is a helper module for authors of Node.js native addon modules. +It is basically the "swiss army knife" of `require()`ing your native module's +`.node` file. + +Throughout the course of Node's native addon history, addons have ended up being +compiled in a variety of different places, depending on which build tool and which +version of node was used. To make matters worse, now the _gyp_ build tool can +produce either a _Release_ or _Debug_ build, each being built into different +locations. + +This module checks _all_ the possible locations that a native addon would be built +at, and returns the first one that loads successfully. + + +Installation +------------ + +Install with `npm`: + +``` bash +$ npm install bindings +``` + +Or add it to the `"dependencies"` section of your _package.json_ file. + + +Example +------- + +`require()`ing the proper bindings file for the current node version, platform +and architecture is as simple as: + +``` js +var bindings = require('bindings')('binding.node') + +// Use your bindings defined in your C files +bindings.your_c_function() +``` + + +Nice Error Output +----------------- + +When the `.node` file could not be loaded, `node-bindings` throws an Error with +a nice error message telling you exactly what was tried. You can also check the +`err.tries` Array property. + +``` +Error: Could not load the bindings file. Tried: + → /Users/nrajlich/ref/build/binding.node + → /Users/nrajlich/ref/build/Debug/binding.node + → /Users/nrajlich/ref/build/Release/binding.node + → /Users/nrajlich/ref/out/Debug/binding.node + → /Users/nrajlich/ref/Debug/binding.node + → /Users/nrajlich/ref/out/Release/binding.node + → /Users/nrajlich/ref/Release/binding.node + → /Users/nrajlich/ref/build/default/binding.node + → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node + at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13) + at Object. (/Users/nrajlich/ref/lib/ref.js:5:47) + at Module._compile (module.js:449:26) + at Object.Module._extensions..js (module.js:467:10) + at Module.load (module.js:356:32) + at Function.Module._load (module.js:312:12) + ... +``` + + +License +------- + +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/bindings/bindings.js b/node_modules/bindings/bindings.js new file mode 100644 index 0000000..93dcf85 --- /dev/null +++ b/node_modules/bindings/bindings.js @@ -0,0 +1,166 @@ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , join = path.join + , dirname = path.dirname + , exists = fs.existsSync || path.existsSync + , defaults = { + arrow: process.env.NODE_BINDINGS_ARROW || ' → ' + , compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled' + , platform: process.platform + , arch: process.arch + , version: process.versions.node + , bindings: 'bindings.node' + , try: [ + // node-gyp's linked version in the "build" dir + [ 'module_root', 'build', 'bindings' ] + // node-waf and gyp_addon (a.k.a node-gyp) + , [ 'module_root', 'build', 'Debug', 'bindings' ] + , [ 'module_root', 'build', 'Release', 'bindings' ] + // Debug files, for development (legacy behavior, remove for node v0.9) + , [ 'module_root', 'out', 'Debug', 'bindings' ] + , [ 'module_root', 'Debug', 'bindings' ] + // Release files, but manually compiled (legacy behavior, remove for node v0.9) + , [ 'module_root', 'out', 'Release', 'bindings' ] + , [ 'module_root', 'Release', 'bindings' ] + // Legacy from node-waf, node <= 0.4.x + , [ 'module_root', 'build', 'default', 'bindings' ] + // Production "Release" buildtype binary (meh...) + , [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ] + ] + } + +/** + * The main `bindings()` function loads the compiled bindings for a given module. + * It uses V8's Error API to determine the parent filename that this function is + * being invoked from, which is then used to find the root directory. + */ + +function bindings (opts) { + + // Argument surgery + if (typeof opts == 'string') { + opts = { bindings: opts } + } else if (!opts) { + opts = {} + } + opts.__proto__ = defaults + + // Get the module root + if (!opts.module_root) { + opts.module_root = exports.getRoot(exports.getFileName()) + } + + // Ensure the given bindings name ends with .node + if (path.extname(opts.bindings) != '.node') { + opts.bindings += '.node' + } + + var tries = [] + , i = 0 + , l = opts.try.length + , n + , b + , err + + for (; i (http://tootallnate.net)", + "repository": { + "type": "git", + "url": "git://github.com/TooTallNate/node-bindings.git" + }, + "main": "./bindings.js", + "bugs": { + "url": "https://github.com/TooTallNate/node-bindings/issues" + }, + "homepage": "https://github.com/TooTallNate/node-bindings", + "license": "MIT" + +,"_resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz" +,"_integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" +,"_from": "bindings@1.2.1" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d161c63 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "function_arguments", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..13f2e39 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "function_arguments", + "version": "0.0.0", + "description": "Node.js Addons Example #2", + "main": "binding.js", + "private": true, + "dependencies": { + "bindings": "~1.2.1" + }, + "scripts": { + "test": "node binding.js" + }, + "gypfile": true +} diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..53b7fab Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/a.out b/src/a.out new file mode 100755 index 0000000..9df8f5d Binary files /dev/null and b/src/a.out differ diff --git a/src/audio_handler.c b/src/audio_handler.c new file mode 100644 index 0000000..56c706f --- /dev/null +++ b/src/audio_handler.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "audio_handler.h" +#include "frame_buffer.h" + +bool sys_on; + +bool recording = false; +int write_to_o_buff = 0; +bool initialized = false; + +frame_buffer inputFrameBuffer; +frame_buffer outputFrameBuffer; + +typedef short SAMPLE; + +static int min_int (int a, int b) { + return (a < b) ? a : b; +} + +#define SAMPLE_RATE (16000) +#define BUFFER_mSECS (30) +#define FRAMES_PER_BUFFER (160 * (BUFFER_mSECS/10)) + + +/* input -> inputFrameBuffer */ +static int input_callback( const void* input, + void* output, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* frameBuffer ) +{ + (void) output; + char *i_buf = (char *) input; + frame_buffer* fb = (frame_buffer*) frameBuffer; + + if (!recording) { + rewrite_frames_fb( fb, + i_buf, + framesPerBuffer*sizeof(SAMPLE) ); + } else { + rewrite_frames_fb( fb, + i_buf, + framesPerBuffer*sizeof(SAMPLE) ); + } + + return paContinue; + +} + + +/* outputFrameBuffer -> output */ +static int output_callback( const void *input, + void* output, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* frameBuffer ) +{ + + (void) input; + char* o_buf = (char *) output; + frame_buffer* fb = (frame_buffer*) frameBuffer; + + if (write_to_o_buff == 0) { + + write_to_o_buff = 2; + + if (fb->frames_used > 0) { + + int frames_to_read = min_int( framesPerBuffer, + fb->frames_used ); + + /* read each frame in outputFrameBuffer and write to output */ + for (int i = 0; i < frames_to_read; i++) { + *((SAMPLE *)o_buf) = *((SAMPLE *) read_frame_at_cursor_fb(fb)); + o_buf += sizeof(SAMPLE); + } + + } else { + *((SAMPLE *)o_buf) = 0; + } + + write_to_o_buff = 0; + + } + + return paContinue; +} + + +static void setParameters( PaDeviceIndex device, + PaStreamParameters* parameters ) +{ + parameters->device = Pa_GetDefaultInputDevice(); + parameters->channelCount = 1; + parameters->hostApiSpecificStreamInfo = NULL; + parameters->suggestedLatency = Pa_GetDeviceInfo(device)->defaultHighInputLatency; +} + + +static PaError set_stream( int type, // 0 = input, 1 = output + PaStream* stream, + PaDeviceIndex device, + PaStreamCallback* callback, + void* frameBuffer ) +{ + PaError err; + PaStreamParameters streamParameters; + + setParameters(device, &streamParameters); + + if (type == 0) { + err = Pa_OpenStream( &stream, + NULL, + &streamParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, + callback, + frameBuffer ); + } else { + err = Pa_OpenStream( &stream, + &streamParameters, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, + callback, + frameBuffer ); + } + if (err != paNoError) return err; + + err = Pa_StartStream(stream); + + return err; +} + + +void AH_initialize() +{ + PaError err = paNoError; + + PaDeviceIndex inputDevice; + PaDeviceIndex outputDevice; + PaDeviceIndex defaultOutputDevice; + PaDeviceIndex defaultInputDevice; + + PaStream* inputStream = NULL; + PaStream* outputStream = NULL; + + init_fb(&inputFrameBuffer); + init_fb(&outputFrameBuffer); + + sys_on = true; + + while (sys_on) { + + Pa_Initialize(); + + defaultInputDevice = Pa_GetDefaultInputDevice(); + defaultOutputDevice = Pa_GetDefaultOutputDevice(); + printf("Input: %i, Output: %i\n", defaultInputDevice, defaultOutputDevice); + + if (inputDevice != defaultInputDevice) { + inputDevice = defaultInputDevice; + err = set_stream( 0, + inputStream, + inputDevice, + &input_callback, + &inputFrameBuffer ); + } + + if (outputDevice != defaultOutputDevice) { + outputDevice = defaultOutputDevice; + err = set_stream( 1, + outputStream, + outputDevice, + &output_callback, + &outputFrameBuffer ); + } + + sleep(1); + + } + + Pa_AbortStream(inputStream); + Pa_AbortStream(outputStream); + + delete_fb(&inputFrameBuffer); + delete_fb(&outputFrameBuffer); + + Pa_Terminate(); + initialized = false; + +} + +void AH_terminate() +{ + printf("Terminating PA\n"); + sys_on = false; + + while(initialized) { + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5000; + nanosleep(&t, &t); + } + +} + + +void AH_fillInputBuffer() +{ + recording = true; +} + + +void AH_resetInputBuffer(void* data, size_t* byte_length) +{ + size_t len = sizeof(inputFrameBuffer.data); + char audioData[len]; + data = audioData; // points to 0th el of audioData + byte_length = &len; + + for(int i = 0; i < (int) len; i++) { + audioData[i] = inputFrameBuffer.data[i]; + } + + recording = false; + clear_fb(&inputFrameBuffer); +} + + +void AH_feedOutputBuffer(void* data, size_t* byte_length) +{ + + // can't intert into buffer while it's being read from + while (write_to_o_buff == 2) { + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5000; + nanosleep(&t, &t); + } + + write_to_o_buff = 1; + insert_frames_fb(&outputFrameBuffer, data, (int) &byte_length); + write_to_o_buff = 0; + +} + + diff --git a/src/audio_handler.h b/src/audio_handler.h new file mode 100644 index 0000000..1487dcd --- /dev/null +++ b/src/audio_handler.h @@ -0,0 +1,16 @@ +#ifndef AUDIO_HANDLER +#define AUDIO_HANDLER + + +void AH_initialize (); + +void AH_fillInputBuffer (); + +void AH_resetInputBuffer(void* data, size_t* byte_length); + +void AH_feedOutputBuffer(void* data, size_t* byte_length); + +void AH_terminate (); + + +#endif \ No newline at end of file diff --git a/src/audio_handler.o b/src/audio_handler.o new file mode 100644 index 0000000..ee8487a Binary files /dev/null and b/src/audio_handler.o differ diff --git a/src/frame_buffer.c b/src/frame_buffer.c new file mode 100644 index 0000000..9fcdac3 --- /dev/null +++ b/src/frame_buffer.c @@ -0,0 +1,120 @@ +#include +#include +#include + + +#include "frame_buffer.h" + +#define BYTES_PER_FRAME (2) +#define INITIAL_FRAME_COUNT (480*100) + + +#define ALPHA (2) + + + +void init_fb ( frame_buffer *fb ) { + fb->frames_used = 0; + fb->frames_free = INITIAL_FRAME_COUNT; + fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT); + fb->cursor = fb->data; +} + + +void delete_fb ( frame_buffer *fb ) { + fb->frames_used = 0; + fb->frames_free = 0; + fb->cursor = NULL; + free(fb->data); +} + + +void clear_fb ( frame_buffer *fb ) { + free(fb->data); + fb->data = (char *) malloc(BYTES_PER_FRAME*INITIAL_FRAME_COUNT); + fb->cursor = fb->data; + fb->frames_free = INITIAL_FRAME_COUNT; + fb->frames_used = 0; +} + + +void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) { + + int frames = frames_len / BYTES_PER_FRAME; + + int cursor_diff = fb->cursor - fb->data; + int data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME; + + if (frames > fb->frames_free) { + fb->data = realloc(fb->data, (data_len+frames_len)*ALPHA); + fb->cursor = fb->data+cursor_diff; + + if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) { + memmove(fb->data+data_len, fb->data, (fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff)); + } + fb->frames_used += frames; + fb->frames_free = fb->frames_used; + } + + data_len = (fb->frames_free+fb->frames_used)*BYTES_PER_FRAME; + if (fb->frames_used*BYTES_PER_FRAME > data_len-cursor_diff) { + memcpy(fb->data+((fb->frames_used*BYTES_PER_FRAME)-(data_len-cursor_diff)), frame_data, frames_len); + fb->frames_free -= frames; + fb->frames_used += frames; + return; + } + if (frames_len+(fb->frames_used*BYTES_PER_FRAME) > data_len-cursor_diff) { + int non_overlap = data_len - (cursor_diff+(fb->frames_used*BYTES_PER_FRAME)); + int overlap = frames_len - non_overlap; + memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, non_overlap); + memcpy(fb->data, &(frame_data[non_overlap]), overlap); + fb->frames_free -= frames; + fb->frames_used += frames; + return; + } + + memcpy(fb->cursor+(fb->frames_used*BYTES_PER_FRAME), frame_data, frames_len); + fb->frames_free -= frames; + fb->frames_used += frames; +} + + +void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ) { + int frames = frames_len / BYTES_PER_FRAME; + + if (frames > (fb->frames_used + fb->frames_free)) { + fb->data = realloc(fb->data, frames_len*ALPHA); + fb->frames_free = frames; + fb->frames_used = frames; + } else { + fb->frames_free = fb->frames_free + fb->frames_used - frames; + fb->frames_used = frames; + } + memcpy(fb->data, frame_data, frames_len); + fb->cursor = fb->data; +} + + + +char* read_frame_at_cursor_fb ( frame_buffer *fb ) { + char *begin = fb->cursor; + int frames_free = fb->frames_free; + int frames_used = fb->frames_used; + char *data = fb->data; + + if (frames_used == 0) { + return NULL; + } + + fb->cursor += BYTES_PER_FRAME; + if (fb->cursor >= data + ((frames_free+frames_used)*BYTES_PER_FRAME)) { + fb->cursor = data; + } + + fb->frames_free += 1; + fb->frames_used -= 1; + + return begin; +} + + diff --git a/src/frame_buffer.h b/src/frame_buffer.h new file mode 100644 index 0000000..1822a1b --- /dev/null +++ b/src/frame_buffer.h @@ -0,0 +1,24 @@ +#ifndef FRAME_BUFFER +#define FRAME_BUFFER + + +typedef struct { + int frames_free, frames_used; + char *data, *cursor; +} frame_buffer; + + +void init_fb ( frame_buffer *fb ); + +void delete_fb ( frame_buffer *fb ); + +void clear_fb ( frame_buffer *fb ); + +void insert_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ); + +void rewrite_frames_fb ( frame_buffer *fb, char *frame_data, int frames_len ); + +char* read_frame_at_cursor_fb ( frame_buffer *fb ); + + +#endif diff --git a/src/frame_buffer.o b/src/frame_buffer.o new file mode 100644 index 0000000..faa02f2 Binary files /dev/null and b/src/frame_buffer.o differ diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..2fa182f --- /dev/null +++ b/src/makefile @@ -0,0 +1,26 @@ +IDIR =../include +CC=gcc +CFLAGS=-I$(IDIR) + +ODIR=obj +LDIR =-L/usr/local/lib -L/usr/lib + +LIBS=-lportaudio + +_DEPS = audio_handler.h frame_buffer.h +DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) + +_OBJ = audio_handler.o frame_buffer.o +OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) + + +$(ODIR)/%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +nodeaudio: $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) $(LDIR) $(LIBS) + +.PHONY: clean + +clean: + rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ \ No newline at end of file diff --git a/src/nodeaudio b/src/nodeaudio new file mode 100755 index 0000000..39e3b57 Binary files /dev/null and b/src/nodeaudio differ diff --git a/src/nodeaudio.c b/src/nodeaudio.c new file mode 100644 index 0000000..0fa7fbd --- /dev/null +++ b/src/nodeaudio.c @@ -0,0 +1,90 @@ +#include +#include +#include + +#include "audio_handler.h" + + +#define DECLARE_NAPI_METHOD(name, func) { name, 0, func, 0, 0, 0, napi_default, 0 } + +napi_value Initialize(napi_env env, napi_callback_info info) +{ + (void) info; + AH_initialize(); + return NULL; +} + +napi_value FillInputBuffer(napi_env env, napi_callback_info info) +{ + (void) info; + AH_fillInputBuffer(); + return NULL; +} + + +napi_value ReturnInputBuffer(napi_env env, napi_callback_info info) +{ + (void) info; + napi_status status; + void* data; + size_t byte_length; + + AH_resetInputBuffer(&data, &byte_length); + + napi_value buffer; + status = napi_create_arraybuffer( env, + byte_length, + &data, + &buffer ); + assert(status == napi_ok); + + return buffer; +} + + +static napi_value FeedOutputBuffer(napi_env env, napi_callback_info info) +{ + napi_status status; + void* data; + size_t byte_length; + napi_value arraybuffer; + + size_t argc = 1; /* parse args */ + napi_value args[1]; + status = napi_get_cb_info(env, info, &argc, args, NULL, NULL); + assert(status == napi_ok); + + arraybuffer = args[0]; + + status = napi_get_arraybuffer_info( env, + arraybuffer, + &data, + &byte_length ); + assert(status == napi_ok); + + AH_feedOutputBuffer(data, &byte_length); + return NULL; +} + + +napi_value Init(napi_env env, napi_value exports) +{ + napi_status status; + + napi_property_descriptor desc[] = { + DECLARE_NAPI_METHOD("fill_input_buffer", FillInputBuffer), + DECLARE_NAPI_METHOD("return_input_buffer", ReturnInputBuffer), + DECLARE_NAPI_METHOD("feed_output_buffer", FeedOutputBuffer) + }; + + status = napi_define_properties(env, exports, 1, desc); + + AH_initialize(); + + return exports; + +} + + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) + diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..93a9732 --- /dev/null +++ b/src/test.c @@ -0,0 +1,44 @@ +#include +#include +#include +// #include "audio_handler.h" + +#include + +// int main() { +// printf("PA init test.\n"); + +// pthread_t in_th; +// printf("Creating audio thread.\n"); +// pthread_create(&in_th, NULL, (void *) AH_initialize, NULL); + +// sleep(10); + +// AH_terminate(); + +// return 0; + +// } + + +int main () +{ + + printf("Initializing portaudio\n"); + Pa_Initialize(); + + for (int i = 0; i < 10; ++i) + { + PaHostApiIndex hostApi = Pa_GetDefaultHostApi(); + const PaHostApiInfo* hostApiInfo = Pa_GetHostApiInfo(hostApi); + + printf("Default input id: %i\n", hostApiInfo->defaultInputDevice); + + sleep(2); + } + + Pa_Terminate(); + + return 0; + +} \ No newline at end of file