examples/nxplayer: add nxplayer from NuttX
authorBongryul Lee <bongryul.lee@samsung.com>
Wed, 7 Jun 2017 21:07:24 +0000 (06:07 +0900)
committerIvan Galkin <ivan.galkin@samsung.com>
Sun, 27 Aug 2017 05:27:38 +0000 (14:27 +0900)
add command line media player.

Change-Id: I8ee94dff717833e0d64ac9655502fba663110f1d
Signed-off-by: Gregory Nutt <gnutt@nuttx.org>
[Lee: backported from NuttX]
Signed-off-by: Bongryul Lee <bongryul.lee@samsung.com>
Signed-off-by: Junhwan Park <junhwan.park@samsung.com>
apps/examples/nxplayer/Kconfig [new file with mode: 0644]
apps/examples/nxplayer/Make.defs [new file with mode: 0644]
apps/examples/nxplayer/Makefile [new file with mode: 0644]
apps/examples/nxplayer/README.txt [new file with mode: 0644]
apps/examples/nxplayer/nxplayer.c [new file with mode: 0644]
apps/examples/nxplayer/nxplayer_main.c [new file with mode: 0644]
apps/include/nxplayer.h [new file with mode: 0644]

diff --git a/apps/examples/nxplayer/Kconfig b/apps/examples/nxplayer/Kconfig
new file mode 100644 (file)
index 0000000..86d0613
--- /dev/null
@@ -0,0 +1,117 @@
+#
+# For a description of the syntax of this configuration file,
+# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
+#
+
+config EXAMPLES_NXPLAYER
+       bool "NxPlayer Media Player"
+       default n
+       depends on AUDIO
+       ---help---
+               Enable support for the NxPlayer media player library and optional
+               command line interface.
+
+if EXAMPLES_NXPLAYER
+
+config NXPLAYER_PLAYTHREAD_STACKSIZE
+       int "NxPlayer thread stack size"
+       default 1500
+       ---help---
+               Stack size to use with the NxPlayer play thread.
+
+config NXPLAYER_COMMAND_LINE
+       bool "Include nxplayer command line application"
+       default y
+       ---help---
+               Compiles in code for the nxplayer command line control.
+               This is a text-based command line interface that uses
+               the nxplayer library to play media files, control the
+               volume, balance, bass, etc.
+
+if NXPLAYER_COMMAND_LINE
+
+config NXPLAYER_INCLUDE_HELP
+       bool "Include HELP command and text"
+       default y
+       ---help---
+               Compiles in the NxPlayer help text to provide online help
+               for available commands with syntax.
+
+endif
+
+config NXPLAYER_INCLUDE_DEVICE_SEARCH
+       bool "Include audio device search code"
+       default y
+       ---help---
+               Compiles in extra code to search the audio device directory
+               for a suitable audio device to play the specified file.
+               Disabling this feature saves some code space, but it will
+               mean the calling application must specify the path of the
+               audio device to use before performing any other operations.
+
+config NXPLAYER_INCLUDE_PREFERRED_DEVICE
+       bool "Include preferred audio device specification code"
+       default y
+       ---help---
+               Adds support for identifying a specific audio device  to use
+               for audio operations.  If this feature is not enabled, then
+               an audio device search will be performed.
+
+config NXPLAYER_FMT_FROM_EXT
+       bool "Include code to determine Audio format from extension"
+       default y
+       ---help---
+               Compiles in extra code to determine audio format based
+               on the filename extension for known file types.
+               This feature is used if the format is not manually
+               specified, and will take priority over the more lengthy
+               file content detection approach.
+
+config NXPLAYER_FMT_FROM_HEADER
+       bool "Include code to find Audio format from file content"
+       default n
+       ---help---
+               Compiles in extra code to determine audio format based
+               on the header content of a file for known file types.
+               This feature is used when the format type cannot be
+               determined from the filename extension.
+
+config NXPLAYER_INCLUDE_MEDIADIR
+       bool "Include support for specifying a media directory"
+       default y
+       ---help---
+               Compiles in extra code to set a media directory which
+               will be searched when a request is made to play a file
+               which is not fully qualified.
+
+if NXPLAYER_INCLUDE_MEDIADIR
+
+config NXPLAYER_DEFAULT_MEDIADIR
+       string "Default root directory to search for media files"
+       default "/music"
+       ---help---
+               Specifies a root directory to search for media files
+               when an absolute path is not provided.  This can be
+               changed at the nxplayer command line, but will default
+               to this value each time nxplayer is launched.
+
+config NXPLAYER_RECURSIVE_MEDIA_SEARCH
+       bool "Perform recursive directory search for media files"
+       default n
+       ---help---
+               When enabled, this feature will add code to perform
+               a complete recursive directory search within the
+               MEDIADIR for any media files that do not have a
+               qualified path (i.e. contain no '/' characters).
+
+endif
+
+config NXPLAYER_INCLUDE_SYSTEM_RESET
+       bool "Include support for system / hardware reset"
+       default n
+       ---help---
+               When enabled, this feature will add code to enable issuing
+               a HW reset via program call.  The system reset will perform
+               a reset on all registered audio devices.
+
+endif
diff --git a/apps/examples/nxplayer/Make.defs b/apps/examples/nxplayer/Make.defs
new file mode 100644 (file)
index 0000000..ca4a04b
--- /dev/null
@@ -0,0 +1,22 @@
+###########################################################################
+#
+# Copyright 2017 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+
+ifeq ($(CONFIG_SYSTEM_NXPLAYER),y)
+CONFIGURED_APPS += examples/nxplayer
+endif
+
diff --git a/apps/examples/nxplayer/Makefile b/apps/examples/nxplayer/Makefile
new file mode 100644 (file)
index 0000000..cdf0e8a
--- /dev/null
@@ -0,0 +1,158 @@
+###########################################################################
+#
+# Copyright 2017 Samsung Electronics All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+# either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+#
+###########################################################################
+############################################################################
+# apps/examples/nxplayer/Makefile
+#
+#   Copyright (C) 2013 Ken Pettit. All rights reserved.
+#   Copyright (C) 2012-2013, 2016 Gregory Nutt. All rights reserved.
+#   Author: Ken Pettit <pettitkd@gmail.com>
+#           Gregory Nutt <gnutt@nuttx.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+
+# built-in application info
+
+APPNAME = nxplayer
+THREADEXEC = TASH_EXECMD_SYNC
+
+ASRCS =
+CSRCS = nxplayer.c
+MAINSRC = nxplayer_main.c
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
+OBJS = $(AOBJS) $(COBJS)
+
+ifneq ($(CONFIG_BUILD_KERNEL),y)
+  OBJS += $(MAINOBJ)
+endif
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+  BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+  BIN = ..\\..\\libapps$(LIBEXT)
+else
+  BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ifeq ($(WINTOOL),y)
+  INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}"
+else
+  INSTALL_DIR = $(BIN_DIR)
+endif
+
+CONFIG_EXAMPLES_NXPLAYER_PROGNAME ?= nxplayer$(EXEEXT)
+PROGNAME = $(CONFIG_EXAMPLES_NXPLAYER_PROGNAME)
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: clean depend distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+       $(call ASSEMBLE, $<, $@)
+
+$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c
+       $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+       $(call ARCHIVE, $(BIN), $(OBJS))
+       @touch .built
+
+ifeq ($(CONFIG_BUILD_KERNEL),y)
+$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ)
+       @echo "LD: $(PROGNAME)"
+       $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
+       $(Q) $(NM) -u  $(INSTALL_DIR)$(DELIM)$(PROGNAME)
+
+install: $(BIN_DIR)$(DELIM)$(PROGNAME)
+
+else
+install:
+
+endif
+
+ifeq ($(CONFIG_BUILTIN_APPS)$(CONFIG_SYSTEM_NXPLAYER),yy)
+$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile
+       $(call REGISTER,$(APPNAME),$(APPNAME)_main,$(THREADEXEC))
+
+context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat
+
+else
+context:
+
+endif
+
+.depend: Makefile $(SRCS)
+       @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
+       @touch $@
+
+depend: .depend
+
+clean:
+       $(call DELFILE, .built)
+       $(call CLEAN)
+
+distclean: clean
+       $(call DELFILE, Make.dep)
+       $(call DELFILE, .depend)
+
+-include Make.dep
+.PHONY: preconfig
+preconfig:
diff --git a/apps/examples/nxplayer/README.txt b/apps/examples/nxplayer/README.txt
new file mode 100644 (file)
index 0000000..32d1f20
--- /dev/null
@@ -0,0 +1,17 @@
+NXPlayer
+========
+
+    Source: NuttX
+    Author: Ken Pettit
+    Date: 11 Sept 2013
+
+This application implements a command-line media player
+which uses the NuttX Audio system to play files (mp3,
+wav, etc.) from the file system.
+
+Usage:
+    nxplayer
+
+The application presents an command line for specifying
+player commands, such as "play filename", "pause",
+"volume 50%", etc.
diff --git a/apps/examples/nxplayer/nxplayer.c b/apps/examples/nxplayer/nxplayer.c
new file mode 100644 (file)
index 0000000..1eb93a0
--- /dev/null
@@ -0,0 +1,1974 @@
+/****************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * apps/examples/nxplayer/nxplayer.c
+ *
+ * Developed by:
+ *
+ *   Copyright (C) 2013 Ken Pettit. All rights reserved.
+ *   Author: Ken Pettit <pettitkd@gmail.com>
+ *
+ * With ongoing support:
+ *
+ *   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ *   Author: Greory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <debug.h>
+
+#include <tinyara/audio/audio.h>
+#include <apps/nxplayer.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NXPLAYER_STATE_IDLE      0
+#define NXPLAYER_STATE_PLAYING   1
+#define NXPLAYER_STATE_PAUSED    2
+
+#ifndef CONFIG_AUDIO_NUM_BUFFERS
+#define CONFIG_AUDIO_NUM_BUFFERS  2
+#endif
+
+#ifndef CONFIG_AUDIO_BUFFER_NUMBYTES
+#define CONFIG_AUDIO_BUFFER_NUMBYTES  8192
+#endif
+
+#ifndef CONFIG_NXPLAYER_MSG_PRIO
+#define CONFIG_NXPLAYER_MSG_PRIO  1
+#endif
+
+#ifndef CONFIG_NXPLAYER_PLAYTHREAD_STACKSIZE
+#define CONFIG_NXPLAYER_PLAYTHREAD_STACKSIZE    1500
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+struct nxplayer_ext_fmt_s {
+       const char *ext;
+       uint16_t format;
+       CODE int (*getsubformat)(FAR FILE *fd);
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_AUDIO_FORMAT_MIDI
+int nxplayer_getmidisubformat(FAR FILE *fd);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+static const struct nxplayer_ext_fmt_s g_known_ext[] = {
+#ifdef CONFIG_AUDIO_FORMAT_AC3
+       {"ac3", AUDIO_FMT_AC3, NULL},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_MP3
+       {"mp3", AUDIO_FMT_MP3, NULL},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_DTS
+       {"dts", AUDIO_FMT_DTS, NULL},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_WMA
+       {"wma", AUDIO_FMT_WMA, NULL},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_PCM
+       {"wav", AUDIO_FMT_PCM, NULL},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_MIDI
+       {"mid", AUDIO_FMT_MIDI, nxplayer_getmidisubformat},
+       {"midi", AUDIO_FMT_MIDI, nxplayer_getmidisubformat},
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_OGG_VORBIS
+       {"ogg", AUDIO_FMT_OGG_VORBIS, NULL}
+#endif
+};
+
+static const int g_known_ext_count = sizeof(g_known_ext) / sizeof(struct nxplayer_ext_fmt_s);
+#endif                                                 /* CONFIG_NXPLAYER_FMT_FROM_EXT */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxplayer_opendevice
+ *
+ *   nxplayer_opendevice() either searches the Audio system for a device
+ *   that is compatible with the specified audio format and opens it, or
+ *   tries to open the prefered device if specified and validates that
+ *   it supports the requested format.
+ *
+ * Return:
+ *    OK        if compatible device opened (searched or preferred)
+ *    -ENODEV   if no compatible device opened.
+ *    -ENOENT   if preferred device couldn't be opened.
+ *
+ ****************************************************************************/
+
+static int nxplayer_opendevice(FAR struct nxplayer_s *pPlayer, int format, int subfmt)
+{
+       /* If we have a preferred device, then open it */
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+       if (pPlayer->prefdevice[0] != '\0') {
+               /* Use the saved prefformat to test if the requested
+                * format is specified by the device
+                */
+
+               if ((pPlayer->prefformat & (1 << (format - 1))) == 0 || (pPlayer->preftype & AUDIO_TYPE_OUTPUT) == 0) {
+                       /* Format not supported by the device */
+
+                       auddbg("ERROR: Format not supported by device: %d\n", format);
+                       return -ENODEV;
+               }
+
+               /* Device supports the format.  Open the device file. */
+
+               pPlayer->devFd = open(pPlayer->prefdevice, O_RDWR);
+               if (pPlayer->devFd == -1) {
+                       int errcode = errno;
+                       DEBUGASSERT(errcode > 0);
+
+                       auddbg("ERROR: Failed to open %s: %d\n", -errcode);
+                       UNUSED(errcode);
+                       return -ENOENT;
+               }
+
+               return OK;
+       }
+#endif
+
+#if defined(CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE) && \
+    defined(CONFIG_NXPLAYER_INCLUDE_DEVICE_SEARCH)
+
+       else
+#endif
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_DEVICE_SEARCH
+       {
+               struct audio_caps_s caps;
+               FAR struct dirent *pDevice;
+               FAR DIR *dirp;
+               char path[64];
+               uint8_t supported = true;
+               uint8_t x;
+
+               /* Search for a device in the audio device directory */
+
+#ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
+#ifdef CONFIG_AUDIO_DEV_ROOT
+               dirp = opendir("/dev");
+#else
+               dirp = opendir(CONFIG_AUDIO_DEV_PATH);
+#endif                                                 /* CONFIG_AUDIO_DEV_ROOT */
+#else
+               dirp = opendir("/dev/audio");
+#endif                                                 /* CONFIG_AUDIO_CUSTOM_DEV_PATH */
+               if (dirp == NULL) {
+                       int errcode = errno;
+                       DEBUGASSERT(errcode > 0);
+
+                       auddbg("ERROR: Failed to open /dev/audio: %d\n", -errcode);
+                       UNUSED(errcode);
+                       return -ENODEV;
+               }
+
+               while ((pDevice = readdir(dirp)) != NULL) {
+                       /* We found the next device.  Try to open it and
+                        * get its audio capabilities.
+                        */
+
+#ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
+#ifdef CONFIG_AUDIO_DEV_ROOT
+                       snprintf(path, sizeof(path), "/dev/%s", pDevice->d_name);
+#else
+                       snprintf(path, sizeof(path), CONFIG_AUDIO_DEV_PATH "/%s", pDevice->d_name);
+#endif                                                 /* CONFIG_AUDIO_DEV_ROOT */
+#else
+                       snprintf(path, sizeof(path), "/dev/audio/%s", pDevice->d_name);
+#endif                                                 /* CONFIG_AUDIO_CUSTOM_DEV_PATH */
+
+                       if ((pPlayer->devFd = open(path, O_RDWR)) != -1) {
+                               /* We have the device file open.  Now issue an AUDIO ioctls to
+                                * get the capabilities
+                                */
+
+                               caps.ac_len = sizeof(caps);
+                               caps.ac_type = AUDIO_TYPE_QUERY;
+                               caps.ac_subtype = AUDIO_TYPE_QUERY;
+
+                               if (ioctl(pPlayer->devFd, AUDIOIOC_GETCAPS, (unsigned long)&caps)
+                                       == caps.ac_len) {
+                                       /* Test if this device supports the format we want */
+
+                                       if (((caps.ac_format.hw & (1 << (format - 1))) != 0) && (caps.ac_controls.b[0] & AUDIO_TYPE_OUTPUT)) {
+                                               /* Do subformat detection */
+
+                                               if (subfmt != AUDIO_FMT_UNDEF) {
+                                                       /* Prepare to get sub-formats for this main format */
+
+                                                       caps.ac_subtype = format;
+                                                       caps.ac_format.b[0] = 0;
+
+                                                       while (ioctl(pPlayer->devFd, AUDIOIOC_GETCAPS, (unsigned long)&caps) == caps.ac_len) {
+                                                               /* Check the next set of 4 controls to find the subformat */
+
+                                                               for (x = 0; x < sizeof(caps.ac_controls); x++) {
+                                                                       if (caps.ac_controls.b[x] == subfmt) {
+                                                                               /* Sub format supported! */
+
+                                                                               break;
+                                                                       } else if (caps.ac_controls.b[x] == AUDIO_SUBFMT_END) {
+                                                                               /* Sub format not supported */
+
+                                                                               supported = false;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               /* If we reached the end of the subformat list, then
+                                                                * break out of the loop.
+                                                                */
+
+                                                               if (x != sizeof(caps.ac_controls)) {
+                                                                       break;
+                                                               }
+
+                                                               /* Increment ac_format.b[0] to get next set of subformats */
+
+                                                               caps.ac_format.b[0]++;
+                                                       }
+                                               }
+
+                                               /* Test if subformat needed and detected */
+
+                                               if (supported) {
+                                                       /* Yes, it supports this format.  Use this device */
+
+                                                       closedir(dirp);
+                                                       return OK;
+                                               }
+                                       }
+                               }
+
+                               /* Not this device! */
+
+                               close(pPlayer->devFd);
+                       }
+               }
+
+               /* Close the directory */
+
+               closedir(dirp);
+       }
+#endif                                                 /* CONFIG_NXPLAYER_INCLUDE_DEVICE_SEARCH */
+
+       /* Device not found */
+
+       auddbg("ERROR: Device not found\n");
+       pPlayer->devFd = -1;
+       return -ENODEV;
+}
+
+/****************************************************************************
+ * Name: nxplayer_getmidisubformat
+ *
+ *   nxplayer_getmidisubformat() reads the MIDI header and determins the
+ *   MIDI format of the file.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_AUDIO_FORMAT_MIDI
+int nxplayer_getmidisubformat(FAR FILE *fd)
+{
+       char type[2];
+       int ret;
+
+       /* Seek to location 8 in the file (the format type) */
+
+       fseek(fd, 8, SEEK_SET);
+       fread(type, 1, 2, fd);
+
+       /* Set return value based on type */
+
+       switch (type[1]) {
+       case 0:
+               ret = AUDIO_SUBFMT_MIDI_0;
+               break;
+
+       case 1:
+               ret = AUDIO_SUBFMT_MIDI_1;
+               break;
+
+       case 2:
+               ret = AUDIO_SUBFMT_MIDI_2;
+               break;
+       }
+       fseek(fd, 0, SEEK_SET);
+
+       return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_fmtfromextension
+ *
+ *   nxplayer_fmtfromextension() tries to determine the file format based
+ *   on the extension of the supplied filename.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+static inline int nxplayer_fmtfromextension(FAR struct nxplayer_s *pPlayer,
+                                            FAR const char *pFilename,
+                                            FAR int *subfmt)
+{
+       const char *pExt;
+       uint8_t x;
+       uint8_t c;
+
+       /* Find the file extension, if any */
+
+       x = strlen(pFilename) - 1;
+       while (x > 0) {
+               /* Seach backward for the first '.' */
+
+               if (pFilename[x] == '.') {
+                       /* First '.' found.  Now compare with known extensions */
+
+                       pExt = &pFilename[x + 1];
+                       for (c = 0; c < g_known_ext_count; c++) {
+                               /* Test for extension match */
+
+                               if (strcasecmp(pExt, g_known_ext[c].ext) == 0) {
+                                       /* Test if we have a sub-format detection routine */
+
+                                       if (subfmt && g_known_ext[c].getsubformat) {
+                                               *subfmt = g_known_ext[c].getsubformat(pPlayer->fileFd);
+                                       }
+
+                                       /* Return the format for this extension */
+
+                                       return g_known_ext[c].format;
+                               }
+                       }
+               }
+
+               /* Stop if we find a '/' */
+
+               if (pFilename[x] == '/') {
+                       break;
+               }
+
+               x--;
+       }
+
+       return AUDIO_FMT_UNDEF;
+}
+#endif                                                 /* CONFIG_NXPLAYER_FMT_FROM_EXT */
+
+/****************************************************************************
+ * Name: nxplayer_fmtfromheader
+ *
+ *   nxplayer_fmtfromheader() tries to determine the file format by checking
+ *   the file header for known file types.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_HEADER
+static int nxplayer_fmtfromheader(FAR struct nxplayer_s *pPlayer)
+{
+       return AUDIO_FMT_UNDEF;
+}
+#endif                                                 /* CONFIG_NXPLAYER_FMT_FROM_HEADER */
+
+/****************************************************************************
+ * Name: nxplayer_mediasearch
+ *
+ *   nxplayer_mediasearch() searches the subdirectories in the mediadir
+ *   for the specified media file.  We borrow the caller's path stack
+ *   variable (playfile) to conserve stack space.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NXPLAYER_MEDIA_SEARCH) && defined(CONFIG_NXPLAYER_INCLUDE_MEDIADIR)
+static int nxplayer_mediasearch(FAR struct nxplayer_s *pPlayer,
+                                FAR const char *pFilename,
+                                FAR const char *path, int pathmax)
+{
+       return -ENOENT;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_readbuffer
+ *
+ *  Read the next block of data from the media file into the specified
+ *  buffer.
+ *
+ ****************************************************************************/
+
+static int nxplayer_readbuffer(FAR struct nxplayer_s *pPlayer,
+                               FAR struct ap_buffer_s* apb)
+{
+       /* Validate the file is still open.  It will be closed automatically when
+        * we encounter the end of file (or, perhaps, a read error that we cannot
+        * handle.
+        */
+
+       if (pPlayer->fileFd == NULL) {
+               /* Return -ENODATA to indicate that there is nothing more to read from
+                * the file.
+                */
+
+               return -ENODATA;
+       }
+
+       /* Read data into the buffer. */
+
+       apb->nbytes = fread(&apb->samp, 1, apb->nmaxbytes, pPlayer->fileFd);
+       apb->curbyte = 0;
+       apb->flags = 0;
+
+       if (apb->nbytes < apb->nmaxbytes) {
+#ifdef CONFIG_DEBUG
+               int errcode = errno;
+               int readerror = ferror(pPlayer->fileFd);
+
+               audvdbg("Closing audio file, nbytes=%d readerr=%d\n", apb->nbytes, readerror);
+#endif
+
+               /* End of file or read error.. We are finished with this file in any
+                * event.
+                */
+
+               fclose(pPlayer->fileFd);
+               pPlayer->fileFd = NULL;
+
+               /* Set a flag to indicate that this is the final buffer in the stream */
+
+               apb->flags |= AUDIO_APB_FINAL;
+
+#ifdef CONFIG_DEBUG
+               /* Was this a file read error */
+
+               if (apb->nbytes == 0 && readerror) {
+                       DEBUGASSERT(errcode > 0);
+                       auddbg("ERROR: fread failed: %d\n", errcode);
+               }
+#endif
+       }
+
+       /* Return OK to indicate that the buffer should be passed through to the
+        * audio device.  This does not necessarily indicate that data was read
+        * correctly.
+        */
+
+       return OK;
+}
+
+/****************************************************************************
+ * Name: nxplayer_enqueuebuffer
+ *
+ * Description:
+ *   Enqueue the audio buffer in the downstream device.  Normally we are
+ *   called with a buffer of data to be enqueued in the audio stream.
+ *
+ *   Be we may also receive an empty length buffer (with only the
+ *   AUDIO_APB_FINAL set) in the event of certin read error occurs or in the
+ *   event that the file was an exact multiple of the nmaxbytes size of the
+ *   audio buffer.  In that latter case, we have an end of file with no bytes
+ *   read.
+ *
+ *   These infrequent zero length buffers have to be passed through because
+ *   the include the AUDIO_APB_FINAL flag that is needed to terminate the
+ *   audio stream.
+ *
+ ****************************************************************************/
+
+static int nxplayer_enqueuebuffer(FAR struct nxplayer_s *pPlayer,
+                                  FAR struct ap_buffer_s* apb)
+{
+       struct audio_buf_desc_s bufdesc;
+       int ret;
+
+       /* Now enqueue the buffer with the audio device.  If the number of
+        * bytes in the file happens to be an exact multiple of the audio
+        * buffer size, then we will receive the last buffer size = 0.  We
+        * encode this buffer also so the audio system knows its the end of
+        * the file and can do proper clean-up.
+        */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       bufdesc.session = pPlayer->session;
+#endif
+       bufdesc.numbytes = apb->nbytes;
+       bufdesc.u.pBuffer = apb;
+
+       ret = ioctl(pPlayer->devFd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)&bufdesc);
+       if (ret < 0) {
+               int errcode = errno;
+               DEBUGASSERT(errcode > 0);
+
+               auddbg("ERROR: AUDIOIOC_ENQUEUEBUFFER ioctl failed: %d\n", errcode);
+               return -errcode;
+       }
+
+       /* Return OK to indicate that we successfully read data from the file
+        * (and we are not yet at the end of file)
+        */
+
+       return OK;
+}
+
+/****************************************************************************
+ * Name: nxplayer_thread_playthread
+ *
+ *  This is the thread that reads the audio file file and enqueues /
+ *  dequeues buffers to the selected and opened audio device.
+ *
+ ****************************************************************************/
+
+static void *nxplayer_playthread(pthread_addr_t pvarg)
+{
+       struct nxplayer_s *pPlayer = (struct nxplayer_s *)pvarg;
+       struct audio_msg_s msg;
+       struct audio_buf_desc_s buf_desc;
+       ssize_t size;
+       bool running = true;
+       bool streaming = true;
+       bool failed = false;
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+       struct ap_buffer_info_s buf_info;
+       FAR struct ap_buffer_s **pBuffers;
+#else
+       FAR struct ap_buffer_s *pBuffers[CONFIG_AUDIO_NUM_BUFFERS];
+#endif
+#ifdef CONFIG_DEBUG
+       int outstanding = 0;
+#endif
+       int prio;
+       int x;
+       int ret;
+
+       audvdbg("Entry\n");
+
+       /* Query the audio device for it's preferred buffer size / qty */
+
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+       if ((ret = ioctl(pPlayer->devFd, AUDIOIOC_GETBUFFERINFO, (unsigned long)&buf_info)) != OK) {
+               /* Driver doesn't report it's buffer size.  Use our default. */
+
+               buf_info.buffer_size = CONFIG_AUDIO_BUFFER_NUMBYTES;
+               buf_info.nbuffers = CONFIG_AUDIO_NUM_BUFFERS;
+       }
+
+       /* Create array of pointers to buffers */
+
+       pBuffers = (FAR struct ap_buffer_s **)malloc(buf_info.nbuffers * sizeof(FAR void *));
+       if (pBuffers == NULL) {
+               /* Error allocating memory for buffer storage! */
+
+               ret = -ENOMEM;
+               running = false;
+               goto err_out;
+       }
+
+       /* Create our audio pipeline buffers to use for queueing up data */
+
+       for (x = 0; x < buf_info.nbuffers; x++) {
+               pBuffers[x] = NULL;
+       }
+
+       for (x = 0; x < buf_info.nbuffers; x++)
+#else                                                  /* CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFER */
+
+       for (x = 0; x < CONFIG_AUDIO_NUM_BUFFERS; x++) {
+               pBuffers[x] = NULL;
+       }
+
+       for (x = 0; x < CONFIG_AUDIO_NUM_BUFFERS; x++)
+#endif                                                 /* CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFER */
+       {
+               /* Fill in the buffer descriptor struct to issue an alloc request */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               buf_desc.session = pPlayer->session;
+#endif
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+               buf_desc.numbytes = buf_info.buffer_size;
+#else
+               buf_desc.numbytes = CONFIG_AUDIO_BUFFER_NUMBYTES;
+#endif
+               buf_desc.u.ppBuffer = &pBuffers[x];
+
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_ALLOCBUFFER, (unsigned long)&buf_desc);
+               if (ret != sizeof(buf_desc)) {
+                       /* Buffer alloc Operation not supported or error allocating! */
+
+                       auddbg("ERROR: Could not allocate buffer %d\n", x);
+                       running = false;
+                       goto err_out;
+               }
+       }
+
+       /* Fill up the pipeline with enqueued buffers */
+
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+       for (x = 0; x < buf_info.nbuffers; x++)
+#else
+       for (x = 0; x < CONFIG_AUDIO_NUM_BUFFERS; x++)
+#endif
+       {
+               /* Read the next buffer of data */
+
+               ret = nxplayer_readbuffer(pPlayer, pBuffers[x]);
+               if (ret != OK) {
+                       /* nxplayer_readbuffer will return an error if there is no further
+                        * data to be read from the file.  This can happen normally if the
+                        * file is very small (less than will fit in
+                        * CONFIG_AUDIO_NUM_BUFFERS) or if an error occurs trying to read
+                        * from the file.
+                        */
+
+                       /* We are no longer streaming data from the file */
+
+                       streaming = false;
+
+                       if (x == 0) {
+                               /* No buffers read?  Should never really happen.  Even in the
+                                * case of a read failure, one empty buffer containing the
+                                * AUDIO_APB_FINAL indication will be returned.
+                                */
+
+                               running = false;
+                       }
+               }
+
+               /* Enqueue buffer by sending it to the audio driver */
+
+               else {
+                       ret = nxplayer_enqueuebuffer(pPlayer, pBuffers[x]);
+                       if (ret != OK) {
+                               /* Failed to enqueue the buffer.  The driver is not happy with
+                                * the buffer.  Perhaps a decoder has detected something that it
+                                * does not like in the stream and has stopped streaming.  This
+                                * would happen normally if we send a file in the incorrect format
+                                * to an audio decoder.
+                                *
+                                * We must stop streaming as gracefully as possible.  Close the
+                                * file so that no further data is read.
+                                */
+
+                               fclose(pPlayer->fileFd);
+                               pPlayer->fileFd = NULL;
+
+                               /* We are no longer streaming data from the file.  Be we will
+                                * need to wait for any outstanding buffers to be recovered.  We
+                                * also still expect the audio driver to send a AUDIO_MSG_COMPLETE
+                                * message after all queued buffers have been returned.
+                                */
+
+                               streaming = false;
+                               failed = true;
+                               break;
+                       }
+#ifdef CONFIG_DEBUG
+                       else {
+                               /* The audio driver has one more buffer */
+
+                               outstanding++;
+                       }
+#endif
+               }
+       }
+
+       audvdbg("%d buffers queued, running=%d streaming=%d\n", x, running, streaming);
+
+       /* Start the audio device */
+
+       if (running && !failed) {
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_START, (unsigned long)pPlayer->session);
+#else
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_START, 0);
+#endif
+
+               if (ret < 0) {
+                       /* Error starting the audio stream!  We need to continue running
+                        * in order to recover the audio buffers that have already been
+                        * queued.
+                        */
+
+                       failed = true;
+               }
+       }
+
+       if (running && !failed) {
+               /* Indicate we are playing a file */
+
+               pPlayer->state = NXPLAYER_STATE_PLAYING;
+
+               /* Set initial parameters such as volume, bass, etc.
+                * REVISIT:  Shouldn't this actually be done BEFORE we start playing?
+                */
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+               (void)nxplayer_setvolume(pPlayer, pPlayer->volume);
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+               nxplayer_setbalance(pPlayer, pPlayer->balance);
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+               nxplayer_setbass(pPlayer, pPlayer->bass);
+               nxplayer_settreble(pPlayer, pPlayer->treble);
+#endif
+       }
+
+       /* Loop until we specifically break.  running == true means that we are
+        * still looping waiting for the playback to complete.  All of the file
+        * data may have been sent (if streaming == false), but the playback is
+        * not complete until we get the AUDIO_MSG_COMPLETE (or AUDIO_MSG_STOP)
+        * message
+        *
+        * The normal protocol for streaming errors detected by the audio driver
+        * is as follows:
+        *
+        * (1) The audio driver will indicated the error by returning a negated
+        *     error value when the next buffer is enqueued.  The upper level
+        *     then knows that this buffer was not queue.
+        * (2) The audio driver must return all queued buffers using the
+        *     AUDIO_MSG_DEQUEUE message, and
+        * (3) Terminate playing by sending the AUDIO_MSG_COMPLETE message.
+        */
+
+       audvdbg("%s\n", running ? "Playing..." : "Not runnning");
+       while (running) {
+               /* Wait for a signal either from the Audio driver that it needs
+                * additional buffer data, or from a user-space signal to pause,
+                * stop, etc.
+                */
+
+               size = mq_receive(pPlayer->mq, (FAR char *)&msg, sizeof(msg), &prio);
+
+               /* Validate a message was received */
+
+               if (size != sizeof(msg)) {
+                       /* Interrupted by a signal? What to do? */
+
+                       continue;
+               }
+
+               /* Perform operation based on message id */
+
+               switch (msg.msgId) {
+               /* An audio buffer is being dequeued by the driver */
+
+               case AUDIO_MSG_DEQUEUE:
+#ifdef CONFIG_DEBUG
+                       /* Make sure that we believe that the audio driver has at
+                        * least one buffer.
+                        */
+
+                       DEBUGASSERT(msg.u.pPtr && outstanding > 0);
+                       outstanding--;
+#endif
+
+                       /* Read data from the file directly into this buffer and
+                        * re-enqueue it.  streaming == true means that we have
+                        * not yet hit the end-of-file.
+                        */
+
+                       if (streaming) {
+                               /* Read the next buffer of data */
+
+                               ret = nxplayer_readbuffer(pPlayer, msg.u.pPtr);
+                               if (ret != OK) {
+                                       /* Out of data.  Stay in the loop until the device sends
+                                        * us a COMPLETE message, but stop trying to play more
+                                        * data.
+                                        */
+
+                                       streaming = false;
+                               }
+
+                               /* Enqueue buffer by sending it to the audio driver */
+
+                               else {
+                                       ret = nxplayer_enqueuebuffer(pPlayer, msg.u.pPtr);
+                                       if (ret != OK) {
+                                               /* There is some issue from the audio driver.
+                                                * Perhaps a problem in the file format?
+                                                *
+                                                * We must stop streaming as gracefully as possible.
+                                                * Close the file so that no further data is read.
+                                                */
+
+                                               fclose(pPlayer->fileFd);
+                                               pPlayer->fileFd = NULL;
+
+                                               /* Stop streaming and wait for buffers to be
+                                                * returned and to receive the AUDIO_MSG_COMPLETE
+                                                * indication.
+                                                */
+
+                                               streaming = false;
+                                               failed = true;
+                                       }
+#ifdef CONFIG_DEBUG
+                                       else {
+                                               /* The audio driver has one more buffer */
+
+                                               outstanding++;
+                                       }
+#endif
+                               }
+                       }
+                       break;
+
+               /* Someone wants to stop the playback. */
+
+               case AUDIO_MSG_STOP:
+                       /* Send a stop message to the device */
+
+                       audvdbg("Stopping! outstanding=%d\n", outstanding);
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+                       ioctl(pPlayer->devFd, AUDIOIOC_STOP, (unsigned long)pPlayer->session);
+#else
+                       ioctl(pPlayer->devFd, AUDIOIOC_STOP, 0);
+#endif
+                       /* Stay in the running loop (without sending more data).
+                        * we will need to recover our audio buffers.  We will
+                        * loop until AUDIO_MSG_COMPLETE is received.
+                        */
+
+                       streaming = false;
+                       break;
+
+               /* Message indicating the playback is complete */
+
+               case AUDIO_MSG_COMPLETE:
+                       audvdbg("Play complete.  outstanding=%d\n", outstanding);
+                       DEBUGASSERT(outstanding == 0);
+                       running = false;
+                       break;
+
+               /* Unknown / unsupported message ID */
+
+               default:
+                       break;
+               }
+       }
+
+       /* Release our audio buffers and unregister / release the device */
+
+err_out:
+       audvdbg("Clean-up and exit\n");
+
+       /* Unregister the message queue and release the session */
+
+       ioctl(pPlayer->devFd, AUDIOIOC_UNREGISTERMQ, (unsigned long)pPlayer->mq);
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       ioctl(pPlayer->devFd, AUDIOIOC_RELEASE, (unsigned long)pPlayer->session);
+#else
+       ioctl(pPlayer->devFd, AUDIOIOC_RELEASE, 0);
+#endif
+
+       /* Cleanup */
+
+       while (sem_wait(&pPlayer->sem) < 0) ;
+
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+       if (pBuffers != NULL) {
+               audvdbg("Freeing buffers\n");
+               for (x = 0; x < buf_info.nbuffers; x++) {
+                       /* Fill in the buffer descriptor struct to issue a free request */
+
+                       if (pBuffers[x] != NULL) {
+                               buf_desc.u.pBuffer = pBuffers[x];
+                               ioctl(pPlayer->devFd, AUDIOIOC_FREEBUFFER, (unsigned long)&buf_desc);
+                       }
+               }
+
+               /* Free the pointers to the buffers */
+
+               free(pBuffers);
+       }
+#else
+       audvdbg("Freeing buffers\n");
+       for (x = 0; x < CONFIG_AUDIO_NUM_BUFFERS; x++) {
+               /* Fill in the buffer descriptor struct to issue a free request */
+
+               if (pBuffers[x] != NULL) {
+                       buf_desc.u.pBuffer = pBuffers[x];
+                       ioctl(pPlayer->devFd, AUDIOIOC_FREEBUFFER, (unsigned long)&buf_desc);
+               }
+       }
+#endif
+
+       /* Close the files */
+
+       if (pPlayer->fileFd != NULL) {
+               fclose(pPlayer->fileFd);        /* Close the file */
+               pPlayer->fileFd = NULL; /* Clear out the FD */
+       }
+
+       close(pPlayer->devFd);          /* Close the device */
+       pPlayer->devFd = -1;            /* Mark device as closed */
+       mq_close(pPlayer->mq);          /* Close the message queue */
+       mq_unlink(pPlayer->mqname);     /* Unlink the message queue */
+       pPlayer->state = NXPLAYER_STATE_IDLE;   /* Go to IDLE */
+
+       sem_post(&pPlayer->sem);        /* Release the semaphore */
+
+       /* The playthread is done with the context.  Release it, which may
+        * actually cause the context to be freed if the creator has already
+        * abandoned (released) the context too.
+        */
+
+       nxplayer_release(pPlayer);
+
+       audvdbg("Exit\n");
+
+       return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxplayer_setvolume
+ *
+ *   nxplayer_setvolume() sets the volume.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+int nxplayer_setvolume(FAR struct nxplayer_s *pPlayer, uint16_t volume)
+{
+       struct audio_caps_desc_s cap_desc;
+       int ret;
+
+       /* Thread sync using the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) ;
+
+       /* If we are currently playing, then we need to post a message to
+        * the playthread to perform the volume change operation.  If we
+        * are not playing, then just store the volume setting and it will
+        * be applied before the next playback begins.
+        */
+
+       if (pPlayer->state == NXPLAYER_STATE_PLAYING) {
+               /* Send a CONFIGURE ioctl to the device to set the volume */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               cap_desc.session = pPlayer->session;
+#endif
+               cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+               cap_desc.caps.ac_type = AUDIO_TYPE_FEATURE;
+               cap_desc.caps.ac_format.hw = AUDIO_FU_VOLUME;
+               cap_desc.caps.ac_controls.hw[0] = volume;
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+               if (ret < 0) {
+                       int errcode = errno;
+                       DEBUGASSERT(errcode > 0);
+
+                       auddbg("ERROR: AUDIOIOC_CONFIGURE ioctl failed: %d\n", errcode);
+                       return -errcode;
+               }
+       }
+
+       /* Store the volume setting */
+
+       pPlayer->volume = volume;
+       sem_post(&pPlayer->sem);
+
+       return OK;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_VOLUME */
+
+/****************************************************************************
+ * Name: nxplayer_setequalization
+ *
+ *   Sets the level on each band of an equalizer.  Each band setting is
+ *   represented in one percent increments, so the range is 0-100.
+ *
+ * Input Parameters:
+ *   pPlayer      - Pointer to the context to initialize
+ *   equalization - Pointer to array of equalizer settings of size
+ *                  CONFIG_AUDIO_EQUALIZER_NBANDS bytes.  Each byte
+ *                  represents the setting for one band in the range of
+ *                  0-100.
+ *
+ * Returned Value:
+ *   OK if equalization was set correctly.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_EQUALIZER
+int nxplayer_setequalization(FAR struct nxplayer_s *pPlayer,
+                             FAR uint8_t *equalization)
+{
+#warning Missing logic
+       return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setbass
+ *
+ *   nxplayer_setbass() sets the bass level and range.
+ *
+ * Input:
+ *   pPlayer  - Pointer to the nxplayer context
+ *   level    - Bass level in percentage (0-100)
+ *   range    - Bass range in percentage (0-100)
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+int nxplayer_setbass(FAR struct nxplayer_s *pPlayer, uint8_t level)
+{
+       struct audio_caps_desc_s cap_desc;
+
+       /* Thread sync using the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) ;
+
+       /* If we are currently playing, then we need to post a message to
+        * the playthread to perform the volume change operation.  If we
+        * are not playing, then just store the bass setting and it will
+        * be applied before the next playback begins.
+        */
+
+       if (pPlayer->state == NXPLAYER_STATE_PLAYING) {
+               /* Send a CONFIGURE ioctl to the device to set the volume */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               cap_desc.session = pPlayer->session;
+#endif
+               cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+               cap_desc.caps.ac_type = AUDIO_TYPE_FEATURE;
+               cap_desc.caps.ac_format.hw = AUDIO_FU_BASS;
+               cap_desc.caps.ac_controls.b[0] = level;
+               ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+       }
+
+       /* Store the volume setting */
+
+       pPlayer->bass = level;
+
+       sem_post(&pPlayer->sem);
+
+       return -ENOENT;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_TONE */
+
+/****************************************************************************
+ * Name: nxplayer_settreble
+ *
+ *   nxplayer_settreble() sets the treble level and range.
+ *
+ * Input:
+ *   pPlayer  - Pointer to the nxplayer context
+ *   level    - Treble level in percentage (0-100)
+ *   range    - Treble range in percentage (0-100)
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+int nxplayer_settreble(FAR struct nxplayer_s *pPlayer, uint8_t level)
+{
+       struct audio_caps_desc_s cap_desc;
+
+       /* Thread sync using the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) ;
+
+       /* If we are currently playing, then we need to post a message to
+        * the playthread to perform the volume change operation.  If we
+        * are not playing, then just store the treble setting and it will
+        * be applied before the next playback begins.
+        */
+
+       if (pPlayer->state == NXPLAYER_STATE_PLAYING) {
+               /* Send a CONFIGURE ioctl to the device to set the volume */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               cap_desc.session = pPlayer->session;
+#endif
+               cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+               cap_desc.caps.ac_type = AUDIO_TYPE_FEATURE;
+               cap_desc.caps.ac_format.hw = AUDIO_FU_TREBLE;
+               cap_desc.caps.ac_controls.b[0] = level;
+               ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+       }
+
+       /* Store the volume setting */
+
+       pPlayer->treble = level;
+
+       sem_post(&pPlayer->sem);
+
+       return -ENOENT;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_TONE */
+
+/****************************************************************************
+ * Name: nxplayer_setbalance
+ *
+ *   nxplayer_setbalance() sets the volume.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+int nxplayer_setbalance(FAR struct nxplayer_s *pPlayer, uint16_t balance)
+{
+       struct audio_caps_desc_s cap_desc;
+
+       /* Thread sync using the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) ;
+
+       /* If we are currently playing, then we need to post a message to
+        * the playthread to perform the volume change operation.  If we
+        * are not playing, then just store the volume setting and it will
+        * be applied before the next playback begins.
+        */
+
+       if (pPlayer->state == NXPLAYER_STATE_PLAYING) {
+               /* Send a CONFIGURE ioctl to the device to set the volume */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               cap_desc.session = pPlayer->session;
+#endif
+               cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+               cap_desc.caps.ac_type = AUDIO_TYPE_FEATURE;
+               cap_desc.caps.ac_format.hw = AUDIO_FU_BALANCE;
+               cap_desc.caps.ac_controls.hw[0] = balance;
+               ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+       }
+
+       /* Store the volume setting */
+
+       pPlayer->balance = balance;
+
+       sem_post(&pPlayer->sem);
+
+       return -ENOENT;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_pause
+ *
+ *   nxplayer_pause() pauses playback without cancelling it.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+int nxplayer_pause(FAR struct nxplayer_s *pPlayer)
+{
+       int ret = OK;
+
+       if (pPlayer->state == NXPLAYER_STATE_PLAYING) {
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_PAUSE, (unsigned long)pPlayer->session);
+#else
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_PAUSE, 0);
+#endif
+               if (ret == OK) {
+                       pPlayer->state = NXPLAYER_STATE_PAUSED;
+               }
+       }
+
+       return ret;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
+
+/****************************************************************************
+ * Name: nxplayer_resume
+ *
+ *   nxplayer_resume() resumes playback after a pause operation.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+int nxplayer_resume(FAR struct nxplayer_s *pPlayer)
+{
+       int ret = OK;
+
+       if (pPlayer->state == NXPLAYER_STATE_PAUSED) {
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_RESUME, (unsigned long)pPlayer->session);
+#else
+               ret = ioctl(pPlayer->devFd, AUDIOIOC_RESUME, 0);
+#endif
+               if (ret == OK) {
+                       pPlayer->state = NXPLAYER_STATE_PLAYING;
+               }
+       }
+
+       return ret;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
+
+/****************************************************************************
+ * Name: nxplayer_fforward
+ *
+ *   Selects to fast forward in the audio data stream.  The fast forward
+ *   operation can be cancelled by simply selected no sub-sampling with
+ *   the AUDIO_SUBSAMPLE_NONE argument returning to normal 1x forward play.
+ *   This function may be called multiple times to change fast forward rate.
+ *
+ *   The preferred way to cancel a fast forward operation is via
+ *   nxplayer_cancel_motion() that provides the option to also return to
+ *   paused, non-playing state.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   subsample - Identifies the fast forward rate (in terms of sub-sampling,
+ *               but does not explicitly require sub-sampling).  See
+ *               AUDIO_SUBSAMPLE_* definitions.
+ *
+ * Returned Value:
+ *   OK if fast forward operation successful.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
+int nxplayer_fforward(FAR struct nxplayer_s *pPlayer, uint8_t subsample)
+{
+       struct audio_caps_desc_s cap_desc;
+       int ret;
+
+       DEBUGASSERT(pPlayer && subsample >= AUDIO_SUBSAMPLE_NONE && subsample <= AUDIO_SUBSAMPLE_MAX);
+
+       /* Send a CONFIGURE ioctl to the device to set the forward rate */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       cap_desc.session = pPlayer->session;
+#endif
+       cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+       cap_desc.caps.ac_type = AUDIO_TYPE_PROCESSING;
+       cap_desc.caps.ac_format.hw = AUDIO_PU_SUBSAMPLE_FORWARD;
+       cap_desc.caps.ac_controls.b[0] = subsample;
+
+       ret = ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+       if (ret < 0) {
+               int errcode = errno;
+               DEBUGASSERT(errcode > 0);
+
+               auddbg("ERROR: ioctl AUDIOIOC_CONFIGURE failed: %d\n", errcode);
+               ret = -errcode;
+       }
+
+       return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_rewind
+ *
+ *   Selects to rewind in the audio data stream.  The rewind operation must
+ *   be cancelled with nxplayer_cancel_motion.  This function may be called
+ *   multiple times to change rewind rate.
+ *
+ *   NOTE that cancellation of the rewind operation differs from
+ *   cancellation of the fast forward operation because we must both restore
+ *   the sub-sampling rate to 1x and also return to forward play.
+ *   AUDIO_SUBSAMPLE_NONE is not a valid argument to this function.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   subsample - Identifies the rewind rate (in terms of sub-sampling, but
+ *               does not explicitly require sub-sampling).  See
+ *               AUDIO_SUBSAMPLE_* definitions.
+ *
+ * Returned Value:
+ *   OK if rewind operation successfully initiated.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_REWIND
+int nxplayer_rewind(FAR struct nxplayer_s *pPlayer, uint8_t subsample)
+{
+       struct audio_caps_desc_s cap_desc;
+       int ret;
+
+       DEBUGASSERT(pPlayer && subsample >= AUDIO_SUBSAMPLE_MIN && subsample <= AUDIO_SUBSAMPLE_MAX);
+
+       /* Send a CONFIGURE ioctl to the device to set the forward rate */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       cap_desc.session = pPlayer->session;
+#endif
+       cap_desc.caps.ac_len = sizeof(struct audio_caps_s);
+       cap_desc.caps.ac_type = AUDIO_TYPE_PROCESSING;
+       cap_desc.caps.ac_format.hw = AUDIO_PU_SUBSAMPLE_REWIND;
+       cap_desc.caps.ac_controls.b[0] = subsample;
+
+       ret = ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
+       if (ret < 0) {
+               int errcode = errno;
+               DEBUGASSERT(errcode > 0);
+
+               auddbg("ERROR: ioctl AUDIOIOC_CONFIGURE failed: %d\n", errcode);
+               ret = -errcode;
+       }
+
+       return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cancel_motion
+ *
+ *   Cancel a rewind or fast forward operation and return to either the
+ *   paused state or to the normal, forward play state.
+ *
+ * Input Parameters:
+ *   pPlayer - Pointer to the context to initialize
+ *   paused  - True: return to the paused state, False: return to the 1X
+ *             forward play state.
+ *
+ * Returned Value:
+ *   OK if rewind operation successfully cancelled.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
+int nxplayer_cancel_motion(FAR struct nxplayer_s *pPlayer, bool paused)
+{
+       int ret;
+
+       /* I think this is equivalent to calling nxplayer_fforward with the
+        * argument AUDIO_SUBSAMPLE_NONE:  Forward motion with no sub-sampling.
+        *
+        * REVISIT: There is no way at present to cancel sub-sampling and return
+        * to pause atomically.
+        */
+
+       ret = nxplayer_fforward(pPlayer, AUDIO_SUBSAMPLE_NONE);
+       if (ret < 0) {
+               auddbg("ERROR: nxplayer_fforward failed: %d\n", ret);
+               return ret;
+       }
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+       if (paused) {
+               ret = nxplayer_pause(pPlayer);
+               if (ret < 0) {
+                       auddbg("ERROR: nxplayer_pause failed: %d\n", ret);
+                       return ret;
+               }
+       }
+#endif
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setdevice
+ *
+ *   nxplayer_setdevice() sets the perferred audio device to use with the
+ *   provided nxplayer context.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+int nxplayer_setdevice(FAR struct nxplayer_s *pPlayer, FAR const char *pDevice)
+{
+       int tempFd;
+       struct audio_caps_s caps;
+
+       DEBUGASSERT(pPlayer != NULL);
+       DEBUGASSERT(pDevice != NULL);
+
+       /* Try to open the device */
+
+       tempFd = open(pDevice, O_RDWR);
+       if (tempFd == -1) {
+               /* Error opening the device */
+
+               return -ENOENT;
+       }
+
+       /* Validate it's an Audio device by issuing an AUDIOIOC_GETCAPS ioctl */
+
+       caps.ac_len = sizeof(caps);
+       caps.ac_type = AUDIO_TYPE_QUERY;
+       caps.ac_subtype = AUDIO_TYPE_QUERY;
+       if (ioctl(tempFd, AUDIOIOC_GETCAPS, (unsigned long)&caps) != caps.ac_len) {
+               /* Not an Audio device! */
+
+               close(tempFd);
+               return -ENODEV;
+       }
+
+       /* Close the file */
+
+       close(tempFd);
+
+       /* Save the path and format capabilities of the preferred device */
+
+       strncpy(pPlayer->prefdevice, pDevice, sizeof(pPlayer->prefdevice));
+       pPlayer->prefformat = caps.ac_format.b[0] | (caps.ac_format.b[1] << 8);
+       pPlayer->preftype = caps.ac_controls.b[0];
+
+       return OK;
+}
+#endif                                                 /* CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE */
+
+/****************************************************************************
+ * Name: nxplayer_stop
+ *
+ *   nxplayer_stop() stops the current playback and closes the file and
+ *   the associated device.
+ *
+ * Input:
+ *   pPlayer    Pointer to the initialized MPlayer context
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+int nxplayer_stop(FAR struct nxplayer_s *pPlayer)
+{
+       struct audio_msg_s term_msg;
+       FAR void *value;
+
+       DEBUGASSERT(pPlayer != NULL);
+
+       /* Validate we are not in IDLE state */
+
+       sem_wait(&pPlayer->sem);        /* Get the semaphore */
+       if (pPlayer->state == NXPLAYER_STATE_IDLE) {
+               sem_post(&pPlayer->sem);        /* Release the semaphore */
+               return OK;
+       }
+
+       sem_post(&pPlayer->sem);
+
+       /* Notify the playback thread that it needs to cancel the playback */
+
+       term_msg.msgId = AUDIO_MSG_STOP;
+       term_msg.u.data = 0;
+       mq_send(pPlayer->mq, (FAR const char *)&term_msg, sizeof(term_msg), CONFIG_NXPLAYER_MSG_PRIO);
+
+       /* Join the thread.  The thread will do all the cleanup. */
+
+       pthread_join(pPlayer->playId, &value);
+       pPlayer->playId = 0;
+
+       return OK;
+}
+#endif                                                 /* CONFIG_AUDIO_EXCLUDE_STOP */
+
+/****************************************************************************
+ * Name: nxplayer_playfile
+ *
+ *   nxplayer_playfile() tries to play the specified file using the Audio
+ *   system.  If a preferred device is specified, it will try to use that
+ *   device otherwise it will perform a search of the Audio device files
+ *   to find a suitable device.
+ *
+ * Input:
+ *   pPlayer    Pointer to the initialized MPlayer context
+ *   pFilename  Pointer to the filename to play
+ *   filefmt    Format of the file or AUD_FMT_UNDEF if unknown / to be
+ *              determined by nxplayer_playfile()
+ *
+ * Returns:
+ *   OK         File is being played
+ *   -EBUSY     The media device is busy
+ *   -ENOSYS    The media file is an unsupported type
+ *   -ENODEV    No audio device suitable to play the media type
+ *   -ENOENT    The media file was not found
+ *
+ ****************************************************************************/
+
+int nxplayer_playfile(FAR struct nxplayer_s *pPlayer,
+                      FAR const char *pFilename, int filefmt, int subfmt)
+{
+       struct mq_attr attr;
+       struct sched_param sparam;
+       pthread_attr_t tattr;
+       void *value;
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+       char path[128];
+#endif
+       int tmpsubfmt = AUDIO_FMT_UNDEF;
+       int ret;
+
+       DEBUGASSERT(pPlayer != NULL);
+       DEBUGASSERT(pFilename != NULL);
+
+       if (pPlayer->state != NXPLAYER_STATE_IDLE) {
+               return -EBUSY;
+       }
+
+       audvdbg("==============================\n");
+       audvdbg("Playing file %s\n", pFilename);
+       audvdbg("==============================\n");
+
+       /* Test that the specified file exists */
+
+       if ((pPlayer->fileFd = fopen(pFilename, "r")) == NULL) {
+               /* File not found.  Test if its in the mediadir */
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+               snprintf(path, sizeof(path), "%s/%s", pPlayer->mediadir, pFilename);
+
+               if ((pPlayer->fileFd = fopen(path, "r")) == NULL) {
+#ifdef CONFIG_NXPLAYER_MEDIA_SEARCH
+                       /* File not found in the media dir.  Do a search */
+
+                       if (nxplayer_mediasearch(pPlayer, pFilename, path, sizeof(path)) != OK) {
+                               auddbg("ERROR: Could not find file\n");
+                               return -ENOENT;
+                       }
+#else
+                       auddbg("ERROR: Could not open %s or %s\n", pFilename, path);
+                       return -ENOENT;
+#endif                                                 /* CONFIG_NXPLAYER_MEDIA_SEARCH */
+               }
+#else                                                  /* CONFIG_NXPLAYER_INCLUDE_MEDIADIR */
+
+               auddbg("ERROR: Could not open %s\n", pFilename);
+               return -ENOENT;
+#endif                                                 /* CONFIG_NXPLAYER_INCLUDE_MEDIADIR */
+       }
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+       /* Try to determine the format of audio file based on the extension */
+
+       if (filefmt == AUDIO_FMT_UNDEF) {
+               filefmt = nxplayer_fmtfromextension(pPlayer, pFilename, &tmpsubfmt);
+       }
+#endif
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_HEADER
+       /* If type not identified, then test for known header types */
+
+       if (filefmt == AUDIO_FMT_UNDEF) {
+               filefmt = nxplayer_fmtfromheader(pPlayer, &subfmt, &tmpsubfmt);
+       }
+#endif
+
+       /* Test if we determined the file format */
+
+       if (filefmt == AUDIO_FMT_UNDEF) {
+               /* Hmmm, it's some unknown / unsupported type */
+
+               auddbg("ERROR: Unsupported format: %d \n", filefmt);
+               ret = -ENOSYS;
+               goto err_out_nodev;
+       }
+
+       /* Test if we have a sub format assignment from above */
+
+       if (subfmt == AUDIO_FMT_UNDEF) {
+               subfmt = tmpsubfmt;
+       }
+
+       /* Try to open the device */
+
+       ret = nxplayer_opendevice(pPlayer, filefmt, subfmt);
+       if (ret < 0) {
+               /* Error opening the device */
+
+               auddbg("ERROR: nxplayer_opendevice failed: %d\n", ret);
+               goto err_out_nodev;
+       }
+
+       /* Try to reserve the device */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       ret = ioctl(pPlayer->devFd, AUDIOIOC_RESERVE, (unsigned long)&pPlayer->session);
+#else
+       ret = ioctl(pPlayer->devFd, AUDIOIOC_RESERVE, 0);
+#endif
+       if (ret < 0) {
+               /* Device is busy or error */
+
+               auddbg("ERROR: Failed to reserve device: %d\n", ret);
+               ret = -errno;
+               goto err_out;
+       }
+
+       /* Create a message queue for the playthread */
+
+       attr.mq_maxmsg = 16;
+       attr.mq_msgsize = sizeof(struct audio_msg_s);
+       attr.mq_curmsgs = 0;
+       attr.mq_flags = 0;
+
+       snprintf(pPlayer->mqname, sizeof(pPlayer->mqname), "/tmp/%0lx", (unsigned long)((uintptr_t) pPlayer));
+
+       pPlayer->mq = mq_open(pPlayer->mqname, O_RDWR | O_CREAT, 0644, &attr);
+       if (pPlayer->mq == NULL) {
+               /* Unable to open message queue! */
+
+               ret = -errno;
+               auddbg("ERROR: mq_open failed: %d\n", ret);
+               goto err_out;
+       }
+
+       /* Register our message queue with the audio device */
+
+       ioctl(pPlayer->devFd, AUDIOIOC_REGISTERMQ, (unsigned long)pPlayer->mq);
+
+       /* Check if there was a previous thread and join it if there was
+        * to perform clean-up.
+        */
+
+       if (pPlayer->playId != 0) {
+               pthread_join(pPlayer->playId, &value);
+       }
+
+       /* Start the playfile thread to stream the media file to the
+        * audio device.
+        */
+
+       pthread_attr_init(&tattr);
+       sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
+       (void)pthread_attr_setschedparam(&tattr, &sparam);
+       (void)pthread_attr_setstacksize(&tattr, CONFIG_NXPLAYER_PLAYTHREAD_STACKSIZE);
+
+       /* Add a reference count to the player for the thread and start the
+        * thread.  We increment for the thread to avoid thread start-up
+        * race conditions.
+        */
+
+       nxplayer_reference(pPlayer);
+       ret = pthread_create(&pPlayer->playId, &tattr, nxplayer_playthread, (pthread_addr_t) pPlayer);
+       if (ret != OK) {
+               auddbg("ERROR: Failed to create playthread: %d\n", ret);
+               goto err_out;
+       }
+
+       /* Name the thread */
+
+       pthread_setname_np(pPlayer->playId, "playthread");
+       return OK;
+
+err_out:
+       close(pPlayer->devFd);
+       pPlayer->devFd = -1;
+
+err_out_nodev:
+       if (pPlayer->fileFd != NULL) {
+               fclose(pPlayer->fileFd);
+               pPlayer->fileFd = NULL;
+       }
+
+       return ret;
+}
+
+/****************************************************************************
+ * Name: nxplayer_setmediadir
+ *
+ *   nxplayer_setmediadir() sets the root path for media searches.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+void nxplayer_setmediadir(FAR struct nxplayer_s *pPlayer,
+                                                 FAR const char *mediadir)
+{
+       strncpy(pPlayer->mediadir, mediadir, sizeof(pPlayer->mediadir));
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_create
+ *
+ *   nxplayer_create() allocates and initializes a nxplayer context for
+ *   use by further nxplayer operations.  This routine must be called before
+ *   to perform the create for proper reference counting.
+ *
+ * Input Parameters:  None
+ *
+ * Returned values:
+ *   Pointer to the created context or NULL if there was an error.
+ *
+ ****************************************************************************/
+
+FAR struct nxplayer_s *nxplayer_create(void)
+{
+       FAR struct nxplayer_s *pPlayer;
+
+       /* Allocate the memory */
+
+       pPlayer = (FAR struct nxplayer_s *)malloc(sizeof(struct nxplayer_s));
+       if (pPlayer == NULL) {
+               return NULL;
+       }
+
+       /* Initialize the context data */
+
+       pPlayer->state = NXPLAYER_STATE_IDLE;
+       pPlayer->devFd = -1;
+       pPlayer->fileFd = NULL;
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+       pPlayer->prefdevice[0] = '\0';
+       pPlayer->prefformat = 0;
+       pPlayer->preftype = 0;
+#endif
+       pPlayer->mq = NULL;
+       pPlayer->playId = 0;
+       pPlayer->crefs = 1;
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+       pPlayer->bass = 50;
+       pPlayer->treble = 50;
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+       pPlayer->balance = 500;
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+       pPlayer->volume = 400;
+#endif
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       pPlayer->session = NULL;
+#endif
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+       strncpy(pPlayer->mediadir, CONFIG_NXPLAYER_DEFAULT_MEDIADIR, sizeof(pPlayer->mediadir));
+#endif
+       sem_init(&pPlayer->sem, 0, 1);
+
+       return pPlayer;
+}
+
+/****************************************************************************
+ * Name: nxplayer_release
+ *
+ *   nxplayer_release() reduces the reference count by one and if it
+ *   reaches zero, frees the context.
+ *
+ * Input Parameters:
+ *   pPlayer    Pointer to the NxPlayer context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxplayer_release(FAR struct nxplayer_s *pPlayer)
+{
+       int refcount;
+       FAR void *value;
+
+       /* Grab the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) {
+               int errcode = errno;
+               DEBUGASSERT(errcode > 0);
+
+               if (errcode != EINTR) {
+                       auddbg("ERROR: sem_wait failed: %d\n", errcode);
+                       return;
+               }
+       }
+
+       /* Check if there was a previous thread and join it if there was */
+
+       if (pPlayer->playId != 0) {
+               sem_post(&pPlayer->sem);
+               pthread_join(pPlayer->playId, &value);
+               pPlayer->playId = 0;
+
+               while (sem_wait(&pPlayer->sem) < 0) {
+                       int errcode = errno;
+                       DEBUGASSERT(errcode > 0);
+
+                       if (errcode != -EINTR) {
+                               auddbg("ERROR: sem_wait failed: %d\n", errcode);
+                               return;
+                       }
+               }
+       }
+
+       /* Reduce the reference count */
+
+       refcount = pPlayer->crefs--;
+       sem_post(&pPlayer->sem);
+
+       /* If the ref count *was* one, then free the context */
+
+       if (refcount == 1) {
+               free(pPlayer);
+       }
+}
+
+/****************************************************************************
+ * Name: nxplayer_reference
+ *
+ *   nxplayer_reference() increments the reference count by one.
+ *
+ * Input Parameters:
+ *   pPlayer    Pointer to the NxPlayer context
+ *
+ * Returned values:    None
+ *
+ ****************************************************************************/
+
+void nxplayer_reference(FAR struct nxplayer_s *pPlayer)
+{
+       /* Grab the semaphore */
+
+       while (sem_wait(&pPlayer->sem) < 0) {
+               int errcode = errno;
+               DEBUGASSERT(errcode > 0);
+
+               if (errcode != -EINTR) {
+                       auddbg("ERROR: sem_wait failed: %d\n", errcode);
+                       return;
+               }
+       }
+
+       /* Increment the reference count */
+
+       pPlayer->crefs++;
+       sem_post(&pPlayer->sem);
+}
+
+/****************************************************************************
+ * Name: nxplayer_systemreset
+ *
+ *   nxplayer_systemreset() performs a HW reset on all registered
+ *   audio devices.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+int nxplayer_systemreset(FAR struct nxplayer_s *pPlayer)
+{
+       struct dirent *pDevice;
+       DIR *dirp;
+       char path[64];
+
+       /* Search for a device in the audio device directory */
+
+#ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
+#ifdef CONFIG_AUDIO_DEV_ROOT
+       dirp = opendir("/dev");
+#else
+       dirp = opendir(CONFIG_AUDIO_DEV_PATH);
+#endif
+#else
+       dirp = opendir("/dev/audio");
+#endif
+       if (dirp == NULL) {
+               return -ENODEV;
+       }
+
+       while ((pDevice = readdir(dirp)) != NULL) {
+               /* We found the next device.  Try to open it and
+                * get its audio capabilities.
+                */
+
+#ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
+#ifdef CONFIG_AUDIO_DEV_ROOT
+               snprintf(path, sizeof(path), "/dev/%s", pDevice->d_name);
+#else
+               snprintf(path, sizeof(path), CONFIG_AUDIO_DEV_PATH "/%s", pDevice->d_name);
+#endif
+#else
+               snprintf(path, sizeof(path), "/dev/audio/%s", pDevice->d_name);
+#endif
+               if ((pPlayer->devFd = open(path, O_RDWR)) != -1) {
+                       /* We have the device file open.  Now issue an
+                        * AUDIO ioctls to perform a HW reset
+                        */
+
+                       ioctl(pPlayer->devFd, AUDIOIOC_HWRESET, 0);
+
+                       /* Now close the device */
+
+                       close(pPlayer->devFd);
+               }
+
+       }
+
+       pPlayer->devFd = -1;
+       return OK;
+}
+#endif                                                 /* CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET */
diff --git a/apps/examples/nxplayer/nxplayer_main.c b/apps/examples/nxplayer/nxplayer_main.c
new file mode 100644 (file)
index 0000000..6e5e995
--- /dev/null
@@ -0,0 +1,691 @@
+/****************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * apps/examples/nxplayer/nxplayer_main.c
+ *
+ *   Copyright (C) 2013 Ken Pettit. All rights reserved.
+ *   Author: Ken Pettit <pettitkd@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+#include <tinyara/audio/audio.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <apps/readline.h>
+#include <apps/nxplayer.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define        NXPLAYER_VER            "1.04"
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_HELP
+#define NXPLAYER_HELP_TEXT(x)  #x
+#else
+#define NXPLAYER_HELP_TEXT(x)
+#endif
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+struct mp_cmd_s {
+       const char *cmd;                        /* The command text */
+       const char *arghelp;            /* Text describing the args */
+       nxplayer_func pFunc;            /* Pointer to command handler */
+       const char *help;                       /* The help text */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int nxplayer_cmd_quit(FAR struct nxplayer_s *pPlayer, char *parg);
+static int nxplayer_cmd_play(FAR struct nxplayer_s *pPlayer, char *parg);
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+static int nxplayer_cmd_reset(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+static int nxplayer_cmd_device(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+static int nxplayer_cmd_pause(FAR struct nxplayer_s *pPlayer, char *parg);
+static int nxplayer_cmd_resume(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+static int nxplayer_cmd_mediadir(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+static int nxplayer_cmd_stop(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+static int nxplayer_cmd_volume(FAR struct nxplayer_s *pPlayer, char *parg);
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+static int nxplayer_cmd_balance(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+#endif
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+static int nxplayer_cmd_bass(FAR struct nxplayer_s *pPlayer, char *parg);
+static int nxplayer_cmd_treble(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_HELP
+static int nxplayer_cmd_help(FAR struct nxplayer_s *pPlayer, char *parg);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct mp_cmd_s g_nxplayer_cmds[] = {
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+       {"balance", "d%", nxplayer_cmd_balance, NXPLAYER_HELP_TEXT(Set balance percentage( < 50 % means more left))},
+#endif
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+       {"bass", "d%", nxplayer_cmd_bass, NXPLAYER_HELP_TEXT(Set bass level percentage)},
+#endif
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+       {"device", "devfile", nxplayer_cmd_device, NXPLAYER_HELP_TEXT(Specify a preferred audio device)},
+#endif
+#ifdef CONFIG_NXPLAYER_INCLUDE_HELP
+       {"h", "", nxplayer_cmd_help, NXPLAYER_HELP_TEXT(Display help for commands)}
+       ,
+       {"help", "", nxplayer_cmd_help, NXPLAYER_HELP_TEXT(Display help for commands)}
+       ,
+#endif
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+       {"mediadir", "path", nxplayer_cmd_mediadir, NXPLAYER_HELP_TEXT(Change the media directory)}
+       ,
+#endif
+       {"play", "filename", nxplayer_cmd_play, NXPLAYER_HELP_TEXT(Play a media file)}
+       ,
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+       {"pause", "", nxplayer_cmd_pause, NXPLAYER_HELP_TEXT(Pause playback)}
+       ,
+#endif
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+       {"reset", "", nxplayer_cmd_reset, NXPLAYER_HELP_TEXT(Perform a HW reset)}
+       ,
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+       {"resume", "", nxplayer_cmd_resume, NXPLAYER_HELP_TEXT(Resume playback)}
+       ,
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+       {"stop", "", nxplayer_cmd_stop, NXPLAYER_HELP_TEXT(Stop playback)}
+       ,
+#endif
+       {"tone", "freq secs", NULL, NXPLAYER_HELP_TEXT(Produce a pure tone)}
+       ,
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+       {"treble", "d%", nxplayer_cmd_treble, NXPLAYER_HELP_TEXT(Set treble level percentage)}
+       ,
+#endif
+       {"q", "", nxplayer_cmd_quit, NXPLAYER_HELP_TEXT(Exit NxPlayer)}
+       ,
+       {"quit", "", nxplayer_cmd_quit, NXPLAYER_HELP_TEXT(Exit NxPlayer)}
+       ,
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+       {"volume", "d%", nxplayer_cmd_volume, NXPLAYER_HELP_TEXT(Set volume to level specified)}
+#endif
+};
+static const int g_nxplayer_cmd_count = sizeof(g_nxplayer_cmds) / sizeof(struct mp_cmd_s);
+
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxplayer_cmd_play
+ *
+ *   nxplayer_cmd_play() plays the specified media file using the nxplayer
+ *   context.
+ *
+ ****************************************************************************/
+
+static int nxplayer_cmd_play(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       int ret;
+
+       /* Try to play the file specified */
+
+       ret = nxplayer_playfile(pPlayer, parg, AUDIO_FMT_UNDEF, AUDIO_FMT_UNDEF);
+
+       /* nxplayer_playfile returned values:
+        *
+        *   OK         File is being played
+        *   -EBUSY     The media device is busy
+        *   -ENOSYS    The media file is an unsupported type
+        *   -ENODEV    No audio device suitable to play the media type
+        *   -ENOENT    The media file was not found
+        */
+
+       switch (-ret) {
+       case OK:
+               break;
+
+       case ENODEV:
+               printf("No suitable Audio Device found\n");
+               break;
+
+       case EBUSY:
+               printf("Audio device busy\n");
+               break;
+
+       case ENOENT:
+               printf("File %s not found\n", parg);
+               break;
+
+       case ENOSYS:
+               printf("Unknown audio format\n");
+               break;
+
+       default:
+               printf("Error playing file: %d\n", -ret);
+               break;
+       }
+
+       return ret;
+}
+
+/****************************************************************************
+ * Name: nxplayer_cmd_volume
+ *
+ *   nxplayer_cmd_volume() sets the volume level.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+static int nxplayer_cmd_volume(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       uint16_t percent;
+
+       /* If no arg given, then print current volume */
+
+       if (parg == NULL || *parg == '\0') {
+               printf("volume: %d\n", pPlayer->volume / 10);
+       } else {
+               /* Get the percentage value from the argument */
+
+               percent = (uint16_t)(atof(parg) * 10.0);
+               nxplayer_setvolume(pPlayer, percent);
+       }
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_bass
+ *
+ *   nxplayer_cmd_bass() sets the bass level and range.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+static int nxplayer_cmd_bass(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       uint8_t level_percent;
+
+       /* If no arg given, then print current bass */
+
+       if (parg == NULL || *parg == '\0') {
+               printf("bass: %d\n", pPlayer->bass);
+       } else {
+               /* Get the level and range percentage value from the argument */
+
+               level_percent = (uint8_t) atoi(parg);
+               nxplayer_setbass(pPlayer, level_percent);
+       }
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_treble
+ *
+ *   nxplayer_cmd_treble() sets the treble level and range.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+static int nxplayer_cmd_treble(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       uint8_t level_percent;
+
+       /* If no arg given, then print current bass */
+
+       if (parg == NULL || *parg == '\0') {
+               printf("treble: %d\n", pPlayer->treble);
+       } else {
+               /* Get the level and range percentage value from the argument */
+
+               level_percent = (uint8_t) atoi(parg);
+               nxplayer_settreble(pPlayer, level_percent);
+       }
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_balance
+ *
+ *   nxplayer_cmd_balance() sets the balance level.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+static int nxplayer_cmd_balance(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       uint16_t percent;
+
+       /* If no arg given, then print current volume */
+
+       if (parg == NULL || *parg == '\0') {
+               printf("balance: %d\n", pPlayer->volume / 10);
+       } else {
+               /* Get the percentage value from the argument */
+
+               percent = (uint16_t)(atof(parg) * 10.0);
+               nxplayer_setbalance(pPlayer, percent);
+       }
+
+       return OK;
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_reset
+ *
+ *   nxplayer_cmd_reset() performs a HW reset of all the audio devices.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+static int nxplayer_cmd_reset(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       nxplayer_systemreset(pPlayer);
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_mediadir
+ *
+ *   nxplayer_cmd_mediadir() displays or changes the media directory
+ *   context.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+static int nxplayer_cmd_mediadir(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       /* If no arg given, then print current media dir */
+
+       if (parg == NULL || *parg == '\0') {
+               printf("%s\n", pPlayer->mediadir);
+       } else {
+               nxplayer_setmediadir(pPlayer, parg);
+       }
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_stop
+ *
+ *   nxplayer_cmd_stop() stops playback of currently playing file
+ *   context.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+static int nxplayer_cmd_stop(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       /* Stop the playback */
+
+       nxplayer_stop(pPlayer);
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_pause
+ *
+ *   nxplayer_cmd_pause() pauses playback of currently playing file
+ *   context.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+static int nxplayer_cmd_pause(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       /* Pause the playback */
+
+       nxplayer_pause(pPlayer);
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_resume
+ *
+ *   nxplayer_cmd_resume() resumes playback of currently playing file
+ *   context.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+static int nxplayer_cmd_resume(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       /* Resume the playback */
+
+       nxplayer_resume(pPlayer);
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cmd_device
+ *
+ *   nxplayer_cmd_device() sets the preferred audio device for playback
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+static int nxplayer_cmd_device(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       int ret;
+       char path[32];
+
+       /* First try to open the file directly */
+
+       ret = nxplayer_setdevice(pPlayer, parg);
+       if (ret == -ENOENT) {
+               /* Append the /dev/audio path and try again */
+
+#ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
+#ifdef CONFIG_AUDIO_DEV_ROOT
+               snprintf(path, sizeof(path), "/dev/%s", parg);
+#else
+               snprintf(path, sizeof(path), CONFIG_AUDIO_DEV_PATH "/%s", parg);
+#endif
+#else
+               snprintf(path, sizeof(path), "/dev/audio/%s", parg);
+#endif
+               ret = nxplayer_setdevice(pPlayer, path);
+       }
+
+       /* Test if the device file exists */
+
+       if (ret == -ENOENT) {
+               /* Device doesn't exit.  Report error */
+
+               printf("Device %s not found\n", parg);
+               return ret;
+       }
+
+       /* Test if is is an audio device */
+
+       if (ret == -ENODEV) {
+               printf("Device %s is not an audio device\n", parg);
+               return ret;
+       }
+
+       if (ret < 0) {
+               return ret;
+       }
+
+       /* Device set successfully */
+
+       return OK;
+}
+#endif                                                 /* CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE */
+
+/****************************************************************************
+ * Name: nxplayer_cmd_quit
+ *
+ *   nxplayer_cmd_quit() terminates the application
+ ****************************************************************************/
+
+static int nxplayer_cmd_quit(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       /* Stop the playback if any */
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+       nxplayer_stop(pPlayer);
+#endif
+
+       return OK;
+}
+
+/****************************************************************************
+ * Name: nxplayer_cmd_help
+ *
+ *   nxplayer_cmd_help() displays the application's help information on
+ *   supported commands and command syntax.
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_HELP
+static int nxplayer_cmd_help(FAR struct nxplayer_s *pPlayer, char *parg)
+{
+       int x, len, maxlen = 0;
+       int c;
+
+       /* Calculate length of longest cmd + arghelp */
+
+       for (x = 0; x < g_nxplayer_cmd_count; x++) {
+               len = strlen(g_nxplayer_cmds[x].cmd) + strlen(g_nxplayer_cmds[x].arghelp);
+               if (len > maxlen) {
+                       maxlen = len;
+               }
+       }
+
+       printf("NxPlayer commands\n================\n");
+       for (x = 0; x < g_nxplayer_cmd_count; x++) {
+               /* Print the command and it's arguments */
+
+               printf("  %s %s", g_nxplayer_cmds[x].cmd, g_nxplayer_cmds[x].arghelp);
+
+               /* Calculate number of spaces to print before the help text */
+
+               len = maxlen - (strlen(g_nxplayer_cmds[x].cmd) + strlen(g_nxplayer_cmds[x].arghelp));
+               for (c = 0; c < len; c++) {
+                       printf(" ");
+               }
+
+               printf("  : %s\n", g_nxplayer_cmds[x].help);
+       }
+
+       return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxplayer
+ *
+ *   nxplayer() reads in commands from the console using the readline
+ *   system add-in and implemets a command-line based media player that
+ *   uses the NuttX audio system to play media files read in from the
+ *   file system.  Commands are provided for setting volume, base and
+ *   other audio features, as well as for pausing and stoping the
+ *   playback.
+ *
+ * Input Parameters:
+ *   buf       - The user allocated buffer to be filled.
+ *   buflen    - the size of the buffer.
+ *   instream  - The stream to read characters from
+ *   outstream - The stream to each characters to.
+ *
+ * Returned values:
+ *   On success, the (positive) number of bytes transferred is returned.
+ *   EOF is returned to indicate either an end of file condition or a
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_BUILD_KERNEL
+int main(int argc, FAR char *argv[])
+#else
+int nxplayer_main(int argc, char *argv[])
+#endif
+{
+       char buffer[64];
+       int len, x, running;
+       char *cmd, *arg;
+       FAR struct nxplayer_s *pPlayer;
+
+       printf("NxPlayer version " NXPLAYER_VER "\n");
+       printf("h for commands, q to exit\n");
+       printf("\n");
+
+       /* Initialize our NxPlayer context */
+
+       pPlayer = nxplayer_create();
+       if (pPlayer == NULL) {
+               printf("Error:  Out of RAM\n");
+               return -ENOMEM;
+       }
+
+       /* Loop until the user exits */
+
+       running = TRUE;
+       while (running) {
+               /* Print a prompt */
+
+               printf("nxplayer> ");
+               fflush(stdout);
+
+               /* Read a line from the terminal */
+
+               len = readline(buffer, sizeof(buffer), stdin, stdout);
+               buffer[len] = '\0';
+               if (len > 0) {
+                       if (buffer[len - 1] == '\n') {
+                               buffer[len - 1] = '\0';
+                       }
+
+                       /* Parse the command from the argument */
+
+                       cmd = strtok_r(buffer, " \n", &arg);
+                       if (cmd == NULL) {
+                               continue;
+                       }
+
+                       /* Remove leading spaces from arg */
+
+                       while (*arg == ' ') {
+                               arg++;
+                       }
+
+                       /* Find the command in our cmd array */
+
+                       for (x = 0; x < g_nxplayer_cmd_count; x++) {
+                               if (strcmp(cmd, g_nxplayer_cmds[x].cmd) == 0) {
+                                       /* Command found.  Call it's handler if not NULL */
+
+                                       if (g_nxplayer_cmds[x].pFunc != NULL) {
+                                               g_nxplayer_cmds[x].pFunc(pPlayer, arg);
+                                       }
+
+                                       /* Test if it is a quit command */
+
+                                       if (g_nxplayer_cmds[x].pFunc == nxplayer_cmd_quit) {
+                                               running = FALSE;
+                                       }
+                                       break;
+                               }
+                       }
+
+                       /* Test for Unknown command */
+
+                       if (x == g_nxplayer_cmd_count) {
+                               printf("%s:  unknown nxplayer command\n", buffer);
+                       }
+               }
+       }
+
+       /* Release the NxPlayer context */
+
+       nxplayer_release(pPlayer);
+
+       return OK;
+}
diff --git a/apps/include/nxplayer.h b/apps/include/nxplayer.h
new file mode 100644 (file)
index 0000000..2b3e30e
--- /dev/null
@@ -0,0 +1,488 @@
+/****************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * apps/include/nxplayer/nxplayer.h
+ *
+ *   Copyright (C) 2013 Ken Pettit. All rights reserved.
+ *   Author: Ken Pettit <pettitkd@gmail.com>
+ *
+ * With updates, enhancements, and modifications by:
+ *
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXPLAYER_NXPLAYER_H
+#define __APPS_SYSTEM_NXPLAYER_NXPLAYER_H 1
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <tinyara/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+/* This structure describes the internal state of the NxPlayer */
+
+struct nxplayer_s {
+       int state;                                      /* Current player state */
+       int devFd;                                      /* File descriptor of active device */
+       mqd_t mq;                                       /* Message queue for the playthread */
+       char mqname[16];                        /* Name of our message queue */
+       pthread_t playId;                       /* Thread ID of the playthread */
+       int crefs;                                      /* Number of references to the player */
+       sem_t sem;                                      /* Thread sync semaphore */
+       FILE *fileFd;                           /* File descriptor of open file */
+#ifdef CONFIG_NXPLAYER_INCLUDE_PREFERRED_DEVICE
+       char prefdevice[CONFIG_NAME_MAX];       /* Preferred audio device */
+       int prefformat;                         /* Formats supported by preferred device */
+       int preftype;                           /* Types supported by preferred device */
+#endif
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+       char mediadir[CONFIG_NAME_MAX]; /* Root media directory where media is located */
+#endif
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+       FAR void *session;                      /* Session assigment from device */
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+       uint16_t volume;                        /* Volume as a whole percentage (0-100) */
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+       uint16_t balance;                       /* Balance as a whole % (0=left off, 100=right off) */
+#endif
+#endif
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+       uint16_t treble;                        /* Treble as a whole % */
+       uint16_t bass;                          /* Bass as a whole % */
+#endif
+};
+
+typedef int (*nxplayer_func)(FAR struct nxplayer_s *pPlayer, char *pargs);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxplayer_create
+ *
+ *   Allocates and Initializes a NxPlayer context that is passed to all
+ *   nxplayer routines.  The player MUST be destroyed using the
+ *   nxplayer_destroy() routine since the context is reference counted.
+ *   The context can be used in a mode where the caller creates the
+ *   context, starts a file playing, and then forgets about the context
+ *   and it will self free.  This is because the nxplayer_playfile
+ *   will also create a reference to the context, so the client calling
+ *   nxplayer_destroy() won't actually de-allocate anything.  The freeing
+ *   will occur after the playthread has completed.
+ *
+ *   Alternately, the caller can create the objec and hold on to it, then
+ *   the context will persist until the original creator destroys it.
+ *
+ * Input Parameters:    None
+ *
+ * Returned Value:
+ *   Pointer to created NxPlayer context or NULL if error.
+ *
+ ****************************************************************************/
+
+FAR struct nxplayer_s *nxplayer_create(void);
+
+/****************************************************************************
+ * Name: nxplayer_release
+ *
+ *   Reduces the reference count to the player and if it reaches zero,
+ *   frees all memory used by the context.
+ *
+ * Input Parameters:
+ *   pPlayer    Pointer to the NxPlayer context
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void nxplayer_release(FAR struct nxplayer_s *pPlayer);
+
+/****************************************************************************
+ * Name: nxplayer_reference
+ *
+ *   Increments the reference count to the player.
+ *
+ * Input Parameters:
+ *   pPlayer    Pointer to the NxPlayer context
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void nxplayer_reference(FAR struct nxplayer_s *pPlayer);
+
+/****************************************************************************
+ * Name: nxplayer_setdevice
+ *
+ *   Sets the preferred Audio device to use with the instance of the
+ *   nxplayer.  Without a preferred device set, the nxplayer will search
+ *   the audio subsystem to find a suitable device depending on the
+ *   type of audio operation requested (i.e. an MP3 decoder device when
+ *   playing an MP3 file, a WAV decoder device for a WAV file, etc.).
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   device    - Pointer to pathname of the preferred device
+ *
+ * Returned Value:
+ *   OK if context initialized successfully, error code otherwise.
+ *
+ ****************************************************************************/
+
+int nxplayer_setdevice(FAR struct nxplayer_s *pPlayer, FAR const char *device);
+
+/****************************************************************************
+ * Name: nxplayer_playfile
+ *
+ *   Plays the specified media file (from the filesystem) using the
+ *   Audio system.  If a preferred device has been set, that device
+ *   will be used for the playback, otherwise the first suitable device
+ *   found in the /dev/audio directory will be used.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   filename  - Pointer to pathname of the file to play
+ *   filefmt   - Format of audio in filename if known, AUDIO_FMT_UNDEF
+ *               to let nxplayer_playfile() determine automatically.
+ *   subfmt    - Sub-Format of audio in filename if known, AUDIO_FMT_UNDEF
+ *               to let nxplayer_playfile() determine automatically.
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+int nxplayer_playfile(FAR struct nxplayer_s *pPlayer, FAR const char *filename, int filefmt, int subfmt);
+
+/****************************************************************************
+ * Name: nxplayer_stop
+ *
+ *   Stops current playback.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_STOP
+int nxplayer_stop(FAR struct nxplayer_s *pPlayer);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_pause
+ *
+ *   Pauses current playback.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+int nxplayer_pause(FAR struct nxplayer_s *pPlayer);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_resume
+ *
+ *   Resumes current playback.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
+int nxplayer_resume(FAR struct nxplayer_s *pPlayer);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_fforward
+ *
+ *   Selects to fast forward in the audio data stream.  The fast forward
+ *   operation can be cancelled by simply selected no sub-sampling with
+ *   the AUDIO_SUBSAMPLE_NONE argument returning to normal 1x forward play.
+ *
+ *   The preferred way to cancel a fast forward operation is via
+ *   nxplayer_cancel_motion() that provides the option to also return to
+ *   paused, non-playing state.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   subsample - Identifies the fast forward rate (in terms of sub-sampling,
+ *               but does not explicitly require sub-sampling).  See
+ *               AUDIO_SUBSAMPLE_* definitions.
+ *
+ * Returned Value:
+ *   OK if fast forward operation successful.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_FFORWARD
+int nxplayer_fforward(FAR struct nxplayer_s *pPlayer, uint8_t subsample);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_rewind
+ *
+ *   Selects to rewind in the audio data stream.  The rewind operation must
+ *   be cancelled with nxplayer_cancel_motion.  This function may be called
+ *   multiple times to change rewind rate.
+ *
+ *   NOTE that cancellation of the rewind operation differs from
+ *   cancellation of the fast forward operation because we must both restore
+ *   the sub-sampling rate to 1x and also return to forward play.
+ *   AUDIO_SUBSAMPLE_NONE is not a valid argument to this function.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   subsample - Identifies the rewind rate (in terms of sub-sampling, but
+ *               does not explicitly require sub-sampling).  See
+ *               AUDIO_SUBSAMPLE_* definitions.
+ *
+ * Returned Value:
+ *   OK if rewind operation successfully initiated.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_REWIND
+int nxplayer_rewind(FAR struct nxplayer_s *pPlayer, uint8_t subsample);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_cancel_motion
+ *
+ *   Cancel a rewind or fast forward operation and return to either the
+ *   paused state or to the normal, forward play state.
+ *
+ * Input Parameters:
+ *   pPlayer - Pointer to the context to initialize
+ *   paused  - True: return to the paused state, False: return to the 1X
+ *             forward play state.
+ *
+ * Returned Value:
+ *   OK if rewind operation successfully cancelled.
+ *
+ ****************************************************************************/
+
+#if !defined(CONFIG_AUDIO_EXCLUDE_FFORWARD) || !defined(CONFIG_AUDIO_EXCLUDE_REWIND)
+int nxplayer_cancel_motion(FAR struct nxplayer_s *pPlayer, bool paused);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setvolume
+ *
+ *   Sets the playback volume.  The volume is represented in 1/10th of a
+ *   percent increments, so the range is 0-1000.  A value of 10 would mean
+ *   1%.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   volume    - Volume level to set in 1/10th percent increments
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+int nxplayer_setvolume(FAR struct nxplayer_s *pPlayer, uint16_t volume);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setbalance
+ *
+ *   Sets the playback balance.  The balance is represented in 1/10th of a
+ *   percent increments, so the range is 0-1000.  A value of 10 would mean
+ *   1%.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   balance   - Balance level to set in 1/10th percent increments
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
+int nxplayer_setbalance(FAR struct nxplayer_s *pPlayer, uint16_t balance);
+#endif
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setmediadir
+ *
+ *   Sets the root media directory for non-path qualified file searches.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   mediadir  - Pointer to pathname of the media directory
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void nxplayer_setmediadir(FAR struct nxplayer_s *pPlayer, FAR const char *mediadir);
+
+/****************************************************************************
+ * Name: nxplayer_setequalization
+ *
+ *   Sets the level on each band of an equalizer.  Each band setting is
+ *   represented in one percent increments, so the range is 0-100.
+ *
+ * Input Parameters:
+ *   pPlayer      - Pointer to the context to initialize
+ *   equalization - Pointer to array of equalizer settings of size
+ *                  CONFIG_AUDIO_EQUALIZER_NBANDS bytes.  Each byte
+ *                  represents the setting for one band in the range of
+ *                  0-100.
+ *
+ * Returned Value:
+ *   OK if equalization was set correctly.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_EQUALIZER
+int nxplayer_setequalization(FAR struct nxplayer_s *pPlayer, FAR uint8_t *equalization);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_setbass
+ *
+ *   Sets the playback bass level.  The bass is represented in one percent
+ *   increments, so the range is 0-100.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   bass      - Bass level to set in one percent increments
+ *
+ * Returned Value:
+ *   OK if the bass level was set successfully
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+int nxplayer_setbass(FAR struct nxplayer_s *pPlayer, uint8_t bass);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_settreble
+ *
+ *   Sets the playback treble level.  The bass is represented in one percent
+ *   increments, so the range is 0-100.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *   treble    - Treble level to set in one percent increments
+ *
+ * Returned Value:
+ *   OK if the treble level was set successfully
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_AUDIO_EXCLUDE_TONE
+int nxplayer_settreble(FAR struct nxplayer_s *pPlayer, uint8_t treble);
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_systemreset
+ *
+ *   Performs an audio system reset, including a hardware reset on all
+ *   registered audio devices.
+ *
+ * Input Parameters:
+ *   pPlayer   - Pointer to the context to initialize
+ *
+ * Returned Value:
+ *   OK if file found, device found, and playback started.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+int nxplayer_systemreset(FAR struct nxplayer_s *pPlayer);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif                                                 /* __APPS_SYSTEM_NXPLAYER_NXPLAYER_H */