mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-28 05:06:32 +00:00
I2S: add command i2sloop (#22807)
* revert upstream change of the library, fix memory leak by using stack again * add i2sloop command
This commit is contained in:
parent
cf739e9522
commit
03e8497211
@ -482,7 +482,7 @@ static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch)
|
|||||||
int pitch_index;
|
int pitch_index;
|
||||||
VARDECL( opus_val16, lp_pitch_buf );
|
VARDECL( opus_val16, lp_pitch_buf );
|
||||||
SAVE_STACK;
|
SAVE_STACK;
|
||||||
opus_val16 *lp_pitch_buf = (opus_val16*)malloc((DECODE_BUFFER_SIZE>>1) * sizeof(opus_val16)); //ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 );
|
ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 );
|
||||||
pitch_downsample(decode_mem, lp_pitch_buf,
|
pitch_downsample(decode_mem, lp_pitch_buf,
|
||||||
DECODE_BUFFER_SIZE, C, arch);
|
DECODE_BUFFER_SIZE, C, arch);
|
||||||
pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf,
|
pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf,
|
||||||
@ -490,7 +490,6 @@ static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch)
|
|||||||
PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch);
|
PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch);
|
||||||
pitch_index = PLC_PITCH_LAG_MAX-pitch_index;
|
pitch_index = PLC_PITCH_LAG_MAX-pitch_index;
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
free(lp_pitch_buf);
|
|
||||||
return pitch_index;
|
return pitch_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,4 +207,3 @@
|
|||||||
# define __restrict__
|
# define __restrict__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
@ -239,30 +239,21 @@ opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus
|
|||||||
|
|
||||||
int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
|
int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
|
||||||
{
|
{
|
||||||
OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer));
|
OpusRepacketizer rp;
|
||||||
opus_int32 ret;
|
opus_int32 ret;
|
||||||
if (len < 1) {
|
if (len < 1)
|
||||||
free(rp);
|
|
||||||
return OPUS_BAD_ARG;
|
return OPUS_BAD_ARG;
|
||||||
}
|
if (len==new_len)
|
||||||
if (len==new_len) {
|
|
||||||
free(rp);
|
|
||||||
return OPUS_OK;
|
return OPUS_OK;
|
||||||
}
|
else if (len > new_len)
|
||||||
else if (len > new_len) {
|
|
||||||
free(rp);
|
|
||||||
return OPUS_BAD_ARG;
|
return OPUS_BAD_ARG;
|
||||||
}
|
opus_repacketizer_init(&rp);
|
||||||
opus_repacketizer_init(rp);
|
|
||||||
/* Moving payload to the end of the packet so we can do in-place padding */
|
/* Moving payload to the end of the packet so we can do in-place padding */
|
||||||
OPUS_MOVE(data+new_len-len, data, len);
|
OPUS_MOVE(data+new_len-len, data, len);
|
||||||
ret = opus_repacketizer_cat(rp, data+new_len-len, len);
|
ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
|
||||||
if (ret != OPUS_OK) {
|
if (ret != OPUS_OK)
|
||||||
free(rp);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
|
||||||
ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, new_len, 0, 1);
|
|
||||||
free(rp);
|
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return OPUS_OK;
|
return OPUS_OK;
|
||||||
else
|
else
|
||||||
@ -271,20 +262,15 @@ int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
|
|||||||
|
|
||||||
opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
|
opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
|
||||||
{
|
{
|
||||||
OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer));
|
OpusRepacketizer rp;
|
||||||
opus_int32 ret;
|
opus_int32 ret;
|
||||||
if (len < 1) {
|
if (len < 1)
|
||||||
free(rp);
|
|
||||||
return OPUS_BAD_ARG;
|
return OPUS_BAD_ARG;
|
||||||
}
|
opus_repacketizer_init(&rp);
|
||||||
opus_repacketizer_init(rp);
|
ret = opus_repacketizer_cat(&rp, data, len);
|
||||||
ret = opus_repacketizer_cat(rp, data, len);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
|
||||||
free(rp);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
|
||||||
ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, len, 0, 0);
|
|
||||||
free(rp);
|
|
||||||
celt_assert(ret > 0 && ret <= len);
|
celt_assert(ret > 0 && ret <= len);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -326,14 +312,12 @@ opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, in
|
|||||||
unsigned char toc;
|
unsigned char toc;
|
||||||
opus_int16 size[48];
|
opus_int16 size[48];
|
||||||
opus_int32 packet_offset;
|
opus_int32 packet_offset;
|
||||||
OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer));
|
OpusRepacketizer rp;
|
||||||
unsigned char *dst;
|
unsigned char *dst;
|
||||||
opus_int32 dst_len;
|
opus_int32 dst_len;
|
||||||
|
|
||||||
if (len < 1){
|
if (len < 1)
|
||||||
free(rp);
|
|
||||||
return OPUS_BAD_ARG;
|
return OPUS_BAD_ARG;
|
||||||
}
|
|
||||||
dst = data;
|
dst = data;
|
||||||
dst_len = 0;
|
dst_len = 0;
|
||||||
/* Unpad all frames */
|
/* Unpad all frames */
|
||||||
@ -341,34 +325,25 @@ opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, in
|
|||||||
{
|
{
|
||||||
opus_int32 ret;
|
opus_int32 ret;
|
||||||
int self_delimited = s!=nb_streams-1;
|
int self_delimited = s!=nb_streams-1;
|
||||||
if (len<=0) {
|
if (len<=0)
|
||||||
free(rp);
|
|
||||||
return OPUS_INVALID_PACKET;
|
return OPUS_INVALID_PACKET;
|
||||||
}
|
opus_repacketizer_init(&rp);
|
||||||
opus_repacketizer_init(rp);
|
|
||||||
ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
|
ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
|
||||||
size, NULL, &packet_offset);
|
size, NULL, &packet_offset);
|
||||||
if (ret<0) {
|
if (ret<0)
|
||||||
free(rp);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
|
||||||
ret = opus_repacketizer_cat_impl(rp, data, packet_offset, self_delimited);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
|
||||||
free(rp);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
|
||||||
ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, dst, len, self_delimited, 0);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
|
||||||
free(rp);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
dst_len += ret;
|
dst_len += ret;
|
||||||
dst += ret;
|
dst += ret;
|
||||||
data += packet_offset;
|
data += packet_offset;
|
||||||
len -= packet_offset;
|
len -= packet_offset;
|
||||||
}
|
}
|
||||||
free(rp);
|
|
||||||
return dst_len;
|
return dst_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +80,10 @@ void silk_NLSF2A(
|
|||||||
};
|
};
|
||||||
const unsigned char *ordering;
|
const unsigned char *ordering;
|
||||||
opus_int k, i, dd;
|
opus_int k, i, dd;
|
||||||
opus_int32 *cos_LSF_QA = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC );
|
opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
|
||||||
opus_int32 *P = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC / 2 + 1));
|
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
|
||||||
opus_int32 *Q= (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC / 2 + 1));
|
|
||||||
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
|
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
|
||||||
opus_int32 *a32_QA1 = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC );
|
opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
|
||||||
|
|
||||||
silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
|
silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
|
||||||
celt_assert( d==10 || d==16 );
|
celt_assert( d==10 || d==16 );
|
||||||
@ -138,9 +137,5 @@ void silk_NLSF2A(
|
|||||||
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
|
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(cos_LSF_QA);
|
|
||||||
free(P);
|
|
||||||
free(Q);
|
|
||||||
free(a32_QA1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,12 +57,12 @@ void silk_burg_modified_c(
|
|||||||
opus_int k, n, s, lz, rshifts, reached_max_gain;
|
opus_int k, n, s, lz, rshifts, reached_max_gain;
|
||||||
opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
|
||||||
const opus_int16 *x_ptr;
|
const opus_int16 *x_ptr;
|
||||||
opus_int32 *C_first_row = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC);
|
opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
|
||||||
opus_int32 *C_last_row = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC);
|
opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
|
||||||
opus_int32 *Af_QA = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC);
|
opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
|
||||||
opus_int32 *CAf = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC+1));
|
opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
|
||||||
opus_int32 *CAb = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC+1));
|
opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
|
||||||
opus_int32 *xcorr = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC);
|
opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
|
||||||
opus_int64 C0_64;
|
opus_int64 C0_64;
|
||||||
|
|
||||||
celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
|
celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
|
||||||
@ -277,10 +277,4 @@ void silk_burg_modified_c(
|
|||||||
*res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
|
*res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
|
||||||
*res_nrg_Q = -rshifts;
|
*res_nrg_Q = -rshifts;
|
||||||
}
|
}
|
||||||
free(C_first_row);
|
|
||||||
free(C_last_row);
|
|
||||||
free(Af_QA);
|
|
||||||
free(CAf);
|
|
||||||
free(CAb);
|
|
||||||
free(xcorr);
|
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ void silk_warped_autocorrelation_FIX_c(
|
|||||||
{
|
{
|
||||||
opus_int n, i, lsh;
|
opus_int n, i, lsh;
|
||||||
opus_int32 tmp1_QS, tmp2_QS;
|
opus_int32 tmp1_QS, tmp2_QS;
|
||||||
opus_int32 *state_QS = (opus_int32*)calloc(MAX_SHAPE_LPC_ORDER + 1, sizeof(opus_int32));
|
opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
|
||||||
opus_int64 *corr_QC = (opus_int64*)calloc(MAX_SHAPE_LPC_ORDER + 1, sizeof(opus_int64));
|
opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
|
||||||
|
|
||||||
/* Order must be even */
|
/* Order must be even */
|
||||||
celt_assert( ( order & 1 ) == 0 );
|
celt_assert( ( order & 1 ) == 0 );
|
||||||
@ -88,7 +88,5 @@ void silk_warped_autocorrelation_FIX_c(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
|
silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
|
||||||
free(state_QS);
|
|
||||||
free(corr_QC);
|
|
||||||
}
|
}
|
||||||
#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */
|
#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */
|
||||||
|
@ -48,8 +48,7 @@ void silk_resampler_down2_3(
|
|||||||
opus_int32 *buf_ptr;
|
opus_int32 *buf_ptr;
|
||||||
SAVE_STACK;
|
SAVE_STACK;
|
||||||
|
|
||||||
// ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 );
|
ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 );
|
||||||
opus_int32 *buf = (opus_int32*)malloc((RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR) * sizeof(opus_int32));
|
|
||||||
|
|
||||||
/* Copy buffered samples to start of buffer */
|
/* Copy buffered samples to start of buffer */
|
||||||
silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) );
|
silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) );
|
||||||
@ -100,6 +99,5 @@ void silk_resampler_down2_3(
|
|||||||
|
|
||||||
/* Copy last part of filtered signal to the state for the next call */
|
/* Copy last part of filtered signal to the state for the next call */
|
||||||
silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
|
silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
|
||||||
free(buf);
|
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
}
|
}
|
||||||
|
@ -90,12 +90,12 @@ int op_test(OpusHead *_head,
|
|||||||
ogg_sync_init(&oy);
|
ogg_sync_init(&oy);
|
||||||
data=ogg_sync_buffer(&oy,(long)_initial_bytes);
|
data=ogg_sync_buffer(&oy,(long)_initial_bytes);
|
||||||
if(data!=NULL){
|
if(data!=NULL){
|
||||||
ogg_stream_state *os = (ogg_stream_state*)malloc(sizeof(ogg_stream_state));
|
ogg_stream_state os;
|
||||||
ogg_page og;
|
ogg_page og;
|
||||||
int ret;
|
int ret;
|
||||||
memcpy(data,_initial_data,_initial_bytes);
|
memcpy(data,_initial_data,_initial_bytes);
|
||||||
ogg_sync_wrote(&oy,(long)_initial_bytes);
|
ogg_sync_wrote(&oy,(long)_initial_bytes);
|
||||||
ogg_stream_init(os,-1);
|
ogg_stream_init(&os,-1);
|
||||||
err=OP_FALSE;
|
err=OP_FALSE;
|
||||||
do{
|
do{
|
||||||
ogg_packet op;
|
ogg_packet op;
|
||||||
@ -104,11 +104,11 @@ int op_test(OpusHead *_head,
|
|||||||
if(ret<0)continue;
|
if(ret<0)continue;
|
||||||
/*Stop if we run out of data.*/
|
/*Stop if we run out of data.*/
|
||||||
if(!ret)break;
|
if(!ret)break;
|
||||||
ogg_stream_reset_serialno(os,ogg_page_serialno(&og));
|
ogg_stream_reset_serialno(&os,ogg_page_serialno(&og));
|
||||||
ogg_stream_pagein(os,&og);
|
ogg_stream_pagein(&os,&og);
|
||||||
/*Only process the first packet on this page (if it's a BOS packet,
|
/*Only process the first packet on this page (if it's a BOS packet,
|
||||||
it's required to be the only one).*/
|
it's required to be the only one).*/
|
||||||
if(ogg_stream_packetout(os,&op)==1){
|
if(ogg_stream_packetout(&os,&op)==1){
|
||||||
if(op.b_o_s){
|
if(op.b_o_s){
|
||||||
ret=opus_head_parse(_head,op.packet,op.bytes);
|
ret=opus_head_parse(_head,op.packet,op.bytes);
|
||||||
/*If this didn't look like Opus, keep going.*/
|
/*If this didn't look like Opus, keep going.*/
|
||||||
@ -122,8 +122,7 @@ int op_test(OpusHead *_head,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(err==OP_FALSE);
|
while(err==OP_FALSE);
|
||||||
ogg_stream_clear(os);
|
ogg_stream_clear(&os);
|
||||||
free(os);
|
|
||||||
}
|
}
|
||||||
else err=OP_EFAULT;
|
else err=OP_EFAULT;
|
||||||
ogg_sync_clear(&oy);
|
ogg_sync_clear(&oy);
|
||||||
@ -836,7 +835,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
ogg_int64_t cur_page_gp;
|
ogg_int64_t cur_page_gp;
|
||||||
ogg_uint32_t serialno;
|
ogg_uint32_t serialno;
|
||||||
opus_int32 total_duration;
|
opus_int32 total_duration;
|
||||||
int *durations = (int*)malloc(255 * sizeof(int));
|
int durations[255];
|
||||||
int cur_page_eos;
|
int cur_page_eos;
|
||||||
int op_count;
|
int op_count;
|
||||||
int pi;
|
int pi;
|
||||||
@ -853,31 +852,26 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
Otherwise there are no audio data packets in the whole logical stream.*/
|
Otherwise there are no audio data packets in the whole logical stream.*/
|
||||||
if(OP_UNLIKELY(page_offset<0)){
|
if(OP_UNLIKELY(page_offset<0)){
|
||||||
/*Fail if there was a read error.*/
|
/*Fail if there was a read error.*/
|
||||||
if(page_offset<OP_FALSE) { free(durations); return (int)page_offset; }
|
if(page_offset<OP_FALSE)return (int)page_offset;
|
||||||
/*Fail if the pre-skip is non-zero, since it's asking us to skip more
|
/*Fail if the pre-skip is non-zero, since it's asking us to skip more
|
||||||
samples than exist.*/
|
samples than exist.*/
|
||||||
if(_link->head.pre_skip>0) {free(durations); return OP_EBADTIMESTAMP;}
|
if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
|
||||||
_link->pcm_file_offset=0;
|
_link->pcm_file_offset=0;
|
||||||
/*Set pcm_end and end_offset so we can skip the call to
|
/*Set pcm_end and end_offset so we can skip the call to
|
||||||
op_find_final_pcm_offset().*/
|
op_find_final_pcm_offset().*/
|
||||||
_link->pcm_start=_link->pcm_end=0;
|
_link->pcm_start=_link->pcm_end=0;
|
||||||
_link->end_offset=_link->data_offset;
|
_link->end_offset=_link->data_offset;
|
||||||
free(durations);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*Similarly, if we hit the next link in the chain, we've gone too far.*/
|
/*Similarly, if we hit the next link in the chain, we've gone too far.*/
|
||||||
if(OP_UNLIKELY(ogg_page_bos(_og))){
|
if(OP_UNLIKELY(ogg_page_bos(_og))){
|
||||||
if(_link->head.pre_skip>0) {
|
if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
|
||||||
free(durations);
|
|
||||||
return OP_EBADTIMESTAMP;
|
|
||||||
}
|
|
||||||
/*Set pcm_end and end_offset so we can skip the call to
|
/*Set pcm_end and end_offset so we can skip the call to
|
||||||
op_find_final_pcm_offset().*/
|
op_find_final_pcm_offset().*/
|
||||||
_link->pcm_file_offset=0;
|
_link->pcm_file_offset=0;
|
||||||
_link->pcm_start=_link->pcm_end=0;
|
_link->pcm_start=_link->pcm_end=0;
|
||||||
_link->end_offset=_link->data_offset;
|
_link->end_offset=_link->data_offset;
|
||||||
/*Tell the caller we've got a buffered page for them.*/
|
/*Tell the caller we've got a buffered page for them.*/
|
||||||
free(durations);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*Ignore pages from other streams (not strictly necessary, because of the
|
/*Ignore pages from other streams (not strictly necessary, because of the
|
||||||
@ -907,10 +901,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
cur_page_gp=_of->op[op_count-1].granulepos;
|
cur_page_gp=_of->op[op_count-1].granulepos;
|
||||||
/*But getting a packet without a valid granule position on the page is not
|
/*But getting a packet without a valid granule position on the page is not
|
||||||
okay.*/
|
okay.*/
|
||||||
if(cur_page_gp==-1) {
|
if(cur_page_gp==-1)return OP_EBADTIMESTAMP;
|
||||||
free(durations);
|
|
||||||
return OP_EBADTIMESTAMP;
|
|
||||||
}
|
|
||||||
cur_page_eos=_of->op[op_count-1].e_o_s;
|
cur_page_eos=_of->op[op_count-1].e_o_s;
|
||||||
if(OP_LIKELY(!cur_page_eos)){
|
if(OP_LIKELY(!cur_page_eos)){
|
||||||
/*The EOS flag wasn't set.
|
/*The EOS flag wasn't set.
|
||||||
@ -919,7 +910,6 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
|
if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
|
||||||
/*The starting granule position MUST not be smaller than the amount of
|
/*The starting granule position MUST not be smaller than the amount of
|
||||||
audio on the first page with completed packets.*/
|
audio on the first page with completed packets.*/
|
||||||
free(durations);
|
|
||||||
return OP_EBADTIMESTAMP;
|
return OP_EBADTIMESTAMP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -933,7 +923,6 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
/*However, the end-trimming MUST not ask us to trim more samples than
|
/*However, the end-trimming MUST not ask us to trim more samples than
|
||||||
exist after applying the pre-skip.*/
|
exist after applying the pre-skip.*/
|
||||||
if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){
|
if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){
|
||||||
free(durations);
|
|
||||||
return OP_EBADTIMESTAMP;
|
return OP_EBADTIMESTAMP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -968,7 +957,6 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||||||
_link->pcm_file_offset=0;
|
_link->pcm_file_offset=0;
|
||||||
_of->prev_packet_gp=_link->pcm_start=pcm_start;
|
_of->prev_packet_gp=_link->pcm_start=pcm_start;
|
||||||
_of->prev_page_offset=page_offset;
|
_of->prev_page_offset=page_offset;
|
||||||
free(durations);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,34 +1391,32 @@ static int op_open_seekable2_impl(OggOpusFile *_of){
|
|||||||
/*64 seek records should be enough for anybody.
|
/*64 seek records should be enough for anybody.
|
||||||
Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE
|
Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE
|
||||||
granularity, much more than enough.*/
|
granularity, much more than enough.*/
|
||||||
OpusSeekRecord *sr = (OpusSeekRecord*)malloc(64 * sizeof(OpusSeekRecord));
|
OpusSeekRecord sr[64];
|
||||||
opus_int64 data_offset;
|
opus_int64 data_offset;
|
||||||
int ret;
|
int ret;
|
||||||
/*We can seek, so set out learning all about this file.*/
|
/*We can seek, so set out learning all about this file.*/
|
||||||
(*_of->callbacks.seek)(_of->stream,0,SEEK_END);
|
(*_of->callbacks.seek)(_of->stream,0,SEEK_END);
|
||||||
_of->offset=_of->end=(*_of->callbacks.tell)(_of->stream);
|
_of->offset=_of->end=(*_of->callbacks.tell)(_of->stream);
|
||||||
if(OP_UNLIKELY(_of->end<0)){free(sr); return OP_EREAD;}
|
if(OP_UNLIKELY(_of->end<0))return OP_EREAD;
|
||||||
data_offset=_of->links[0].data_offset;
|
data_offset=_of->links[0].data_offset;
|
||||||
if(OP_UNLIKELY(_of->end<data_offset)){ free(sr); return OP_EBADLINK;}
|
if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
|
||||||
/*Get the offset of the last page of the physical bitstream, or, if we're
|
/*Get the offset of the last page of the physical bitstream, or, if we're
|
||||||
lucky, the last Opus page of the first link, as most Ogg Opus files will
|
lucky, the last Opus page of the first link, as most Ogg Opus files will
|
||||||
contain a single logical bitstream.*/
|
contain a single logical bitstream.*/
|
||||||
ret=op_get_prev_page_serial(_of,sr,_of->end,
|
ret=op_get_prev_page_serial(_of,sr,_of->end,
|
||||||
_of->links[0].serialno,_of->serialnos,_of->nserialnos);
|
_of->links[0].serialno,_of->serialnos,_of->nserialnos);
|
||||||
if(OP_UNLIKELY(ret<0)){free(sr); return ret;}
|
if(OP_UNLIKELY(ret<0))return ret;
|
||||||
/*If there's any trailing junk, forget about it.*/
|
/*If there's any trailing junk, forget about it.*/
|
||||||
_of->end=sr[0].offset+sr[0].size;
|
_of->end=sr[0].offset+sr[0].size;
|
||||||
if(OP_UNLIKELY(_of->end<data_offset)){free(sr); return OP_EBADLINK;}
|
if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
|
||||||
/*Now enumerate the bitstream structure.*/
|
/*Now enumerate the bitstream structure.*/
|
||||||
ret = op_bisect_forward_serialno(_of,data_offset,sr,sizeof(sr)/sizeof(*sr),
|
return op_bisect_forward_serialno(_of,data_offset,sr,sizeof(sr)/sizeof(*sr),
|
||||||
&_of->serialnos,&_of->nserialnos,&_of->cserialnos);
|
&_of->serialnos,&_of->nserialnos,&_of->cserialnos);
|
||||||
free(sr);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int op_open_seekable2(OggOpusFile *_of){
|
static int op_open_seekable2(OggOpusFile *_of){
|
||||||
ogg_sync_state oy_start;
|
ogg_sync_state oy_start;
|
||||||
ogg_stream_state *os_start = (ogg_stream_state*)malloc(sizeof(ogg_stream_state));
|
ogg_stream_state os_start;
|
||||||
ogg_packet *op_start;
|
ogg_packet *op_start;
|
||||||
opus_int64 prev_page_offset;
|
opus_int64 prev_page_offset;
|
||||||
opus_int64 start_offset;
|
opus_int64 start_offset;
|
||||||
@ -1449,9 +1435,9 @@ static int op_open_seekable2(OggOpusFile *_of){
|
|||||||
start_op_count=_of->op_count;
|
start_op_count=_of->op_count;
|
||||||
/*This is a bit too large to put on the stack unconditionally.*/
|
/*This is a bit too large to put on the stack unconditionally.*/
|
||||||
op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count);
|
op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count);
|
||||||
if(op_start==NULL){free(os_start); return OP_EFAULT;}
|
if(op_start==NULL)return OP_EFAULT;
|
||||||
*&oy_start=_of->oy;
|
*&oy_start=_of->oy;
|
||||||
*os_start=_of->os;
|
*&os_start=_of->os;
|
||||||
prev_page_offset=_of->prev_page_offset;
|
prev_page_offset=_of->prev_page_offset;
|
||||||
start_offset=_of->offset;
|
start_offset=_of->offset;
|
||||||
memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
|
memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
|
||||||
@ -1463,7 +1449,7 @@ static int op_open_seekable2(OggOpusFile *_of){
|
|||||||
ogg_stream_clear(&_of->os);
|
ogg_stream_clear(&_of->os);
|
||||||
ogg_sync_clear(&_of->oy);
|
ogg_sync_clear(&_of->oy);
|
||||||
*&_of->oy=*&oy_start;
|
*&_of->oy=*&oy_start;
|
||||||
*&_of->os=*os_start;
|
*&_of->os=*&os_start;
|
||||||
_of->offset=start_offset;
|
_of->offset=start_offset;
|
||||||
_of->op_count=start_op_count;
|
_of->op_count=start_op_count;
|
||||||
memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count);
|
memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count);
|
||||||
@ -1471,10 +1457,9 @@ static int op_open_seekable2(OggOpusFile *_of){
|
|||||||
_of->prev_packet_gp=_of->links[0].pcm_start;
|
_of->prev_packet_gp=_of->links[0].pcm_start;
|
||||||
_of->prev_page_offset=prev_page_offset;
|
_of->prev_page_offset=prev_page_offset;
|
||||||
_of->cur_discard_count=_of->links[0].head.pre_skip;
|
_of->cur_discard_count=_of->links[0].head.pre_skip;
|
||||||
if(OP_UNLIKELY(ret<0)){free(os_start); return ret;}
|
if(OP_UNLIKELY(ret<0))return ret;
|
||||||
/*And restore the position indicator.*/
|
/*And restore the position indicator.*/
|
||||||
ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET);
|
ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET);
|
||||||
free(os_start);
|
|
||||||
return OP_UNLIKELY(ret<0)?OP_EREAD:0;
|
return OP_UNLIKELY(ret<0)?OP_EREAD:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1995,7 +1980,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||||||
ogg_stream_pagein(&_of->os,&og);
|
ogg_stream_pagein(&_of->os,&og);
|
||||||
if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
|
if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
|
||||||
opus_int32 total_duration;
|
opus_int32 total_duration;
|
||||||
int *durations = (int*)malloc(255 * sizeof(int));
|
int durations[255];
|
||||||
int op_count;
|
int op_count;
|
||||||
int report_hole;
|
int report_hole;
|
||||||
report_hole=0;
|
report_hole=0;
|
||||||
@ -2052,7 +2037,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||||||
Proceed to the next link, rather than risk playing back some
|
Proceed to the next link, rather than risk playing back some
|
||||||
samples that shouldn't have been played.*/
|
samples that shouldn't have been played.*/
|
||||||
_of->op_count=0;
|
_of->op_count=0;
|
||||||
if(report_hole){ free(durations); return OP_HOLE; }
|
if(report_hole)return OP_HOLE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/*By default discard 80 ms of data after a seek, unless we seek
|
/*By default discard 80 ms of data after a seek, unless we seek
|
||||||
@ -2160,9 +2145,9 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||||||
_of->prev_page_offset=_page_offset;
|
_of->prev_page_offset=_page_offset;
|
||||||
_of->op_count=op_count=pi;
|
_of->op_count=op_count=pi;
|
||||||
}
|
}
|
||||||
if(report_hole) { free(durations); return OP_HOLE; }
|
if(report_hole)return OP_HOLE;
|
||||||
/*If end-trimming didn't trim all the packets, we're done.*/
|
/*If end-trimming didn't trim all the packets, we're done.*/
|
||||||
if(op_count>0) { free(durations); return 0; }
|
if(op_count>0)return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3016,7 +3001,7 @@ static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(OP_FIXED_POINT)
|
#if defined(OP_FIXED_POINT)
|
||||||
#if 0
|
|
||||||
/*Matrices for downmixing from the supported channel counts to stereo.
|
/*Matrices for downmixing from the supported channel counts to stereo.
|
||||||
The matrices with 5 or more channels are normalized to a total volume of 2.0,
|
The matrices with 5 or more channels are normalized to a total volume of 2.0,
|
||||||
since most mixes sound too quiet if normalized to 1.0 (as there is generally
|
since most mixes sound too quiet if normalized to 1.0 (as there is generally
|
||||||
@ -3025,6 +3010,7 @@ static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
|
|||||||
32-bit number.*/
|
32-bit number.*/
|
||||||
static const opus_int16 OP_STEREO_DOWNMIX_Q14
|
static const opus_int16 OP_STEREO_DOWNMIX_Q14
|
||||||
[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
|
[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
|
||||||
|
#if OP_NCHANNELS_MAX>2
|
||||||
/*3.0*/
|
/*3.0*/
|
||||||
{
|
{
|
||||||
{9598,0},{6786,6786},{0,9598}
|
{9598,0},{6786,6786},{0,9598}
|
||||||
@ -3051,8 +3037,9 @@ static const opus_int16 OP_STEREO_DOWNMIX_Q14
|
|||||||
{6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183},
|
{6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183},
|
||||||
{3183,5515},{4502,4502}
|
{3183,5515},{4502,4502}
|
||||||
}
|
}
|
||||||
|
#endif // OP_NCHANNELS_MAX>2
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
|
int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
|
||||||
return op_read_native(_of,_pcm,_buf_size,_li);
|
return op_read_native(_of,_pcm,_buf_size,_li);
|
||||||
}
|
}
|
||||||
@ -3070,7 +3057,6 @@ static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
|
|||||||
for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
|
for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
#if 0
|
|
||||||
for(i=0;i<_nsamples;i++){
|
for(i=0;i<_nsamples;i++){
|
||||||
opus_int32 l;
|
opus_int32 l;
|
||||||
opus_int32 r;
|
opus_int32 r;
|
||||||
@ -3086,8 +3072,6 @@ static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
|
|||||||
dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767);
|
dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767);
|
||||||
dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767);
|
dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// noop, removed for RAM savings
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _nsamples;
|
return _nsamples;
|
||||||
|
@ -729,7 +729,7 @@ struct OpusServerInfo{
|
|||||||
/**The software used by the origin server (Server).
|
/**The software used by the origin server (Server).
|
||||||
This is <code>NULL</code> if there was no <code>Server</code> header.*/
|
This is <code>NULL</code> if there was no <code>Server</code> header.*/
|
||||||
char *server;
|
char *server;
|
||||||
/**The media type of the entity sent to the recipient (Content-Type).
|
/**The media type of the entity sent to the recepient (Content-Type).
|
||||||
This is <code>NULL</code> if there was no <code>Content-Type</code>
|
This is <code>NULL</code> if there was no <code>Content-Type</code>
|
||||||
header.*/
|
header.*/
|
||||||
char *content_type;
|
char *content_type;
|
||||||
|
@ -877,5 +877,36 @@ int16_t TasmotaI2S::lowpassFilter(int16_t pcm_in) {
|
|||||||
return pcm_out;
|
return pcm_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "AudioFileSource.h"
|
||||||
|
class AudioFileSourceLoopBuffer : public AudioFileSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AudioFileSourceLoopBuffer(void *inBuff, uint32_t buffSizeBytes, uint32_t restartOffset = 0){
|
||||||
|
readPtr = 0;
|
||||||
|
buffer = reinterpret_cast<uint8_t*>(inBuff);
|
||||||
|
buffSize = buffSizeBytes;
|
||||||
|
restart = restartOffset;
|
||||||
|
}
|
||||||
|
virtual ~AudioFileSourceLoopBuffer() override {};
|
||||||
|
|
||||||
|
virtual uint32_t read(void *data, uint32_t len) override {
|
||||||
|
uint32_t _availableBytes = len > (buffSize - readPtr) ? buffSize - readPtr : len;
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(data), buffer + readPtr, _availableBytes);
|
||||||
|
readPtr += len;
|
||||||
|
if(readPtr >= buffSize) {readPtr = restart;}
|
||||||
|
return _availableBytes;
|
||||||
|
}
|
||||||
|
virtual bool seek(int32_t pos, int dir) override {return false;}
|
||||||
|
virtual bool close() override {return true;}
|
||||||
|
virtual bool isOpen() override {return true;}
|
||||||
|
virtual uint32_t getSize() override {return buffSize;}
|
||||||
|
virtual uint32_t getPos() override {return readPtr;}
|
||||||
|
private:
|
||||||
|
uint32_t buffSize;
|
||||||
|
uint8_t *buffer;
|
||||||
|
uint32_t readPtr;
|
||||||
|
uint32_t restart;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // USE_I2S_AUDIO
|
#endif // USE_I2S_AUDIO
|
||||||
#endif // defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
#endif // defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
||||||
|
@ -79,9 +79,11 @@ void CmndI2SMP3Stream(void);
|
|||||||
struct AUDIO_I2S_MP3_t {
|
struct AUDIO_I2S_MP3_t {
|
||||||
#ifdef USE_I2S_MP3
|
#ifdef USE_I2S_MP3
|
||||||
AudioGenerator *decoder = nullptr;
|
AudioGenerator *decoder = nullptr;
|
||||||
AudioFileSourceFS *file = nullptr;
|
AudioFileSource *file = nullptr;
|
||||||
AudioFileSourceID3 *id3 = nullptr;
|
AudioFileSource *id3 = nullptr;
|
||||||
|
AudioFileSource *buff = NULL;
|
||||||
|
|
||||||
|
void *preallocateBuffer = NULL;
|
||||||
void *preallocateCodec = NULL;
|
void *preallocateCodec = NULL;
|
||||||
#endif // USE_I2S_MP3
|
#endif // USE_I2S_MP3
|
||||||
|
|
||||||
@ -96,6 +98,7 @@ struct AUDIO_I2S_MP3_t {
|
|||||||
bool use_stream = false;
|
bool use_stream = false;
|
||||||
bool task_running = false;
|
bool task_running = false;
|
||||||
bool task_has_ended = false;
|
bool task_has_ended = false;
|
||||||
|
bool task_loop_mode = false;
|
||||||
|
|
||||||
// SHINE
|
// SHINE
|
||||||
uint32_t recdur;
|
uint32_t recdur;
|
||||||
@ -124,7 +127,7 @@ struct AUDIO_I2S_MP3_t {
|
|||||||
const char kI2SAudio_Commands[] PROGMEM = "I2S|"
|
const char kI2SAudio_Commands[] PROGMEM = "I2S|"
|
||||||
"Gain|Rec|Stop|Config"
|
"Gain|Rec|Stop|Config"
|
||||||
#ifdef USE_I2S_MP3
|
#ifdef USE_I2S_MP3
|
||||||
"|Play"
|
"|Play|Loop"
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_I2S_DEBUG
|
#ifdef USE_I2S_DEBUG
|
||||||
"|Mic" // debug only
|
"|Mic" // debug only
|
||||||
@ -153,6 +156,7 @@ void (* const I2SAudio_Command[])(void) PROGMEM = {
|
|||||||
&CmndI2SGain, &CmndI2SMicRec, &CmndI2SStop, &CmndI2SConfig,
|
&CmndI2SGain, &CmndI2SMicRec, &CmndI2SStop, &CmndI2SConfig,
|
||||||
#ifdef USE_I2S_MP3
|
#ifdef USE_I2S_MP3
|
||||||
&CmndI2SPlay,
|
&CmndI2SPlay,
|
||||||
|
&CmndI2SLoop,
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_I2S_DEBUG
|
#ifdef USE_I2S_DEBUG
|
||||||
&CmndI2SMic,
|
&CmndI2SMic,
|
||||||
@ -837,6 +841,7 @@ void I2sMp3Task(void *arg) {
|
|||||||
}
|
}
|
||||||
audio_i2s.out->flush();
|
audio_i2s.out->flush();
|
||||||
audio_i2s_mp3.decoder->stop();
|
audio_i2s_mp3.decoder->stop();
|
||||||
|
audio_i2s_mp3.task_loop_mode = false;
|
||||||
mp3_delete();
|
mp3_delete();
|
||||||
audio_i2s_mp3.mp3_task_handle = nullptr;
|
audio_i2s_mp3.mp3_task_handle = nullptr;
|
||||||
audio_i2s_mp3.task_has_ended = true;
|
audio_i2s_mp3.task_has_ended = true;
|
||||||
@ -933,7 +938,7 @@ bool I2SinitDecoder(uint32_t decoder_type){
|
|||||||
int32_t I2SPlayFile(const char *path, uint32_t decoder_type) {
|
int32_t I2SPlayFile(const char *path, uint32_t decoder_type) {
|
||||||
int32_t i2s_err = I2SPrepareTx();
|
int32_t i2s_err = I2SPrepareTx();
|
||||||
if ((i2s_err) != I2S_OK) { return i2s_err; }
|
if ((i2s_err) != I2S_OK) { return i2s_err; }
|
||||||
if (audio_i2s_mp3.decoder) return I2S_ERR_DECODER_IN_USE;
|
if (audio_i2s_mp3.decoder != nullptr) return I2S_ERR_DECODER_IN_USE;
|
||||||
|
|
||||||
// check if the filename starts with '/', if not add it
|
// check if the filename starts with '/', if not add it
|
||||||
char fname[64];
|
char fname[64];
|
||||||
@ -946,8 +951,17 @@ int32_t I2SPlayFile(const char *path, uint32_t decoder_type) {
|
|||||||
|
|
||||||
I2SAudioPower(true);
|
I2SAudioPower(true);
|
||||||
|
|
||||||
audio_i2s_mp3.file = new AudioFileSourceFS(*ufsp, fname);
|
if (audio_i2s_mp3.task_loop_mode == true){
|
||||||
|
File _loopFile = ufsp->open(fname);
|
||||||
|
size_t _fsize = _loopFile.size();
|
||||||
|
audio_i2s_mp3.preallocateBuffer = special_realloc(audio_i2s_mp3.preallocateBuffer,_fsize);
|
||||||
|
size_t _received = _loopFile.read(reinterpret_cast<uint8_t*>(audio_i2s_mp3.preallocateBuffer),_fsize);
|
||||||
|
_loopFile.close();
|
||||||
|
|
||||||
|
audio_i2s_mp3.file = new AudioFileSourceLoopBuffer (audio_i2s_mp3.preallocateBuffer, _fsize); // use the id3 var to make the code shorter down the line
|
||||||
|
} else {
|
||||||
|
audio_i2s_mp3.file = new AudioFileSourceFS(*ufsp, fname);
|
||||||
|
}
|
||||||
audio_i2s_mp3.id3 = new AudioFileSourceID3(audio_i2s_mp3.file);
|
audio_i2s_mp3.id3 = new AudioFileSourceID3(audio_i2s_mp3.file);
|
||||||
|
|
||||||
if(I2SinitDecoder(decoder_type)){
|
if(I2SinitDecoder(decoder_type)){
|
||||||
@ -956,17 +970,18 @@ int32_t I2SPlayFile(const char *path, uint32_t decoder_type) {
|
|||||||
return I2S_ERR_DECODER_FAILED_TO_INIT;
|
return I2S_ERR_DECODER_FAILED_TO_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wr_tasksize = 8000; // suitable for ACC and MP3
|
size_t play_tasksize = 8000; // suitable for ACC and MP3
|
||||||
if(decoder_type == 2){ // opus needs a ton of stack
|
if(decoder_type == 2){ // opus needs a ton of stack
|
||||||
wr_tasksize = 26000;
|
play_tasksize = 26000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always use a task
|
// Always use a task
|
||||||
xTaskCreatePinnedToCore(I2sMp3Task, "PLAYFILE", wr_tasksize, NULL, 3, &audio_i2s_mp3.mp3_task_handle, 1);
|
xTaskCreatePinnedToCore(I2sMp3Task, "PLAYFILE", play_tasksize, NULL, 3, &audio_i2s_mp3.mp3_task_handle, 1);
|
||||||
return I2S_OK;
|
return I2S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp3_delete(void) {
|
void mp3_delete(void) {
|
||||||
|
delete audio_i2s_mp3.buff;
|
||||||
delete audio_i2s_mp3.file;
|
delete audio_i2s_mp3.file;
|
||||||
delete audio_i2s_mp3.id3;
|
delete audio_i2s_mp3.id3;
|
||||||
delete audio_i2s_mp3.decoder;
|
delete audio_i2s_mp3.decoder;
|
||||||
@ -1018,6 +1033,11 @@ void CmndI2SStop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_I2S_MP3
|
#ifdef USE_I2S_MP3
|
||||||
|
void CmndI2SLoop(void) {
|
||||||
|
audio_i2s_mp3.task_loop_mode = 1;
|
||||||
|
CmndI2SPlay();
|
||||||
|
}
|
||||||
|
|
||||||
void CmndI2SPlay(void) {
|
void CmndI2SPlay(void) {
|
||||||
if (XdrvMailbox.data_len > 0) {
|
if (XdrvMailbox.data_len > 0) {
|
||||||
int32_t err = I2SPlayFile(XdrvMailbox.data, XdrvMailbox.index);
|
int32_t err = I2SPlayFile(XdrvMailbox.data, XdrvMailbox.index);
|
||||||
|
@ -21,11 +21,8 @@
|
|||||||
#if defined(USE_I2S_AUDIO) && defined(USE_I2S_WEBRADIO)
|
#if defined(USE_I2S_AUDIO) && defined(USE_I2S_WEBRADIO)
|
||||||
|
|
||||||
struct AUDIO_I2S_WEBRADIO_t {
|
struct AUDIO_I2S_WEBRADIO_t {
|
||||||
// Webradio
|
|
||||||
AudioFileSourceICYStream *ifile = NULL;
|
AudioFileSourceICYStream *ifile = NULL;
|
||||||
AudioFileSourceBuffer *buff = NULL;
|
|
||||||
char wr_title[64];
|
char wr_title[64];
|
||||||
void *preallocateBuffer = NULL;
|
|
||||||
} Audio_webradio;
|
} Audio_webradio;
|
||||||
|
|
||||||
void I2sMDCallback(void *cbData, const char *type, bool isUnicode, const char *str) {
|
void I2sMDCallback(void *cbData, const char *type, bool isUnicode, const char *str) {
|
||||||
@ -53,18 +50,18 @@ bool I2SWebradio(const char *url, uint32_t decoder_type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allocate buffers if not already done
|
// allocate buffers if not already done
|
||||||
if (Audio_webradio.preallocateBuffer == NULL) {
|
if (audio_i2s_mp3.preallocateBuffer == NULL) {
|
||||||
Audio_webradio.preallocateBuffer = special_malloc(preallocateBufferSize);
|
audio_i2s_mp3.preallocateBuffer = special_malloc(preallocateBufferSize);
|
||||||
}
|
}
|
||||||
if (audio_i2s_mp3.preallocateCodec == NULL) {
|
if (audio_i2s_mp3.preallocateCodec == NULL) {
|
||||||
audio_i2s_mp3.preallocateCodec = special_malloc(preallocateCodecSize);
|
audio_i2s_mp3.preallocateCodec = special_malloc(preallocateCodecSize);
|
||||||
}
|
}
|
||||||
// check if we have buffers
|
// check if we have buffers
|
||||||
if (Audio_webradio.preallocateBuffer == NULL || audio_i2s_mp3.preallocateCodec == NULL) {
|
if (audio_i2s_mp3.preallocateBuffer == NULL || audio_i2s_mp3.preallocateCodec == NULL) {
|
||||||
AddLog(LOG_LEVEL_INFO, "I2S: cannot allocate buffers");
|
AddLog(LOG_LEVEL_INFO, "I2S: cannot allocate buffers");
|
||||||
if (Audio_webradio.preallocateBuffer != NULL) {
|
if (audio_i2s_mp3.preallocateBuffer != NULL) {
|
||||||
free(Audio_webradio.preallocateBuffer);
|
free(audio_i2s_mp3.preallocateBuffer);
|
||||||
Audio_webradio.preallocateBuffer = NULL;
|
audio_i2s_mp3.preallocateBuffer = NULL;
|
||||||
}
|
}
|
||||||
if (audio_i2s_mp3.preallocateCodec != NULL) {
|
if (audio_i2s_mp3.preallocateCodec != NULL) {
|
||||||
free(audio_i2s_mp3.preallocateCodec);
|
free(audio_i2s_mp3.preallocateCodec);
|
||||||
@ -82,11 +79,11 @@ bool I2SWebradio(const char *url, uint32_t decoder_type) {
|
|||||||
AddLog(LOG_LEVEL_INFO, "I2S: did connect to %s",url);
|
AddLog(LOG_LEVEL_INFO, "I2S: did connect to %s",url);
|
||||||
|
|
||||||
I2SAudioPower(true);
|
I2SAudioPower(true);
|
||||||
Audio_webradio.buff = new AudioFileSourceBuffer(Audio_webradio.ifile, Audio_webradio.preallocateBuffer, preallocateBufferSize);
|
audio_i2s_mp3.buff = new AudioFileSourceBuffer(Audio_webradio.ifile, audio_i2s_mp3.preallocateBuffer, preallocateBufferSize);
|
||||||
if(Audio_webradio.buff == nullptr){
|
if(audio_i2s_mp3.buff == nullptr){
|
||||||
goto i2swr_fail;
|
goto i2swr_fail;
|
||||||
}
|
}
|
||||||
Audio_webradio.buff->RegisterStatusCB(I2sStatusCallback, NULL);
|
audio_i2s_mp3.buff->RegisterStatusCB(I2sStatusCallback, NULL);
|
||||||
|
|
||||||
if(I2SinitDecoder(decoder_type) == false){
|
if(I2SinitDecoder(decoder_type) == false){
|
||||||
AddLog(LOG_LEVEL_DEBUG, "I2S: decoder init failed");
|
AddLog(LOG_LEVEL_DEBUG, "I2S: decoder init failed");
|
||||||
@ -94,7 +91,7 @@ bool I2SWebradio(const char *url, uint32_t decoder_type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio_i2s_mp3.decoder->RegisterStatusCB(I2sStatusCallback, NULL);
|
audio_i2s_mp3.decoder->RegisterStatusCB(I2sStatusCallback, NULL);
|
||||||
if(audio_i2s_mp3.decoder->begin(Audio_webradio.buff, audio_i2s.out)){
|
if(audio_i2s_mp3.decoder->begin(audio_i2s_mp3.buff, audio_i2s.out)){
|
||||||
AddLog(LOG_LEVEL_DEBUG, "I2S: decoder started");
|
AddLog(LOG_LEVEL_DEBUG, "I2S: decoder started");
|
||||||
} else {
|
} else {
|
||||||
goto i2swr_fail;
|
goto i2swr_fail;
|
||||||
@ -146,10 +143,10 @@ void I2sWebRadioStopPlaying() {
|
|||||||
delete audio_i2s_mp3.decoder;
|
delete audio_i2s_mp3.decoder;
|
||||||
audio_i2s_mp3.decoder = nullptr;
|
audio_i2s_mp3.decoder = nullptr;
|
||||||
}
|
}
|
||||||
if (Audio_webradio.buff) {
|
if (audio_i2s_mp3.buff) {
|
||||||
Audio_webradio.buff->close();
|
audio_i2s_mp3.buff->close();
|
||||||
delete Audio_webradio.buff;
|
delete audio_i2s_mp3.buff;
|
||||||
Audio_webradio.buff = NULL;
|
audio_i2s_mp3.buff = NULL;
|
||||||
}
|
}
|
||||||
if (Audio_webradio.ifile) {
|
if (Audio_webradio.ifile) {
|
||||||
Audio_webradio.ifile->close();
|
Audio_webradio.ifile->close();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user