nxplayer: add mp3 offload playback demo
Mask: Only parse ID3v2 header simple. Usage: nxplayer device pcm0p play /stream/1.mp3 Signed-off-by: qiaohaijiao1 <qiaohaijiao1@xiaomi.com>
This commit is contained in:
parent
5ae46ab6a7
commit
05eadd1bd6
@ -39,6 +39,14 @@
|
|||||||
* Public Type Declarations
|
* Public Type Declarations
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct nxplayer_dec_ops_s
|
||||||
|
{
|
||||||
|
int format;
|
||||||
|
CODE int (*pre_parse)(int fd, FAR uint32_t *samplerate,
|
||||||
|
FAR uint8_t *chans, FAR uint8_t *bps);
|
||||||
|
CODE int (*fill_data)(int fd, FAR struct ap_buffer_s *apb);
|
||||||
|
};
|
||||||
|
|
||||||
/* This structure describes the internal state of the NxPlayer */
|
/* This structure describes the internal state of the NxPlayer */
|
||||||
|
|
||||||
struct nxplayer_s
|
struct nxplayer_s
|
||||||
@ -72,6 +80,8 @@ struct nxplayer_s
|
|||||||
uint16_t treble; /* Treble as a whole % */
|
uint16_t treble; /* Treble as a whole % */
|
||||||
uint16_t bass; /* Bass as a whole % */
|
uint16_t bass; /* Bass as a whole % */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
FAR const struct nxplayer_dec_ops_s *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*nxplayer_func)(FAR struct nxplayer_s *pplayer, char *pargs);
|
typedef int (*nxplayer_func)(FAR struct nxplayer_s *pplayer, char *pargs);
|
||||||
@ -480,6 +490,53 @@ int nxplayer_settreble(FAR struct nxplayer_s *pplayer, uint8_t treble);
|
|||||||
int nxplayer_systemreset(FAR struct nxplayer_s *pplayer);
|
int nxplayer_systemreset(FAR struct nxplayer_s *pplayer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_parse_mp3
|
||||||
|
*
|
||||||
|
* Performs pre-process when play mp3 file.
|
||||||
|
* Parse samplerate, channels, bps.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* pplayer - Pointer to the context to initialize
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK if file parsed successfully.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_parse_mp3(int fd, FAR uint32_t *samplerate,
|
||||||
|
FAR uint8_t *chans, FAR uint8_t *bps);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_fill_mp3
|
||||||
|
*
|
||||||
|
* Performs read mp3 frame to apb buffer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* pplayer - Pointer to the context to initialize
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK if file read successfully.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_fill_mp3(int fd, FAR struct ap_buffer_s *apb);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_fill_pcm
|
||||||
|
*
|
||||||
|
* Performs read pcm file to apb buffer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* pplayer - Pointer to the context to initialize
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK if file read successfully.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_fill_pcm(int fd, FAR struct ap_buffer_s *apb);
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ include $(APPDIR)/Make.defs
|
|||||||
# NxPlayer Library
|
# NxPlayer Library
|
||||||
|
|
||||||
CSRCS = nxplayer.c
|
CSRCS = nxplayer.c
|
||||||
|
CSRCS += nxplayer_mp3.c
|
||||||
|
CSRCS += nxplayer_pcm.c
|
||||||
|
|
||||||
ifneq ($(CONFIG_NXPLAYER_COMMAND_LINE),)
|
ifneq ($(CONFIG_NXPLAYER_COMMAND_LINE),)
|
||||||
PROGNAME = nxplayer
|
PROGNAME = nxplayer
|
||||||
|
@ -88,6 +88,10 @@ struct nxplayer_ext_fmt_s
|
|||||||
int nxplayer_getmidisubformat(int fd);
|
int nxplayer_getmidisubformat(int fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_AUDIO_FORMAT_MP3
|
||||||
|
int nxplayer_getmp3subformat(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -99,7 +103,7 @@ static const struct nxplayer_ext_fmt_s g_known_ext[] =
|
|||||||
{ "ac3", AUDIO_FMT_AC3, NULL },
|
{ "ac3", AUDIO_FMT_AC3, NULL },
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_AUDIO_FORMAT_MP3
|
#ifdef CONFIG_AUDIO_FORMAT_MP3
|
||||||
{ "mp3", AUDIO_FMT_MP3, NULL },
|
{ "mp3", AUDIO_FMT_MP3, nxplayer_getmp3subformat },
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_AUDIO_FORMAT_DTS
|
#ifdef CONFIG_AUDIO_FORMAT_DTS
|
||||||
{ "dts", AUDIO_FMT_DTS, NULL },
|
{ "dts", AUDIO_FMT_DTS, NULL },
|
||||||
@ -121,6 +125,21 @@ static const struct nxplayer_ext_fmt_s g_known_ext[] =
|
|||||||
|
|
||||||
static const int g_known_ext_count = sizeof(g_known_ext) /
|
static const int g_known_ext_count = sizeof(g_known_ext) /
|
||||||
sizeof(struct nxplayer_ext_fmt_s);
|
sizeof(struct nxplayer_ext_fmt_s);
|
||||||
|
|
||||||
|
static const struct nxplayer_dec_ops_s g_dec_ops[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
AUDIO_FMT_MP3,
|
||||||
|
nxplayer_parse_mp3,
|
||||||
|
nxplayer_fill_mp3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AUDIO_FMT_PCM,
|
||||||
|
NULL,
|
||||||
|
nxplayer_fill_pcm
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_NXPLAYER_FMT_FROM_EXT */
|
#endif /* CONFIG_NXPLAYER_FMT_FROM_EXT */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -501,6 +520,11 @@ int nxplayer_getmidisubformat(int fd)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int nxplayer_getmp3subformat(int fd)
|
||||||
|
{
|
||||||
|
return AUDIO_SUBFMT_PCM_MP3;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: nxplayer_fmtfromextension
|
* Name: nxplayer_fmtfromextension
|
||||||
*
|
*
|
||||||
@ -608,6 +632,8 @@ static int nxplayer_mediasearch(FAR struct nxplayer_s *pplayer,
|
|||||||
static int nxplayer_readbuffer(FAR struct nxplayer_s *pplayer,
|
static int nxplayer_readbuffer(FAR struct nxplayer_s *pplayer,
|
||||||
FAR struct ap_buffer_s *apb)
|
FAR struct ap_buffer_s *apb)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Validate the file is still open. It will be closed automatically when
|
/* Validate the file is still open. It will be closed automatically when
|
||||||
* we encounter the end of file (or, perhaps, a read error that we cannot
|
* we encounter the end of file (or, perhaps, a read error that we cannot
|
||||||
* handle.
|
* handle.
|
||||||
@ -622,65 +648,17 @@ static int nxplayer_readbuffer(FAR struct nxplayer_s *pplayer,
|
|||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read data into the buffer. */
|
ret = pplayer->ops->fill_data(pplayer->fd, apb);
|
||||||
|
if (ret < 0)
|
||||||
apb->nbytes = read(pplayer->fd, apb->samp, apb->nmaxbytes);
|
|
||||||
apb->curbyte = 0;
|
|
||||||
apb->flags = 0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_NXPLAYER_HTTP_STREAMING_SUPPORT
|
|
||||||
/* read data up to nmaxbytes from network */
|
|
||||||
|
|
||||||
while (0 < apb->nbytes && apb->nbytes < apb->nmaxbytes)
|
|
||||||
{
|
{
|
||||||
int n = apb->nmaxbytes - apb->nbytes;
|
|
||||||
int ret = read(pplayer->fd, &apb->samp[apb->nbytes], n);
|
|
||||||
|
|
||||||
if (0 >= ret)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
apb->nbytes += ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (apb->nbytes < apb->nmaxbytes)
|
|
||||||
{
|
|
||||||
#if defined (CONFIG_DEBUG_AUDIO_INFO) || defined (CONFIG_DEBUG_AUDIO_ERROR)
|
|
||||||
int errcode = errno;
|
|
||||||
|
|
||||||
audinfo("Closing audio file, nbytes=%d errcode=%d\n",
|
|
||||||
apb->nbytes, errcode);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* End of file or read error.. We are finished with this file in any
|
/* End of file or read error.. We are finished with this file in any
|
||||||
* event.
|
* event.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
close(pplayer->fd);
|
close(pplayer->fd);
|
||||||
pplayer->fd = -1;
|
pplayer->fd = -1;
|
||||||
|
|
||||||
/* Set a flag to indicate that this is the final buffer in the stream */
|
|
||||||
|
|
||||||
apb->flags |= AUDIO_APB_FINAL;
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_AUDIO_ERROR
|
|
||||||
/* Was this a file read error */
|
|
||||||
|
|
||||||
if (apb->nbytes == 0 && errcode != 0)
|
|
||||||
{
|
|
||||||
DEBUGASSERT(errcode > 0);
|
|
||||||
auderr("ERROR: fread failed: %d\n", errcode);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return OK to indicate that the buffer should be passed through to the
|
|
||||||
* audio device. This does not necessarily indicate that data was read
|
|
||||||
* correctly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1150,6 +1128,7 @@ err_out:
|
|||||||
pplayer->dev_fd = -1; /* Mark device as closed */
|
pplayer->dev_fd = -1; /* Mark device as closed */
|
||||||
mq_close(pplayer->mq); /* Close the message queue */
|
mq_close(pplayer->mq); /* Close the message queue */
|
||||||
mq_unlink(pplayer->mqname); /* Unlink the message queue */
|
mq_unlink(pplayer->mqname); /* Unlink the message queue */
|
||||||
|
pplayer->ops = NULL; /* Clear offload parser */
|
||||||
pplayer->state = NXPLAYER_STATE_IDLE; /* Go to IDLE */
|
pplayer->state = NXPLAYER_STATE_IDLE; /* Go to IDLE */
|
||||||
|
|
||||||
sem_post(&pplayer->sem); /* Release the semaphore */
|
sem_post(&pplayer->sem); /* Release the semaphore */
|
||||||
@ -1780,6 +1759,7 @@ static int nxplayer_playinternal(FAR struct nxplayer_s *pplayer,
|
|||||||
#endif
|
#endif
|
||||||
int tmpsubfmt = AUDIO_FMT_UNDEF;
|
int tmpsubfmt = AUDIO_FMT_UNDEF;
|
||||||
int ret;
|
int ret;
|
||||||
|
int c;
|
||||||
|
|
||||||
DEBUGASSERT(pplayer != NULL);
|
DEBUGASSERT(pplayer != NULL);
|
||||||
DEBUGASSERT(pfilename != NULL);
|
DEBUGASSERT(pfilename != NULL);
|
||||||
@ -1877,6 +1857,26 @@ static int nxplayer_playinternal(FAR struct nxplayer_s *pplayer,
|
|||||||
goto err_out_nodev;
|
goto err_out_nodev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (c = 0; c < sizeof(g_dec_ops) / sizeof(g_dec_ops[0]); c++)
|
||||||
|
{
|
||||||
|
if (g_dec_ops[c].format == filefmt)
|
||||||
|
{
|
||||||
|
pplayer->ops = &g_dec_ops[c];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pplayer->ops)
|
||||||
|
{
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pplayer->ops->pre_parse)
|
||||||
|
{
|
||||||
|
ret = pplayer->ops->pre_parse(pplayer->fd, &samprate,
|
||||||
|
&nchannels, &bpsamp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to reserve the device */
|
/* Try to reserve the device */
|
||||||
|
|
||||||
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
#ifdef CONFIG_AUDIO_MULTI_SESSION
|
||||||
@ -1906,6 +1906,7 @@ static int nxplayer_playinternal(FAR struct nxplayer_s *pplayer,
|
|||||||
cap_desc.caps.ac_controls.hw[0] = samprate;
|
cap_desc.caps.ac_controls.hw[0] = samprate;
|
||||||
cap_desc.caps.ac_controls.b[3] = samprate >> 16;
|
cap_desc.caps.ac_controls.b[3] = samprate >> 16;
|
||||||
cap_desc.caps.ac_controls.b[2] = bpsamp;
|
cap_desc.caps.ac_controls.b[2] = bpsamp;
|
||||||
|
cap_desc.caps.ac_subtype = filefmt;
|
||||||
|
|
||||||
ioctl(pplayer->dev_fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
|
ioctl(pplayer->dev_fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
|
||||||
}
|
}
|
||||||
|
311
system/nxplayer/nxplayer_mp3.c
Normal file
311
system/nxplayer/nxplayer_mp3.c
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* apps/system/nxplayer/nxplayer_mp3.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <nuttx/audio/audio.h>
|
||||||
|
|
||||||
|
#include "system/nxplayer.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define ID3V2_BIT_MASK 0x7F
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Type Declarations
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
const static uint16_t g_mpa_freq_tab[3] =
|
||||||
|
{
|
||||||
|
44100, 48000, 32000
|
||||||
|
};
|
||||||
|
|
||||||
|
const static uint16_t g_mpa_bitrate_tab[2][3][15] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{
|
||||||
|
0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int nxplayer_check_mpeg(uint32_t header)
|
||||||
|
{
|
||||||
|
/* header */
|
||||||
|
|
||||||
|
if ((header & 0xffe00000) != 0xffe00000)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* version check */
|
||||||
|
|
||||||
|
if ((header & (3 << 19)) == 1 << 19)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* layer check */
|
||||||
|
|
||||||
|
if ((header & (3 << 17)) == 0)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bit rate */
|
||||||
|
|
||||||
|
if ((header & (0xf << 12)) == 0xf << 12)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frequency */
|
||||||
|
|
||||||
|
if ((header & (3 << 10)) == 3 << 10)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nxplayer_parse_mpeg(uint32_t header, FAR uint32_t *samplerate,
|
||||||
|
FAR uint8_t *chans, FAR uint8_t *bps)
|
||||||
|
{
|
||||||
|
int sample_rate;
|
||||||
|
int frame_size;
|
||||||
|
int padding;
|
||||||
|
int mpeg25;
|
||||||
|
int sr_idx;
|
||||||
|
int br_idx;
|
||||||
|
int layer;
|
||||||
|
int mode;
|
||||||
|
int lsf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nxplayer_check_mpeg(header);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header & (1 << 20))
|
||||||
|
{
|
||||||
|
lsf = (header & (1 << 19)) ? 0 : 1;
|
||||||
|
mpeg25 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lsf = 1;
|
||||||
|
mpeg25 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer = 4 - ((header >> 17) & 3);
|
||||||
|
br_idx = (header >> 12) & 0xf;
|
||||||
|
sr_idx = (header >> 10) & 3;
|
||||||
|
padding = (header >> 9) & 1;
|
||||||
|
mode = (header >> 6) & 3;
|
||||||
|
|
||||||
|
if (sr_idx >= sizeof(g_mpa_freq_tab) / sizeof(g_mpa_freq_tab[0]) ||
|
||||||
|
br_idx >= 0xf)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_rate = g_mpa_freq_tab[sr_idx] >> (lsf + mpeg25);
|
||||||
|
|
||||||
|
if (br_idx != 0)
|
||||||
|
{
|
||||||
|
frame_size = g_mpa_bitrate_tab[lsf][layer - 1][br_idx];
|
||||||
|
|
||||||
|
switch (layer)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
frame_size = (frame_size * 12000) / sample_rate;
|
||||||
|
frame_size = (frame_size + padding) * 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
frame_size = (frame_size * 144000) / sample_rate;
|
||||||
|
frame_size += padding;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case 3:
|
||||||
|
frame_size = (frame_size * 144000) / (sample_rate << lsf);
|
||||||
|
frame_size += padding;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if no frame size computed, signal it */
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (samplerate)
|
||||||
|
{
|
||||||
|
*samplerate = sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chans)
|
||||||
|
{
|
||||||
|
*chans = mode == 3 ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bps)
|
||||||
|
{
|
||||||
|
*bps = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_parse_mp3
|
||||||
|
*
|
||||||
|
* nxplayer_parse_mp3() parse mp3 header, get samplerate, channels, bps.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_parse_mp3(int fd, FAR uint32_t *samplerate,
|
||||||
|
FAR uint8_t *chans, FAR uint8_t *bps)
|
||||||
|
{
|
||||||
|
uint32_t mpa_header;
|
||||||
|
uint8_t buffer[10];
|
||||||
|
off_t position;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read(fd, buffer, sizeof(buffer));
|
||||||
|
if (ret < sizeof(buffer))
|
||||||
|
{
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
position = (buffer[6] & ID3V2_BIT_MASK) * 0x200000 +
|
||||||
|
(buffer[7] & ID3V2_BIT_MASK) * 0x4000 +
|
||||||
|
(buffer[8] & ID3V2_BIT_MASK) * 0x80 +
|
||||||
|
(buffer[9] & ID3V2_BIT_MASK) +
|
||||||
|
sizeof(buffer);
|
||||||
|
|
||||||
|
lseek(fd, position, SEEK_SET);
|
||||||
|
|
||||||
|
read(fd, buffer, 4);
|
||||||
|
mpa_header = buffer[0] << 24 |
|
||||||
|
buffer[1] << 16 |
|
||||||
|
buffer[2] << 8 |
|
||||||
|
buffer[3];
|
||||||
|
|
||||||
|
ret = nxplayer_parse_mpeg(mpa_header, samplerate, chans, bps);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, position, SEEK_SET);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_fill_mp3
|
||||||
|
*
|
||||||
|
* nxplayer_fill_mp3 fill mp3 data into apb buffer.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_fill_mp3(int fd, FAR struct ap_buffer_s *apb)
|
||||||
|
{
|
||||||
|
uint32_t mpa_header;
|
||||||
|
uint8_t header[16];
|
||||||
|
int h_size = 4;
|
||||||
|
int b_size;
|
||||||
|
int size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read(fd, header, h_size);
|
||||||
|
if (ret < h_size)
|
||||||
|
{
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpa_header = header[0] << 24 |
|
||||||
|
header[1] << 16 |
|
||||||
|
header[2] << 8 |
|
||||||
|
header[3];
|
||||||
|
|
||||||
|
size = nxplayer_parse_mpeg(mpa_header, NULL, NULL, NULL);
|
||||||
|
if (size < 0)
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(apb->samp, header, h_size);
|
||||||
|
|
||||||
|
b_size = size - h_size;
|
||||||
|
ret = read(fd, apb->samp + h_size, b_size + 8);
|
||||||
|
if (ret < b_size)
|
||||||
|
{
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, -8, SEEK_CUR);
|
||||||
|
|
||||||
|
apb->nbytes = size + 8;
|
||||||
|
apb->curbyte = 0;
|
||||||
|
apb->flags = 0;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
104
system/nxplayer/nxplayer_pcm.c
Normal file
104
system/nxplayer/nxplayer_pcm.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* apps/system/nxplayer/nxplayer_pcm.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/audio/audio.h>
|
||||||
|
|
||||||
|
#include "system/nxplayer.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: nxplayer_fill_pcm
|
||||||
|
*
|
||||||
|
* nxplayer_fill_pcm fill pcm data into apb buffer.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int nxplayer_fill_pcm(int fd, FAR struct ap_buffer_s *apb)
|
||||||
|
{
|
||||||
|
/* Read data into the buffer. */
|
||||||
|
|
||||||
|
apb->nbytes = read(fd, apb->samp, apb->nmaxbytes);
|
||||||
|
apb->curbyte = 0;
|
||||||
|
apb->flags = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NXPLAYER_HTTP_STREAMING_SUPPORT
|
||||||
|
/* read data up to nmaxbytes from network */
|
||||||
|
|
||||||
|
while (0 < apb->nbytes && apb->nbytes < apb->nmaxbytes)
|
||||||
|
{
|
||||||
|
int n = apb->nmaxbytes - apb->nbytes;
|
||||||
|
int ret = read(fd, &apb->samp[apb->nbytes], n);
|
||||||
|
|
||||||
|
if (0 >= ret)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
apb->nbytes += ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (apb->nbytes < apb->nmaxbytes)
|
||||||
|
{
|
||||||
|
#if defined (CONFIG_DEBUG_AUDIO_INFO) || defined (CONFIG_DEBUG_AUDIO_ERROR)
|
||||||
|
int errcode = errno;
|
||||||
|
|
||||||
|
audinfo("Closing audio file, nbytes=%d errcode=%d\n",
|
||||||
|
apb->nbytes, errcode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set a flag to indicate that this is the final buffer in the stream */
|
||||||
|
|
||||||
|
apb->flags |= AUDIO_APB_FINAL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_AUDIO_ERROR
|
||||||
|
/* Was this a file read error */
|
||||||
|
|
||||||
|
if (apb->nbytes == 0 && errcode != 0)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(errcode > 0);
|
||||||
|
auderr("ERROR: fread failed: %d\n", errcode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return OK to indicate that the buffer should be passed through to the
|
||||||
|
* audio device. This does not necessarily indicate that data was read
|
||||||
|
* correctly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user