summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-27 07:23:01 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-27 07:23:01 -0600
commit6dc974b4b0d8423cc9073e425a2e3a4370160df6 (patch)
treedb597b33eff503c1eb0ea0dbf9f97c79af9bdbbb
parent8acac95003c039ba20487ce04ec7cd6ca939bb53 (diff)
downloadpx4-nuttx-6dc974b4b0d8423cc9073e425a2e3a4370160df6.tar.gz
px4-nuttx-6dc974b4b0d8423cc9073e425a2e3a4370160df6.tar.bz2
px4-nuttx-6dc974b4b0d8423cc9073e425a2e3a4370160df6.zip
Add apps/system/nxplayer media player from Ken Pettit
-rw-r--r--apps/ChangeLog.txt2
-rw-r--r--apps/include/nxplayer.h356
-rw-r--r--apps/system/Kconfig4
-rw-r--r--apps/system/Make.defs4
-rw-r--r--apps/system/Makefile6
-rw-r--r--apps/system/nxplayer/.gitignore11
-rw-r--r--apps/system/nxplayer/Kconfig109
-rw-r--r--apps/system/nxplayer/Makefile131
-rw-r--r--apps/system/nxplayer/README.txt17
-rw-r--r--apps/system/nxplayer/nxplayer.c1513
-rw-r--r--apps/system/nxplayer/nxplayer_main.c666
11 files changed, 2816 insertions, 3 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt
index aff570b5b..33b6820df 100644
--- a/apps/ChangeLog.txt
+++ b/apps/ChangeLog.txt
@@ -700,4 +700,6 @@
* apps/examples/adc: Add support so that a ADC driven by
software triggering can be tested (2013-10-25).
* apps/examples/cc3000: Updates from David Sidrane (2013-10-25).
+ * apps/system/nxplayer: Implements a command line media
+ player. From Ken Pettit (2013-10-27).
diff --git a/apps/include/nxplayer.h b/apps/include/nxplayer.h
new file mode 100644
index 000000000..5932c9928
--- /dev/null
+++ b/apps/include/nxplayer.h
@@ -0,0 +1,356 @@
+/****************************************************************************
+ * apps/system/nxplayer/nxplayer.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_SYSTEM_NXPLAYER_NXPLAYER_H
+#define __APPS_SYSTEM_NXPLAYER_NXPLAYER_H 1
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+
+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
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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 values:
+ * 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 values: 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 values: 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 values:
+ * OK if context initialized successfully, error code otherwise.
+ *
+ **************************************************************************/
+
+int nxplayer_setdevice(FAR struct nxplayer_s *pPlayer, 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.
+ *
+ * Returned values:
+ * OK if file found, device found, and playback started.
+ *
+ **************************************************************************/
+
+int nxplayer_playfile(FAR struct nxplayer_s *pPlayer, char* filename,
+ int filefmt);
+
+/****************************************************************************
+ * Name: nxplayer_stop
+ *
+ * Stops current playback.
+ *
+ * Input Parameters:
+ * pPlayer - Pointer to the context to initialize
+ *
+ * Returned values:
+ * 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 values:
+ * 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
+ *
+ * Resuems current playback.
+ *
+ * Input Parameters:
+ * pPlayer - Pointer to the context to initialize
+ *
+ * Returned values:
+ * 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_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 values:
+ * 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 values:
+ * 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
+ *
+ *
+ **************************************************************************/
+
+inline void nxplayer_setmediadir(FAR struct nxplayer_s *pPlayer, char* mediadir);
+
+/****************************************************************************
+ * 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 values:
+ * OK if file found, device found, and playback started.
+ *
+ **************************************************************************/
+
+#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 values:
+ * OK if file found, device found, and playback started.
+ *
+ **************************************************************************/
+
+#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 values:
+ * OK if file found, device found, and playback started.
+ *
+ **************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_INCLUDE_SYSTEM_RESET
+int nxplayer_systemreset(FAR struct nxplayer_s *pPlayer);
+#endif
+
+#endif /* __APPS_SYSTEM_NXPLAYER_NXPLAYER_H */
+
diff --git a/apps/system/Kconfig b/apps/system/Kconfig
index 82741e572..b95224b33 100644
--- a/apps/system/Kconfig
+++ b/apps/system/Kconfig
@@ -27,6 +27,10 @@ menu "FLASH Erase-all Command"
source "$APPSDIR/system/flash_eraseall/Kconfig"
endmenu
+menu "NxPlayer media player library / command Line"
+source "$APPSDIR/system/nxplayer/Kconfig"
+endmenu
+
menu "RAM test"
source "$APPSDIR/system/ramtest/Kconfig"
endmenu
diff --git a/apps/system/Make.defs b/apps/system/Make.defs
index 7c7b886fe..b25f1acb7 100644
--- a/apps/system/Make.defs
+++ b/apps/system/Make.defs
@@ -58,6 +58,10 @@ ifeq ($(CONFIG_SYSTEM_FLASH_ERASEALL),y)
CONFIGURED_APPS += system/flash_eraseall
endif
+ifeq ($(CONFIG_SYSTEM_NXPLAYER),y)
+CONFIGURED_APPS += system/nxplayer
+endif
+
ifeq ($(CONFIG_SYSTEM_RAMTEST),y)
CONFIGURED_APPS += system/ramtest
endif
diff --git a/apps/system/Makefile b/apps/system/Makefile
index d3438793b..72d703b28 100644
--- a/apps/system/Makefile
+++ b/apps/system/Makefile
@@ -37,9 +37,9 @@
# Sub-directories containing system task
-SUBDIRS = cdcacm composite flash_eraseall free i2c install poweroff
-SUBDIRS += ramtest ramtron readline sdcard stackmonitor sysinfo usbmonitor
-SUBDIRS += usbmsc zmodem
+SUBDIRS = cdcacm composite flash_eraseall free i2c install nxplayer
+SUBDIRS += poweroff ramtest ramtron readline sdcard stackmonitor sysinfo
+SUBDIRS += usbmonitor usbmsc zmodem
# Create the list of installed runtime modules (INSTALLED_DIRS)
diff --git a/apps/system/nxplayer/.gitignore b/apps/system/nxplayer/.gitignore
new file mode 100644
index 000000000..83bd7b811
--- /dev/null
+++ b/apps/system/nxplayer/.gitignore
@@ -0,0 +1,11 @@
+/Make.dep
+/.depend
+/.built
+/*.asm
+/*.rel
+/*.lst
+/*.sym
+/*.adb
+/*.lib
+/*.src
+/*.obj
diff --git a/apps/system/nxplayer/Kconfig b/apps/system/nxplayer/Kconfig
new file mode 100644
index 000000000..6651422fc
--- /dev/null
+++ b/apps/system/nxplayer/Kconfig
@@ -0,0 +1,109 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config SYSTEM_NXPLAYER
+ bool "NxPlayer library / command line support"
+ default n
+ ---help---
+ Enable support for the command line media player
+
+if SYSTEM_NXPLAYER
+
+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/system/nxplayer/Makefile b/apps/system/nxplayer/Makefile
new file mode 100644
index 000000000..d2790e915
--- /dev/null
+++ b/apps/system/nxplayer/Makefile
@@ -0,0 +1,131 @@
+############################################################################
+# apps/system/nxplayer/Makefile
+#
+# Copyright (C) 2013 Ken Pettit. All rights reserved.
+# Copyright (C) 2012-2013 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.
+#
+############################################################################
+
+# TODO, this makefile should run make under the app dirs, instead of
+# sourcing the Make.defs!
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+
+ifeq ($(WINTOOL),y)
+INCDIROPT = -w
+endif
+
+# NxPlayer Library
+
+ASRCS =
+CSRCS = nxplayer.c
+
+# NxPlayer Application
+
+APPNAME = nxplayer
+PRIORITY = SCHED_PRIORITY_DEFAULT
+STACKSIZE = 3100
+
+ifeq ($(CONFIG_NXPLAYER_COMMAND_LINE),y)
+CSRCS += nxplayer_main.c
+endif
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+ BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+ BIN = ..\\..\\libapps$(LIBEXT)
+else
+ BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: context depend clean distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+ $(call ARCHIVE, $(BIN), $(OBJS))
+ $(Q) touch .built
+
+# Register application
+
+ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
+ifeq ($(CONFIG_NXPLAYER_COMMAND_LINE),y)
+$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile
+ $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
+
+context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat
+else
+context:
+endif
+else
+context:
+endif
+
+# Create dependencies
+
+.depend: Makefile $(SRCS)
+ $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
+ $(Q) touch $@
+
+depend: .depend
+
+clean:
+ $(call DELFILE, .built)
+ $(call CLEAN)
+ rm -rf ..$(DELIM)..$(DELIM)builtin$(DELIM)registry$(DELIM)$(APPNAME)_main.*
+
+distclean: clean
+ $(call DELFILE, Make.dep)
+ $(call DELFILE, .depend)
+
+-include Make.dep
diff --git a/apps/system/nxplayer/README.txt b/apps/system/nxplayer/README.txt
new file mode 100644
index 000000000..32d1f20fc
--- /dev/null
+++ b/apps/system/nxplayer/README.txt
@@ -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/system/nxplayer/nxplayer.c b/apps/system/nxplayer/nxplayer.c
new file mode 100644
index 000000000..a86c5030c
--- /dev/null
+++ b/apps/system/nxplayer/nxplayer.c
@@ -0,0 +1,1513 @@
+/****************************************************************************
+ * apps/system/nxplayer/nxplayer.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 <nuttx/config.h>
+#include <nuttx/audio/audio.h>
+#include <debug.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <dirent.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
+
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+struct nxplayer_ext_fmt_s
+{
+ const char *ext;
+ uint16_t format;
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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 },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_MP3
+ { "mp3", AUDIO_FMT_MP3 },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_DTS
+ { "dts", AUDIO_FMT_DTS },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_WMA
+ { "wma", AUDIO_FMT_WMA },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_PCM
+ { "wav", AUDIO_FMT_PCM },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_MIDI
+ { "mid", AUDIO_FMT_MIDI },
+ { "midi", AUDIO_FMT_MIDI },
+#endif
+#ifdef CONFIG_AUDIO_FORMAT_OGG_VORBIS
+ { "ogg", AUDIO_FMT_OGG_VORBIS }
+#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)
+{
+ struct dirent* pDevice;
+ DIR* dirp;
+ char path[64];
+ struct audio_caps_s caps;
+
+ /* 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 & format) == 0) ||
+ ((pPlayer->preftype & AUDIO_TYPE_OUTPUT) == 0))
+ {
+ /* Format not supported by the device */
+
+ return -ENODEV;
+ }
+
+ /* Device supports the format. Open the device file. */
+
+ pPlayer->devFd = open(pPlayer->prefdevice, O_RDWR);
+ if (pPlayer->devFd == -1)
+ 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
+ {
+ /* 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)
+ {
+ 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 */
+
+ int ac_format = caps.ac_format[0] | (caps.ac_format[1] << 8);
+ if (((ac_format & format) != 0) &&
+ (caps.ac_controls[0] & AUDIO_TYPE_OUTPUT))
+ {
+ /* 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 */
+
+ pPlayer->devFd = -1;
+ return -ENODEV;
+}
+
+/****************************************************************************
+ * 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 int nxplayer_fmtfromextension(char* pFilename)
+{
+ const char *pExt;
+ int x, 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)
+ {
+ /* 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, char *pFilename,
+ char *path, int pathmax)
+{
+ return -ENOENT;
+}
+#endif
+
+/****************************************************************************
+ * Name: nxplayer_enqueuebuffer
+ *
+ * Reads the next block of data from the media file into the specified
+ * buffer and enqueues it to the audio device.
+ *
+ ****************************************************************************/
+
+static int nxplayer_enqueuebuffer(struct nxplayer_s *pPlayer,
+ struct ap_buffer_s* pBuf)
+{
+ struct audio_buf_desc_s bufdesc;
+ int ret;
+
+ //auddbg("Entry: %p\n", pBuf);
+
+ /* Validate the file is still open */
+
+ if (pPlayer->fileFd == NULL)
+ return OK;
+
+ /* Read data into the buffer. */
+
+ pBuf->nbytes = fread(&pBuf->samp, 1, pBuf->nmaxbytes, pPlayer->fileFd);
+ if (pBuf->nbytes < pBuf->nmaxbytes)
+ {
+ fclose(pPlayer->fileFd);
+ pPlayer->fileFd = NULL;
+ }
+
+ /* 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 cleanup.
+ */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ bufdesc.session = pPlayer->session;
+#endif
+ bufdesc.numbytes = pBuf->nbytes;
+ bufdesc.u.pBuffer = pBuf;
+ ret = ioctl(pPlayer->devFd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)
+ &bufdesc);
+ if (ret >= 0)
+ ret = OK;
+ else
+ ret = errno;
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nxplayer_thread_playthread
+ *
+ * This is the thread that reads the audio file file and enqueue's /
+ * 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;
+ int prio;
+ ssize_t size;
+ uint8_t running = TRUE;
+ uint8_t playing = TRUE;
+ int x, ret;
+#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
+
+ auddbg("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("nxplayer_playthread: can't alloc 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
+ {
+ /* Enqueue next buffer */
+
+ ret = nxplayer_enqueuebuffer(pPlayer, pBuffers[x]);
+ if (ret != OK)
+ {
+ /* Error encoding initial buffers or file is small */
+
+ if (x == 0)
+ running = FALSE;
+ else
+ playing = FALSE;
+
+ break;
+ }
+ }
+
+ /* Start the audio device */
+
+#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! */
+
+ running = FALSE;
+ }
+
+ /* Indicate we are playing a file */
+
+ pPlayer->state = NXPLAYER_STATE_PLAYING;
+
+ /* Set parameters such as volume, bass, etc. */
+
+#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
+ 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 */
+
+ 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, &msg, sizeof(msg), &prio);
+
+ /* Validate a message was received */
+
+ if (size != sizeof(msg))
+ {
+ /* Interrupted by a signal? What to do? */
+
+ }
+
+ /* Perform operation based on message id */
+
+ switch (msg.msgId)
+ {
+ /* An audio buffer is being dequeued by the driver */
+
+ case AUDIO_MSG_DEQUEUE:
+
+ /* Read data from the file directly into this buffer
+ * and re-enqueue it.
+ */
+
+ if (playing)
+ {
+ ret = nxplayer_enqueuebuffer(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.
+ */
+
+ playing = FALSE;
+ }
+ }
+ break;
+
+ /* Someone wants to stop the playback. */
+
+ case AUDIO_MSG_STOP:
+
+ /* Send a stop message to the device */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ ioctl(pPlayer->devFd, AUDIOIOC_STOP,
+ (unsigned long) pPlayer->session);
+#else
+ ioctl(pPlayer->devFd, AUDIOIOC_STOP, 0);
+#endif
+ playing = FALSE;
+ running = FALSE;
+ break;
+
+ /* Message indicating the playback is complete */
+
+ case AUDIO_MSG_COMPLETE:
+
+ running = FALSE;
+ break;
+
+ /* Unknown / unsupported message ID */
+
+ default:
+ break;
+ }
+ }
+
+ /* Release our audio buffers and unregister / release the device */
+
+err_out:
+ /* 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) != OK)
+ ;
+
+#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
+ if (pBuffers != NULL)
+ {
+ auddbg("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
+ auddbg("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);
+
+ auddbg("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;
+
+ /* Thread sync using the semaphore */
+
+ while (sem_wait(&pPlayer->sem) != OK)
+ ;
+
+ /* 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;
+ *((uint16_t *) cap_desc.caps.ac_format) = AUDIO_FU_VOLUME;
+ *((uint16_t *) cap_desc.caps.ac_controls) = volume;
+ ioctl(pPlayer->devFd, AUDIOIOC_CONFIGURE, (unsigned long) &cap_desc);
+ }
+
+ /* Store the volume setting */
+
+ pPlayer->volume = volume;
+
+ sem_post(&pPlayer->sem);
+
+ return -ENOENT;
+}
+#endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */
+
+/****************************************************************************
+ * 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) != OK)
+ ;
+
+ /* 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;
+ *((uint16_t *) cap_desc.caps.ac_format) = AUDIO_FU_BASS;
+ cap_desc.caps.ac_controls[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) != OK)
+ ;
+
+ /* 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;
+ *((uint16_t *) cap_desc.caps.ac_format) = AUDIO_FU_TREBLE;
+ cap_desc.caps.ac_controls[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) != OK)
+ ;
+
+ /* 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;
+ *((uint16_t *) cap_desc.caps.ac_format) = AUDIO_FU_BALANCE;
+ *((uint16_t *) cap_desc.caps.ac_controls) = 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_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, 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[0] | (caps.ac_format[1] << 8);
+ pPlayer->preftype = caps.ac_controls[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, &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, char* pFilename, int filefmt)
+{
+ int ret;
+ struct mq_attr attr;
+ struct sched_param sparam;
+ pthread_attr_t tattr;
+ void* value;
+#ifdef CONFIG_NXPLAYER_INCLUDE_MEDIADIR
+ char path[128];
+#endif
+
+ DEBUGASSERT(pPlayer != NULL);
+ DEBUGASSERT(pFilename != NULL);
+
+ if (pPlayer->state != NXPLAYER_STATE_IDLE)
+ {
+ return -EBUSY;
+ }
+
+ auddbg("==============================\n");
+ auddbg("Playing file %s\n", pFilename);
+ auddbg("==============================\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)
+ return -ENOENT;
+#else
+ return -ENOENT;
+#endif /* CONFIG_NXPLAYER_MEDIA_SEARCH */
+ }
+
+#else /* CONFIG_NXPLAYER_INCLUDE_MEDIADIR */
+ return -ENOENT;
+#endif /* CONFIG_NXPLAYER_INCLUDE_MEDIADIR */
+ }
+
+ /* Try to determine the format of audio file based on the extension */
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_EXT
+ if (filefmt == AUDIO_FMT_UNDEF)
+ filefmt = nxplayer_fmtfromextension(pFilename);
+#endif
+
+ /* If type not identified, then test for known header types */
+
+#ifdef CONFIG_NXPLAYER_FMT_FROM_HEADER
+ if (filefmt == AUDIO_FMT_UNDEF)
+ filefmt = nxplayer_fmtfromheader(pPlayer);
+#endif
+
+ /* Test if we determined the file format */
+
+ if (filefmt == AUDIO_FMT_UNDEF)
+ {
+ /* Hmmm, it's some unknown / unsupported type */
+
+ ret = -ENOSYS;
+ goto err_out_nodev;
+ }
+
+ /* Try to open the device */
+
+ ret = nxplayer_opendevice(pPlayer, filefmt);
+ if (ret < 0)
+ {
+ /* Error opening the device */
+
+ 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 */
+
+ 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/%0X", pPlayer);
+ pPlayer->mq = mq_open(pPlayer->mqname, O_RDWR | O_CREAT, 0644, &attr);
+ if (pPlayer->mq == NULL)
+ {
+ /* Unable to open message queue! */
+
+ ret = -errno;
+ 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 cleanup.
+ */
+
+ 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;
+ pthread_attr_setschedparam(&tattr, &sparam);
+
+ /* 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 %d creating playthread\n", ret);
+ goto err_out;
+ }
+
+ 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, 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, ret;
+ FAR void* value;
+
+ /* Grab the semaphore */
+
+ while ((ret = sem_wait(&pPlayer->sem)) != OK)
+ {
+ if (ret != -EINTR)
+ {
+ auddbg("Error getting semaphore\n");
+ 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 ((ret = sem_wait(&pPlayer->sem)) != OK)
+ {
+ if (ret != -EINTR)
+ {
+ auddbg("Error getting semaphore\n");
+ 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)
+{
+ int ret;
+
+ /* Grab the semaphore */
+
+ while ((ret = sem_wait(&pPlayer->sem)) != OK)
+ {
+ if (ret != -EINTR)
+ {
+ auddbg("Error getting semaphore\n");
+ return;
+ }
+ }
+
+ /* Increment the reference count */
+
+ pPlayer->crefs++;
+ sem_post(&pPlayer->sem);
+}
+
+/****************************************************************************
+ * Name: nxplayer_detach
+ *
+ * nxplayer_detach() detaches from the playthread to make it independant
+ * so the caller can abandon the context while the file is still
+ * being played.
+ *
+ * Input Parameters:
+ * pPlayer Pointer to the NxPlayer context
+ *
+ * Returned values: None
+ *
+ **************************************************************************/
+
+void nxplayer_detach(FAR struct nxplayer_s* pPlayer)
+{
+#if 0
+ int ret;
+
+ /* Grab the semaphore */
+
+ while ((ret = sem_wait(&pPlayer->sem)) != OK)
+ {
+ if (ret != -EINTR)
+ {
+ auddbg("Error getting semaphore\n");
+ return;
+ }
+ }
+
+ if (pPlayer->playId != NULL)
+ {
+ /* Do a pthread detach */
+
+ pthread_detach(pPlayer->playId);
+ pPlayer->playId = NULL;
+ }
+
+ sem_post(&pPlayer->sem);
+#endif
+}
+
+/****************************************************************************
+ * 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/system/nxplayer/nxplayer_main.c b/apps/system/nxplayer/nxplayer_main.c
new file mode 100644
index 000000000..171684042
--- /dev/null
+++ b/apps/system/nxplayer/nxplayer_main.c
@@ -0,0 +1,666 @@
+/****************************************************************************
+ * apps/system/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 <nuttx/config.h>
+#include <nuttx/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);
+
+ /* Test if the device file exists */
+
+ if (ret == -ENODEV)
+ {
+ printf("No suitable Audio Device found\n");
+ }
+
+ else if (ret == -EBUSY)
+ {
+ printf("Audio device busy\n");
+ }
+
+ else if (ret == -ENOENT)
+ {
+ printf("File %s not found\n", parg);
+ }
+
+ else if (ret == -ENOSYS)
+ {
+ printf("Unknown audio format\n");
+ }
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* File playing successfully */
+
+ return OK;
+}
+
+/****************************************************************************
+ * 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)
+{
+ /* Nothing to do */
+
+ 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.
+ *
+ **************************************************************************/
+
+int nxplayer_main(int argc, char *argv[])
+{
+ 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_detach(pPlayer);
+ nxplayer_release(pPlayer);
+
+ return OK;
+}