Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d1ced32
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,125 @@
+#
+#    Copyright (c) 2010-2014 Nest, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the makefile for the ALSA User space library
+#
+
+
+include pre.mak
+
+PackageName		:= alsa-lib
+
+PackageExtension	:= tar.bz2
+PackageSeparator	:= -
+
+PackagePatchArgs	:= -p1
+
+PackageArchive		:= $(PackageName).$(PackageExtension)
+PackageSourceDir	:= $(PackageName)$(PackageSeparator)$(PackageVersion)/
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,Makefile)
+
+CleanPaths		+= $(PackageLicenseFile)
+
+AlsaUserIncDir		:= /usr/include/alsa/
+AlsaUserLibDir		:= /usr/lib/
+ifeq ($(BUILD_FEATURE_SIMULATOR),1)
+AsoundConfigFile	:= asound_sim.conf
+DebugFlags		:= -g -O0
+AlsaPulseDir		:= /usr/lib/x86_64-linux-gnu/alsa-lib/
+else
+AsoundConfigFile	:= asound.conf
+DebugFlags		:=
+AlsaPulseDir		:=
+endif
+
+SOURCEDIRS                      = $(PackageSourceDir)
+$(PackageSourceDir)_RULE_TARGET = $(BuildDirectory)/configure
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/LICENSE: $(BuildDirectory)/source
+
+$(PackageLicenseFile): $(PackageSourceDir)/LICENSE
+	$(copy-result)
+
+# Extract the source from the archive and apply patches, if any.
+
+$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths)
+	$(expand-and-patch-package)
+
+# Prepare the sources.
+
+$(BuildDirectory)/source: | $(PackageSourceDir) $(BuildDirectory)
+	$(Verbose)touch $@
+
+# Patch the sources, if necessary.
+
+$(BuildDirectory)/patch: $(BuildDirectory)/source
+	$(Verbose)touch $@
+
+# Generate the package build makefile.
+
+# Configure the source for building.
+$(BuildDirectory)/configure: PATH := $(HostBinDir):$(PATH)
+
+$(BuildDirectory)/configure: $(BuildDirectory)/source | $(PackageSourceDir) $(BuildDirectory)
+	$(Verbose)cd $(BuildDirectory) && \
+	$(CURDIR)/$(PackageSourceDir)/configure \
+	CC="$(CC) $(DebugFlags)" CXX="$(CXX) $(CPPOPTFLAGS)" AR=$(AR) RANLIB=$(RANLIB) STRIP=$(STRIP) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	--build=$(HostTuple) \
+	--host=$(TargetTuple) \
+	--with-plugindir=$(AlsaPulseDir) \
+	--with-versioned=no \
+	--prefix=/usr \
+	--sysconfdir=/etc \
+	--localstatedir=/var \
+	--includedir=$(AlsaUserIncDir) \
+	--libdir=$(AlsaUserLibDir) \
+	--disable-rawmidi \
+	--disable-seq \
+	--disable-old-symbols \
+	--disable-python \
+	--disable-alisp
+	$(Verbose)touch $@
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+$(BuildDirectory)/build: $(BuildDirectory)/configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) all
+	$(Verbose)touch $@
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+$(BuildDirectory)/stage: $(BuildDirectory)/build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) DESTDIR=$(ResultDirectory) install
+	$(Verbose)cp -f $(AsoundConfigFile) $(ResultDirectory)
+	$(Verbose)touch $@
+
+.PHONY: stage
+stage: $(BuildDirectory)/stage
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/alsa-lib.patches/alsa-lib-50.description b/alsa-lib.patches/alsa-lib-50.description
new file mode 100644
index 0000000..603243d
--- /dev/null
+++ b/alsa-lib.patches/alsa-lib-50.description
@@ -0,0 +1 @@
+This patches handles race conditions during open and close of the dmix device. The changes have been ported from Alsa library version 1.1.4.1 which is the latest version currently.
diff --git a/alsa-lib.patches/alsa-lib-50.patch b/alsa-lib.patches/alsa-lib-50.patch
new file mode 100644
index 0000000..b35609f
--- /dev/null
+++ b/alsa-lib.patches/alsa-lib-50.patch
@@ -0,0 +1,69 @@
+diff -aruN alsa-lib-1.0.27.2/src/pcm/pcm_direct.c alsa-lib-1.0.27.2.N/src/pcm/pcm_direct.c
+--- alsa-lib-1.0.27.2/src/pcm/pcm_direct.c	2013-07-08 05:31:36.000000000 -0700
++++ alsa-lib-1.0.27.2.N/src/pcm/pcm_direct.c	2017-07-13 13:18:48.424261391 -0700
+@@ -91,13 +91,20 @@
+ int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix)
+ {
+ 	struct shmid_ds buf;
+-	int tmpid, err;
++	int tmpid, err, first_instance = 0;
+ 	
+ retryget:
+ 	dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t),
+-			     IPC_CREAT | dmix->ipc_perm);
++			     dmix->ipc_perm);
++	if (dmix->shmid < 0 && errno == ENOENT) {
++		if ((dmix->shmid = shmget(dmix->ipc_key, sizeof(snd_pcm_direct_share_t),
++					     IPC_CREAT | IPC_EXCL | dmix->ipc_perm)) != -1)
++			first_instance = 1;
++		else if (errno == EEXIST)
++			goto retryget;
++	}
+ 	err = -errno;
+-	if (dmix->shmid < 0){
++	if (dmix->shmid < 0) {
+ 		if (errno == EINVAL)
+ 		if ((tmpid = shmget(dmix->ipc_key, 0, dmix->ipc_perm)) != -1)
+ 		if (!shmctl(tmpid, IPC_STAT, &buf))
+@@ -119,7 +126,7 @@
+ 		snd_pcm_direct_shm_discard(dmix);
+ 		return err;
+ 	}
+-	if (buf.shm_nattch == 1) {	/* we're the first user, clear the segment */
++	if (first_instance) {	/* we're the first user, clear the segment */
+ 		memset(dmix->shmptr, 0, sizeof(snd_pcm_direct_share_t));
+ 		if (dmix->ipc_gid >= 0) {
+ 			buf.shm_perm.gid = dmix->ipc_gid;
+@@ -130,6 +137,7 @@
+ 	} else {
+ 		if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) {
+ 			snd_pcm_direct_shm_discard(dmix);
++			SNDERR("Error in second instance");
+ 			return -EINVAL;
+ 		}
+ 	}
+diff -aruN alsa-lib-1.0.27.2/src/pcm/pcm_dmix.c alsa-lib-1.0.27.2.N/src/pcm/pcm_dmix.c
+--- alsa-lib-1.0.27.2/src/pcm/pcm_dmix.c	2013-07-08 05:31:36.000000000 -0700
++++ alsa-lib-1.0.27.2.N/src/pcm/pcm_dmix.c	2017-07-13 13:15:33.874553985 -0700
+@@ -1013,6 +1013,7 @@
+ 	dmix->max_periods = opts->max_periods;
+ 	dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
+ 
++ retry:
+ 	if (first_instance) {
+ 		/* recursion is already checked in
+ 		   snd_pcm_direct_get_slave_ipc_offset() */
+@@ -1069,6 +1070,13 @@
+ 						 SND_PCM_APPEND,
+ 						 NULL);
+ 			if (ret < 0) {
++				/* all other streams have been closed;
++				 * retry as the first instance
++				 */
++				if (ret == -EBADFD) {
++					first_instance = 1;
++					goto retry;
++				}
+ 				SNDERR("unable to open slave");
+ 				goto _err;
+ 			}
diff --git a/alsa-lib.patches/alsa-lib-51.description b/alsa-lib.patches/alsa-lib-51.description
new file mode 100644
index 0000000..c6b0095
--- /dev/null
+++ b/alsa-lib.patches/alsa-lib-51.description
@@ -0,0 +1 @@
+This patch adds some logs to track the open/close of the dmix instances.
diff --git a/alsa-lib.patches/alsa-lib-51.patch b/alsa-lib.patches/alsa-lib-51.patch
new file mode 100644
index 0000000..c63437a
--- /dev/null
+++ b/alsa-lib.patches/alsa-lib-51.patch
@@ -0,0 +1,43 @@
+diff -aruN alsa-lib-1.0.27.2/src/pcm/pcm_dmix.c alsa-lib-1.0.27.2.N/src/pcm/pcm_dmix.c
+--- alsa-lib-1.0.27.2/src/pcm/pcm_dmix.c	2017-08-14 10:28:26.855071601 -0700
++++ alsa-lib-1.0.27.2.N/src/pcm/pcm_dmix.c	2017-08-14 10:36:01.205629277 -0700
+@@ -769,6 +769,7 @@
+ static int snd_pcm_dmix_close(snd_pcm_t *pcm)
+ {
+ 	snd_pcm_direct_t *dmix = pcm->private_data;
++	SNDERR("Closing instance %x", pcm);
+ 
+ 	if (dmix->timer)
+ 		snd_timer_close(dmix->timer);
+@@ -787,6 +788,7 @@
+ 	free(dmix->bindings);
+ 	pcm->private_data = NULL;
+ 	free(dmix);
++	SNDERR("Closed instance %x", pcm);
+ 	return 0;
+ }
+ 
+@@ -1017,6 +1019,7 @@
+ 	if (first_instance) {
+ 		/* recursion is already checked in
+ 		   snd_pcm_direct_get_slave_ipc_offset() */
++		SNDERR("Opening first instance");
+ 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+ 					 mode | SND_PCM_NONBLOCK, NULL);
+ 		if (ret < 0) {
+@@ -1050,6 +1053,7 @@
+ 
+ 		dmix->shmptr->type = spcm->type;
+ 	} else {
++		SNDERR("Opening non-first instance");
+ 		if (dmix->shmptr->use_server) {
+ 			/* up semaphore to avoid deadlock */
+ 			snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+@@ -1123,6 +1127,7 @@
+ 	snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+ 
+ 	*pcmp = pcm;
++	SNDERR("Opened instance %x", pcm);
+ 	return 0;
+ 	
+  _err:
diff --git a/alsa-lib.tar.bz2 b/alsa-lib.tar.bz2
new file mode 100644
index 0000000..be32560
--- /dev/null
+++ b/alsa-lib.tar.bz2
Binary files differ
diff --git a/alsa-lib.url b/alsa-lib.url
new file mode 100644
index 0000000..92ea637
--- /dev/null
+++ b/alsa-lib.url
@@ -0,0 +1 @@
+ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.0.27.2.tar.bz2
diff --git a/alsa-lib.version b/alsa-lib.version
new file mode 100644
index 0000000..6ce29ad
--- /dev/null
+++ b/alsa-lib.version
@@ -0,0 +1 @@
+1.0.27.2
diff --git a/asound.conf b/asound.conf
new file mode 100644
index 0000000..4bc085f
--- /dev/null
+++ b/asound.conf
@@ -0,0 +1,40 @@
+pcm_slave.speaker_16khz_slave {
+	pcm "hw:0,0"
+	format S16_LE
+	channels 1
+	rate 16000
+	period_time 50000
+	buffer_time 100000
+}
+
+pcm.speaker_16khz {
+	type dmix
+	ipc_key 1000  # any unique value
+	ipc_key_add_uid true
+	slave speaker_16khz_slave
+}
+
+pcm_slave.speaker_any_format_slave {
+	pcm "speaker_16khz"
+}
+
+pcm.speaker_any_format {
+	type plug
+	slave speaker_any_format_slave
+}
+
+pcm_slave.mic_16khz_mono_slave {
+	pcm "hw:0,1"
+	format S16_LE
+	channels 1
+	rate 16000
+	period_time 50000
+	buffer_time 100000
+}
+
+pcm.mic_16khz_mono {
+	type dsnoop
+	ipc_key 2000  # any unique value
+	ipc_key_add_uid true
+	slave mic_16khz_mono_slave
+}
diff --git a/asound_sim.conf b/asound_sim.conf
new file mode 100644
index 0000000..460f94b
--- /dev/null
+++ b/asound_sim.conf
@@ -0,0 +1,2 @@
+pcm.speaker_16khz pcm.default
+pcm.mic_16khz_mono pcm.default