You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/02/02 14:12:05 UTC
[nuttx-apps] branch master updated: nxrecorder: add support to record media file.
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 61c4050d3 nxrecorder: add support to record media file.
61c4050d3 is described below
commit 61c4050d31b13816fa619fca54be713f38bea7bf
Author: qiaohaijiao1 <qi...@xiaomi.com>
AuthorDate: Wed Jan 18 13:49:25 2023 +0800
nxrecorder: add support to record media file.
Signed-off-by: qiaohaijiao1 <qi...@xiaomi.com>
---
include/system/nxrecorder.h | 9 +-
system/nxrecorder/Kconfig | 10 ++
system/nxrecorder/nxrecorder.c | 276 +++++++++++++++++++++++++++++++++---
system/nxrecorder/nxrecorder_main.c | 91 +++++++++++-
4 files changed, 353 insertions(+), 33 deletions(-)
diff --git a/include/system/nxrecorder.h b/include/system/nxrecorder.h
index 129a23170..a06d86df4 100644
--- a/include/system/nxrecorder.h
+++ b/include/system/nxrecorder.h
@@ -153,7 +153,7 @@ int nxrecorder_setdevice(FAR struct nxrecorder_s *precorder,
FAR const char *device);
/****************************************************************************
- * Name: nxrecorder_recordraw
+ * Name: nxrecorder_recordinternal
*
* Plays the specified media file (from the filesystem) using the
* Audio system. If a preferred device has been set, that device
@@ -173,9 +173,10 @@ int nxrecorder_setdevice(FAR struct nxrecorder_s *precorder,
*
****************************************************************************/
-int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
- FAR const char *filename, uint8_t nchannels,
- uint8_t bpsamp, uint32_t samprate, uint8_t chmap);
+int nxrecorder_recordinternal(FAR struct nxrecorder_s *precorder,
+ FAR const char *filename, int filefmt,
+ uint8_t nchannels, uint8_t bpsamp,
+ uint32_t samprate, uint8_t chmap);
/****************************************************************************
* Name: nxrecorder_stop
diff --git a/system/nxrecorder/Kconfig b/system/nxrecorder/Kconfig
index 4dee937c4..dd274eb2e 100644
--- a/system/nxrecorder/Kconfig
+++ b/system/nxrecorder/Kconfig
@@ -43,5 +43,15 @@ config NXRECORDER_INCLUDE_HELP
Compiles in the NxRecorder help text to provide online help
for available commands with syntax.
+config NXRECORDER_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.
+
endif
endif
diff --git a/system/nxrecorder/nxrecorder.c b/system/nxrecorder/nxrecorder.c
index 9b6cb4372..cc6f3fa20 100644
--- a/system/nxrecorder/nxrecorder.c
+++ b/system/nxrecorder/nxrecorder.c
@@ -58,6 +58,62 @@
# define CONFIG_NXRECORDER_RECORDTHREAD_STACKSIZE 1500
#endif
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
+
+#ifdef CONFIG_NXRECORDER_FMT_FROM_EXT
+struct nxrecorder_ext_fmt_s
+{
+ FAR const char *ext;
+ uint16_t format;
+ CODE int (*getsubformat)(int fd);
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_AUDIO_FORMAT_MP3
+int nxrecorder_getmp3subformat(int fd);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NXRECORDER_FMT_FROM_EXT
+static const struct nxrecorder_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, nxrecorder_getmp3subformat },
+#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, NULL },
+ { "midi", AUDIO_FMT_MIDI, NULL },
+#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 nxrecorder_ext_fmt_s);
+#endif
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -77,8 +133,13 @@
*
****************************************************************************/
-static int nxrecorder_opendevice(FAR struct nxrecorder_s *precorder)
+static int nxrecorder_opendevice(FAR struct nxrecorder_s *precorder,
+ int format, int subfmt)
{
+ struct audio_caps_s cap;
+ bool supported = true;
+ int x;
+
/* If we have a device, then open it */
if (precorder->device[0] != '\0')
@@ -101,7 +162,79 @@ static int nxrecorder_opendevice(FAR struct nxrecorder_s *precorder)
return -ENOENT;
}
- return OK;
+ cap.ac_len = sizeof(cap);
+ cap.ac_type = AUDIO_TYPE_QUERY;
+ cap.ac_subtype = AUDIO_TYPE_QUERY;
+
+ if (ioctl(precorder->dev_fd, AUDIOIOC_GETCAPS,
+ (uintptr_t)&cap) == cap.ac_len)
+ {
+ if (((cap.ac_format.hw & (1 << (format - 1))) != 0) &&
+ (cap.ac_controls.b[0] & AUDIO_TYPE_INPUT))
+ {
+ /* Test if subformat needed and detected */
+
+ if (subfmt != AUDIO_FMT_UNDEF)
+ {
+ /* Prepare to get sub-formats for
+ * this main format
+ */
+
+ cap.ac_subtype = format;
+ cap.ac_format.b[0] = 0;
+
+ while (ioctl(precorder->dev_fd, AUDIOIOC_GETCAPS,
+ (uintptr_t)&cap) == cap.ac_len)
+ {
+ /* Check the next set of 4 controls
+ * to find the subformat
+ */
+
+ for (x = 0; x < sizeof(cap.ac_controls.b); x++)
+ {
+ if (cap.ac_controls.b[x] == subfmt)
+ {
+ /* Sub format supported! */
+
+ break;
+ }
+ else if (cap.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(cap.ac_controls))
+ {
+ break;
+ }
+
+ /* Increment ac_format.b[0] to get next
+ * set of subformats
+ */
+
+ cap.ac_format.b[0]++;
+ }
+ }
+
+ if (supported)
+ {
+ /* Yes, it supports this format. Use this device */
+
+ return OK;
+ }
+ }
+
+ close(precorder->dev_fd);
+ }
}
/* Device not found */
@@ -111,6 +244,84 @@ static int nxrecorder_opendevice(FAR struct nxrecorder_s *precorder)
return -ENODEV;
}
+/****************************************************************************
+ * Name: nxrecorder_getmp3subformat
+ *
+ * nxrecorder_getmp3subformat() just ruturn AUDIO_SUBFMT_PCM_MP3.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_AUDIO_FORMAT_MP3
+int nxrecorder_getmp3subformat(int fd)
+{
+ return AUDIO_SUBFMT_PCM_MP3;
+}
+#endif
+
+#ifdef CONFIG_NXRECORDER_FMT_FROM_EXT
+
+/****************************************************************************
+ * Name: nxprecorder_fmtfromext
+ *
+ * nxrecorder_fmtfromext() tries to determine the file format based
+ * on the extension of the supplied filename.
+ *
+ ****************************************************************************/
+
+static inline int nxrecorder_fmtfromext(FAR struct nxrecorder_s *precorder,
+ FAR const char *pfilename,
+ FAR int *subfmt)
+{
+ FAR const char *pext;
+ uint8_t x;
+ uint8_t c;
+
+ /* Find the file extension, if any */
+
+ x = strlen(pfilename) - 1;
+ while (x > 0)
+ {
+ /* Search 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(precorder->fd);
+ }
+
+ /* 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
+
/****************************************************************************
* Name: nxrecorder_writebuffer
*
@@ -198,7 +409,7 @@ static int nxrecorder_enqueuebuffer(FAR struct nxrecorder_s *precorder,
bufdesc.u.buffer = apb;
ret = ioctl(precorder->dev_fd, AUDIOIOC_ENQUEUEBUFFER,
- (unsigned long)&bufdesc);
+ (uintptr_t)&bufdesc);
if (ret < 0)
{
int errcode = errno;
@@ -276,7 +487,7 @@ static FAR void *nxrecorder_recordthread(pthread_addr_t pvarg)
/* Query the audio device for its preferred buffer size / qty */
if ((ret = ioctl(precorder->dev_fd, AUDIOIOC_GETBUFFERINFO,
- (unsigned long) &buf_info)) != OK)
+ (uintptr_t)&buf_info)) != OK)
{
/* Driver doesn't report its buffer size. Use our default. */
@@ -316,7 +527,7 @@ static FAR void *nxrecorder_recordthread(pthread_addr_t pvarg)
buf_desc.u.pbuffer = &pbuffers[x];
ret = ioctl(precorder->dev_fd, AUDIOIOC_ALLOCBUFFER,
- (unsigned long) &buf_desc);
+ (uintptr_t)&buf_desc);
if (ret != sizeof(buf_desc))
{
/* Buffer alloc Operation not supported or error allocating! */
@@ -378,7 +589,7 @@ static FAR void *nxrecorder_recordthread(pthread_addr_t pvarg)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = ioctl(precorder->dev_fd, AUDIOIOC_START,
- (unsigned long) precorder->session);
+ (uintptr_t)precorder->session);
#else
ret = ioctl(precorder->dev_fd, AUDIOIOC_START, 0);
#endif
@@ -522,7 +733,7 @@ static FAR void *nxrecorder_recordthread(pthread_addr_t pvarg)
#ifdef CONFIG_AUDIO_MULTI_SESSION
ioctl(precorder->dev_fd, AUDIOIOC_STOP,
- (unsigned long) precorder->session);
+ (uintptr_t)precorder->session);
#else
ioctl(precorder->dev_fd, AUDIOIOC_STOP, 0);
#endif
@@ -570,7 +781,7 @@ err_out:
buf_desc.u.buffer = pbuffers[x];
ioctl(precorder->dev_fd,
AUDIOIOC_FREEBUFFER,
- (unsigned long) &buf_desc);
+ (uintptr_t)&buf_desc);
}
}
@@ -583,11 +794,11 @@ err_out:
ioctl(precorder->dev_fd,
AUDIOIOC_UNREGISTERMQ,
- (unsigned long) precorder->mq);
+ (uintptr_t)precorder->mq);
#ifdef CONFIG_AUDIO_MULTI_SESSION
ioctl(precorder->dev_fd,
AUDIOIOC_RELEASE,
- (unsigned long) precorder->session);
+ (uintptr_t)precorder->session);
#else
ioctl(precorder->dev_fd,
AUDIOIOC_RELEASE,
@@ -646,7 +857,7 @@ int nxrecorder_pause(FAR struct nxrecorder_s *precorder)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = ioctl(precorder->dev_fd, AUDIOIOC_PAUSE,
- (unsigned long) precorder->session);
+ (uintptr_t)precorder->session);
#else
ret = ioctl(precorder->dev_fd, AUDIOIOC_PAUSE, 0);
#endif
@@ -676,7 +887,7 @@ int nxrecorder_resume(FAR struct nxrecorder_s *precorder)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = ioctl(precorder->dev_fd, AUDIOIOC_RESUME,
- (unsigned long) precorder->session);
+ (uintptr_t)precorder->session);
#else
ret = ioctl(precorder->dev_fd, AUDIOIOC_RESUME, 0);
#endif
@@ -770,10 +981,10 @@ int nxrecorder_stop(FAR struct nxrecorder_s *precorder)
#endif /* CONFIG_AUDIO_EXCLUDE_STOP */
/****************************************************************************
- * Name: nxrecorder_recordraw
+ * Name: nxrecorder_recordinteral
*
- * nxrecorder_recordraw() tries to record the raw data file using the Audio
- * system. If a device is specified, it will try to use that
+ * nxrecorder_recordinternal() tries to record audio file using the Audio
+ * system. If a device is specified, it will try to use that
* device.
* Input:
* precorder Pointer to the initialized MRecorder context
@@ -792,9 +1003,10 @@ int nxrecorder_stop(FAR struct nxrecorder_s *precorder)
*
****************************************************************************/
-int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
- FAR const char *pfilename, uint8_t nchannels,
- uint8_t bpsamp, uint32_t samprate, uint8_t chmap)
+int nxrecorder_recordinternal(FAR struct nxrecorder_s *precorder,
+ FAR const char *pfilename, int filefmt,
+ uint8_t nchannels, uint8_t bpsamp,
+ uint32_t samprate, uint8_t chmap)
{
struct mq_attr attr;
struct sched_param sparam;
@@ -802,6 +1014,7 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
struct audio_caps_desc_s cap_desc;
struct ap_buffer_info_s buf_info;
int ret;
+ int subfmt = AUDIO_FMT_UNDEF;
DEBUGASSERT(precorder != NULL);
DEBUGASSERT(pfilename != NULL);
@@ -825,9 +1038,25 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
return -ENOENT;
}
+ if (filefmt == AUDIO_FMT_UNDEF)
+ {
+ filefmt = nxrecorder_fmtfromext(precorder, pfilename, &subfmt);
+ }
+
+ /* Test if we determined the file format */
+
+ if (filefmt == AUDIO_FMT_UNDEF)
+ {
+ /* Hmmm, it's some unknown / unsupported type */
+
+ auderr("ERROR: Unsupported format: %d\n", filefmt);
+ ret = -ENOSYS;
+ goto err_out_nodev;
+ }
+
/* Try to open the device */
- ret = nxrecorder_opendevice(precorder);
+ ret = nxrecorder_opendevice(precorder, filefmt, subfmt);
if (ret < 0)
{
/* Error opening the device */
@@ -840,7 +1069,7 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = ioctl(precorder->dev_fd, AUDIOIOC_RESERVE,
- (unsigned long)&precorder->session);
+ (uintptr_t)&precorder->session);
#else
ret = ioctl(precorder->dev_fd, AUDIOIOC_RESERVE, 0);
#endif
@@ -863,8 +1092,9 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
cap_desc.caps.ac_controls.hw[0] = samprate ? samprate : 48000;
cap_desc.caps.ac_controls.b[3] = samprate >> 16;
cap_desc.caps.ac_controls.b[2] = bpsamp ? bpsamp : 16;
+ cap_desc.caps.ac_subtype = filefmt;
ret = ioctl(precorder->dev_fd, AUDIOIOC_CONFIGURE,
- (unsigned long)&cap_desc);
+ (uintptr_t)&cap_desc);
if (ret < 0)
{
ret = -errno;
@@ -874,7 +1104,7 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
/* Query the audio device for its preferred buffer count */
if (ioctl(precorder->dev_fd, AUDIOIOC_GETBUFFERINFO,
- (unsigned long)&buf_info) != OK)
+ (uintptr_t)&buf_info) != OK)
{
/* Driver doesn't report its buffer size. Use our default. */
@@ -905,7 +1135,7 @@ int nxrecorder_recordraw(FAR struct nxrecorder_s *precorder,
ioctl(precorder->dev_fd,
AUDIOIOC_REGISTERMQ,
- (unsigned long)precorder->mq);
+ (uintptr_t)precorder->mq);
/* Check if there was a previous thread and join it if there was
* to perform clean-up.
diff --git a/system/nxrecorder/nxrecorder_main.c b/system/nxrecorder/nxrecorder_main.c
index b5eb5fd37..c1c21fd50 100644
--- a/system/nxrecorder/nxrecorder_main.c
+++ b/system/nxrecorder/nxrecorder_main.c
@@ -68,6 +68,8 @@ static int nxrecorder_cmd_quit(FAR struct nxrecorder_s *precorder,
FAR char *parg);
static int nxrecorder_cmd_recordraw(FAR struct nxrecorder_s *precorder,
FAR char *parg);
+static int nxrecorder_cmd_record(FAR struct nxrecorder_s *precorder,
+ FAR char *parg);
static int nxrecorder_cmd_device(FAR struct nxrecorder_s *precorder,
FAR char *parg);
@@ -120,6 +122,13 @@ static const struct mp_cmd_s g_nxrecorder_cmds[] =
nxrecorder_cmd_recordraw,
NXRECORDER_HELP_TEXT("Record a pcm raw file")
},
+ {
+ "record",
+ "filename",
+ nxrecorder_cmd_record,
+ NXRECORDER_HELP_TEXT("Record a media file")
+ },
+
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
{
"pause",
@@ -186,12 +195,13 @@ static int nxrecorder_cmd_recordraw(FAR struct nxrecorder_s *precorder,
/* Try to record the file specified */
- ret = nxrecorder_recordraw(precorder,
- filename,
- channels,
- bpsamp,
- samprate,
- chmap);
+ ret = nxrecorder_recordinternal(precorder,
+ filename,
+ AUDIO_FMT_PCM,
+ channels,
+ bpsamp,
+ samprate,
+ chmap);
/* nxrecorder_recordfile returned values:
*
@@ -231,6 +241,75 @@ static int nxrecorder_cmd_recordraw(FAR struct nxrecorder_s *precorder,
return ret;
}
+/****************************************************************************
+ * Name: nxrecorder_cmd_record
+ *
+ * nxrecorder_cmd_record() record the specified media file using the
+ * nxrecorder context.
+ *
+ ****************************************************************************/
+
+static int nxrecorder_cmd_record(FAR struct nxrecorder_s *precorder,
+ FAR char *parg)
+{
+ int ret;
+ int channels = 0;
+ int bpsamp = 0;
+ int samprate = 0;
+ int chmap = 0;
+ char filename[128];
+
+ sscanf(parg, "%s %d %d %d %d", filename, &channels, &bpsamp,
+ &samprate, &chmap);
+
+ /* Try to record the file specified */
+
+ ret = nxrecorder_recordinternal(precorder,
+ filename,
+ AUDIO_FMT_UNDEF,
+ channels,
+ bpsamp,
+ samprate,
+ chmap);
+
+ /* nxrecorder_recordfile returned values:
+ *
+ * OK File is being recorded
+ * -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: nxrecorder_cmd_stop
*