主要分析了乐鑫、MTK、炬芯、全志的RTOS audio player,仅供参考

公司 乐鑫 MTK 炬芯 全志
平台 ESP32 LinkIt/mt2523 ATS3503_WIFI XR871
许可证 MIT License 需要MTK许可 Apache License 2 必须保留版权信息
工程地址 https://github.com/espressif/esp-adf 淘宝 淘宝 淘宝
player主文件(个人理解) https://github.com/espressif/
esp-adf/tree/
3305749c93763b7a83d
030e7f30b28f3aeb1d186/
examples
/player有多种组合
淘宝/mt2523_hdk/apps/
mp3_local_playback/src/
AudioPlayer/audio_player_main.c
淘宝/ATS3503_WIFI/
samples/storyapp/src/
storyplayer/storyplayer_main.c
淘宝/XR871/03_SDK/
xr871sdk/project/
evb_audio/audio_player.c
官方音频文档 https://docs.espressif.com/
projects/esp-adf/en/latest/
api-reference/index.html
特点 使用Pipeline来连接Elements,可以注册多种Elements组合,比较灵活 大部分操作通过decoder提供的api完成。 也是story player,playlist部分可参考。 流程比较简单,但代码可能不全
缺点 差异较大,可能需要大改 player似乎只支持MP3,其他格式只有aac提供了demo。 代码可能不全,只看到初始化预处理部分,具体decode和output部分不明 代码可能不全

乐鑫 ESP32

播放流程简要分析,可参考https://blog.csdn.net/zhejfl/article/details/86477866
主要特点为:使用了Pipeline。主要职责是控制音频数据流stream以及用ring_buffer连接各音频元素elements。它按顺序并启动音频元素,负责从前一个元素检索数据然后传递给后面一个元素,还可从每个元素获取事件、处理事件或将其传递到更高层。
可以注册多种Elements组合,在连接的时候选择一种Elements组合连接起来,也可以在断开再组成其他的Elements组合,则使得使用pipeline非常灵活。
启动audio_pipeline时,会为pipeline中的所有Elements创建Tasks。
audio_pipeline_register(pipeline, mp3_decoder, “mp3”);
audio_pipeline_register(pipeline, i2s_stream_writer, “i2s”);
audio_pipeline_link(pipeline, (const char *[]) {“mp3”, “i2s”}, 2);

audio_pipeline_run(pipeline);//为管道中的所有Elements创建Tasks。

音频框架流程:

一组链接的元素的动态组合是使用音频管道完成的。您无需处理单个元素,而只需处理一个音频管道。每个元素都通过环形缓冲区连接。音频管道还负责将消息从元素任务转发到应用程序。
下图显示了音频流水线中三个元素的组织,即HTTP读取流,MP3解码器和I2S写入流,已在player / pipeline_http_mp3示例中使用。

音乐播放器或录音机支持音频格式,例如MP3,AAC,FLAC,WAV,OGG,OPUS,AMR,TS,EQ,Downmixer,Sonic,ALC,G.711 …
从以下来源播放音乐:HTTP,HLS(HTTP实时流),SPIFFS,SDCARD,A2DP来源,A2DP接收器,HFP …
集成媒体服务,例如:DLNA,VoIP …
网络广播
语音识别以及与Alexa,DuerOS等在线服务的集成…

https://github.com/espressif/esp-adf/tree/3305749c93763b7a83d030e7f30b28f3aeb1d186/examples/player
player有多种组合

以pipelind_sdcard_mp3文件夹下的play_sdcard_mp3_example.c为例
在app_main中
[ 1 ] Mount sdcard
// 初始化外围设备管理
// 初始化SD卡外设
[ 2 ] 启动codec芯片
[3.0] 创建用于播放的音频管道
[3.1]创建fatfs流以从sdcard读取数据
[3.2]创建i2s流以将数据写入codec芯片
[3.3]创建mp3解码器以解码mp3文件
[3.4]将所有元素注册到音频管道
audio_pipeline_register(pipeline, fatfs_stream_reader, “file”);
audio_pipeline_register(pipeline, mp3_decoder, “mp3”);
audio_pipeline_register(pipeline, i2s_stream_writer, “i2s”);
[3.5] 将其链接在一起[sdcard]–>fatfs_stream–>mp3_decoder–>i2s_stream–>[codec_chip]
audio_pipeline_link(pipeline, (const char []) {“file”, “mp3”, “i2s”}, 3);
[3.6] Set up uri (file as fatfs_stream, mp3 as mp3 decoder, and default output is i2s)
[ 4 ] Set up event listener
[4.1]来自管道所有元素的Listening event
[4.2]来自外围设备的Listening event
[ 5 ] 启动音频管道
[ 6 ] 监听所有管道事件
while (1)
/
当最后一个管道元素(在这种情况下为i2s_stream_writer)接收到停止事件时停止*/
[ 7 ] 停止音频管道

以pipelind_sdcard_mp3文件夹下的play_sdcard_mp3_example.c为例

结构体:

typedef struct **audio_player** {audio_pipeline_handle_t pipeline;audio_element_handle_t http_stream_reader;audio_element_handle_t i2s_stream_writer;audio_element_handle_t mp3_decoder;audio_event_iface_handle_t evt;audio_hal_handle_t hal;bool run;bool playing;player_event event_handler;
} audio_player_t;struct **audio_pipeline** {audio_element_list_t        el_list;ringbuf_list_t              rb_list;audio_element_state_t       state;xSemaphoreHandle            lock;bool                        linked;audio_event_iface_handle_t  listener;
};struct **audio_element** {/* Functions/RingBuffers */io_func                     open;io_func                     seek;process_func                process;io_func                     close;io_func                     destroy;io_type_t                   read_type;union {ringbuf_handle_t        input_rb;io_callback_t           read_cb;} in;io_type_t                   write_type;union {ringbuf_handle_t        output_rb;io_callback_t           write_cb;} out;audio_multi_rb_t            multi_in;audio_multi_rb_t            multi_out;/* Properties */bool                        is_open;audio_element_state_t       state;events_type_t               events_type;audio_event_iface_handle_t  iface_event;audio_callback_t            callback_event;int                         buf_size;char                        *buf;char                        *tag;int                         task_stack;int                         task_prio;int                         task_core;xSemaphoreHandle            lock;audio_element_info_t        info;audio_element_info_t        *report_info;/* PrivateData */void                        *data;EventGroupHandle_t          state_event;int                         input_wait_time;int                         output_wait_time;int                         out_buf_size_expect;int                         out_rb_size;bool                        is_running;bool                        task_run;bool                        stopping;};
 * Event message*/typedef struct {int cmd;                /*!< Command id */void *data;             /*!< Data pointer */int data_len;           /*!< Data length */void *source;           /*!< Source event */int source_type;        /*!< Source type (To know where it came from) */bool need_free_data;    /*!< Need to free data pointer after the event has been processed */} audio_event_iface_msg_t;

MTK的LinkIt

player似乎只支持MP3,其他格式的decoder只找到aac\amr,但只有aac提供了demo,amr未找到调用方。
wav_codec.c中有一个wav_codec_deocde_event_handler函数,只在prompt_control.c和bt_sink_srv_am_task.c中被调用。

有两个audio_player_main.c文件,
project/mt2523_hdk/apps/headset_ref_design/src/AudioPlayer/audio_player_main.c
project/mt2523_hdk/apps/mp3_local_playback/src/AudioPlayer/audio_player_main.c

mp3_local_playback文件夹中的audio_player_main.c
audio_player_init()创建audio_player_task_main线程,初始化g_aud_ring_buff

audio_player_task_main线程中,
1、调用audio_player_scan_file(),搜索0:/music里的音频文件
2、调用bt_sink_srv_ami_audio_open函数,open a new audio handler and get the audio ID.同时指定一个callback函数audio_player_ami_hdr,用来write driver media data。
3、调用xSemaphoreCreateBinary创建g_aud_event_semaphore
4、调用bt_sink_srv_audio_setting_init()
5、在while(1)循环中执行audio_player_processing()

audio_player_processing函数在while(1)循环中,获取信号量,然后读文件并写到ring buffer中,再调用audio_player_check_threshold。

audio_player_check_threshold函数判断如果read_byte大于阈值,就根据aud_ply->flag的状态,调用g_file_med_hd->media_handle.mp3.resume 或g_file_med_hd->media_handle.mp3.play

再往下调用
mp3_codec_play→MP3Dec_Init
→mp3_codec_play_internal→MP3Dec_Decode
MP3Dec_Init和MP3Dec_Decode只在middleware/MTK/audio/mp3_codec/inc/mp3dec_exp.h中有声明,找不到具体函数。

mp3.stop部分提供了一个audio_player_stop函数,但没找到调用方。
mp3.stop←audply_stop←audio_player_stop。

**headset_ref_design文件夹中的audio_player_main.c,上层调用关系有些不一样,**但是audio_player_task_main→audio_player_processing→audio_player_check_threshold 这部分流程大致是一样的

g_file_med_hd结构体为

typedef struct {am_file_type_t type;union {**bt_sink_srv_am_mp3_media_handle_t mp3;**} media_handle;
} bt_sink_srv_am_files_media_handle_t;

bt_sink_srv_am_mp3_media_handle_t结构体为

typedef struct {void (*get_write_buffer)(bt_sink_srv_am_id_t aud_id, uint8_t **buffer, uint32_t *length);
/**< 获取写入共享缓冲区的可用长度和指向共享缓冲区的指针。 */void (*get_read_buffer)(bt_sink_srv_am_id_t aud_id, uint8_t **buffer, uint32_t *length);
/**< 获取写入(注释确实是write)共享缓冲区的可用长度和指向共享缓冲区的指针 */void (*write_data_done)(bt_sink_srv_am_id_t aud_id, uint32_t length);  /**<更新指向共享缓冲区的写指针 */void (*finish_write_data)(bt_sink_srv_am_id_t aud_id);                 /**< 指示最后一次数据传输。*/int32_t (*get_data_count)(bt_sink_srv_am_id_t aud_id);                 /**< 从共享缓冲区获取数据长度. */int32_t (*get_free_space)(bt_sink_srv_am_id_t aud_id);                 /**< 从共享缓冲区获取可用长度 */int32_t (*play)(bt_sink_srv_am_id_t aud_id);                                                    /**< The MP3 codec play function. */int32_t (*pause)(bt_sink_srv_am_id_t aud_id);                                                   /**< The MP3 codec pause function. */int32_t (*resume)(bt_sink_srv_am_id_t aud_id);                                                  /**< The MP3 codec resume function. */int32_t (*stop)(bt_sink_srv_am_id_t aud_id);                                                    /**< The MP3 codec stop function. */int32_t (*close_codec)(bt_sink_srv_am_id_t aud_id);                                             /**< The MP3 codec close_codec function. */int32_t (*skip_id3v2_and_reach_next_frame)(bt_sink_srv_am_id_t aud_id, uint32_t file_size);     /**< Skip id3v2 header and reach next frame */int32_t (*set_silence_frame_information)(bt_sink_srv_am_id_t aud_id, silence_frame_information_t *frm_info);
/**< 设置静音帧信息 */int32_t (*fill_silence_frame)(bt_sink_srv_am_id_t aud_id, uint8_t *buffer);
/**< 获取静音帧 */int32_t (*get_data_status)(bt_sink_srv_am_id_t aud_id, mp3_codec_data_type_t type, int32_t *status);int32_t (*flush)(bt_sink_srv_am_id_t aud_id, int32_t flush_data_flag);#ifdef __BT_AWS_SUPPORT__int32_t (*set_aws_flag)(bt_sink_srv_am_id_t aud_id, bool flag);int32_t (*set_aws_initial_sync)(bt_sink_srv_am_id_t aud_id);int32_t (*aws_init)(void);int32_t (*aws_deinit)(void);int32_t (*aws_set_clock_skew_compensation_value)(int32_t sample_count);int32_t (*aws_get_clock_skew_status)(int32_t *status);int32_t (*aws_set_clock_skew)(bool flag);
#endif /* __BT_AWS_SUPPORT__ */
} bt_sink_srv_am_mp3_media_handle_t;

aac的play demo,是从sd卡里打开文件,然后调用decoder的api进行处理
函数调用如下,看函数名即可。
aac_play_demo
├──play
│ ├──test_open_file_from_sd(&fdst, _T(“SD:/AAC/v1.aac”)
│ ├──hal_audio_set_stream_out_volume
│ ├──hal_audio_set_stream_out_device
│ ├──hdl = aac_deocder_api_open(test_sd_event_callback);
│ ├──hdl->set_share_buffer(hdl, share_buffer, SHARE_BUF_SIZE);
│ ├──hdl->get_write_buffer(hdl, &share_buf, &share_buf_len);
│ ├──f_read(&fdst, share_buf, share_buf_len, &length_read);
│ ├──hdl->write_data_done(hdl, length_read);
│ ├──hdl->finish_write_data(hdl);
│ ├──hdl->play(hdl);
│ │ ├──aac_decoder_api_play
│ │ │ ├──aac_decoder_api_event_register_callback
│ │ │ ├──aac_decoder_api_reset_pcm_out_buffer
│ │ │ ├──aac_decoder_api_request_data
│ │ │ ├──aac_decoder_init
│ │ │ ├──aac_decoder_api_decode
│ │ │ ├──hal_audio_set_stream_out_sampling_rate
│ │ │ ├──hal_audio_set_stream_out_channel_number
│ │ │ ├──hal_audio_register_stream_out_callback
│ │ │ ├──hal_audio_start_stream_out
//注释写的是打开模拟和数字音频硬件的电源以输出音频
│ │ │ ├──aac_decoder_api_event_send_from_isr

主要操作都通过调用decoder提供的api进行。

/** @brief HE-AAC audio handle structure type.*/
typedef struct _aac_decoder_api_media_handle_t {aac_decoder_api_state_t     state;      /**< The AAC decoder state. */aac_decoder_api_share_buffer_t   share_buffer;
/**<  AAC decoder的共享缓存区. */bool                     underflow;/**< The AAC decoder data underflow occurred. */bool             waiting;
/**< AAC decoder正在等待填充数据 */uint16_t           audio_id;
/**< The audio ID of the AAC decoder. */
void (*handler)(struct _aac_decoder_api_media_handle_t *handle, aac_decoder_api_media_event_t event_idd);
/**< The AAC decoder handler. */
void (*set_share_buffer)(struct _aac_decoder_api_media_handle_t *handle, uint8_t  *buffer, uint32_t  length);
/**<设置bitstream的共享缓冲区。 可以通过共享缓冲区填充音频流数据*/
void (*get_write_buffer)(struct _aac_decoder_api_media_handle_t *handle, uint8_t **buffer, uint32_t *length);
/**<获取向共享缓冲区写入的可用长度和指向共享缓冲区的指针。 */
void (*get_read_buffer)(struct _aac_decoder_api_media_handle_t *handle, uint8_t **buffer, uint32_t *length);
/**< 获取从共享缓冲区读取的可用长度和指向共享缓冲区的指针。 */
void (*write_data_done)(struct _aac_decoder_api_media_handle_t *handle, uint32_t length);
/**< 更新指向共享缓冲区的写指针. */
void (*finish_write_data)(struct _aac_decoder_api_media_handle_t *handle);
/**< 最后一次数据传输. */
void (*reset_share_buffer)(struct _aac_decoder_api_media_handle_t *handle);
/**< 重置共享缓冲区的信息. */
void (*read_data_done)(struct _aac_decoder_api_media_handle_t *handle, uint32_t length);
/**< 更新指向共享缓冲区的读指针. */
int32_t (*get_free_space)(struct _aac_decoder_api_media_handle_t *handle);
/**<获取共享缓冲区中可用的可用空间长度。 (以字节为单位)*/
int32_t (*get_data_count)(struct _aac_decoder_api_media_handle_t *handle);
/**< 获取共享缓冲区的可用数据量。 */
aac_decoder_api_status_t (*play)(struct _aac_decoder_api_media_handle_t *handle);
/**< The AAC decoder play function. */
aac_decoder_api_status_t (*pause)(struct _aac_decoder_api_media_handle_t *handle);
/**< The AAC decoder pause function. */
aac_decoder_api_status_t (*resume)(struct _aac_decoder_api_media_handle_t *handle);
/**< The AAC decoder resume function. */
aac_decoder_api_status_t (*process)(struct _aac_decoder_api_media_handle_t *handle, aac_decoder_api_media_event_t event_id);
/**< The AAC decoder process function. */
aac_decoder_api_status_t (*stop)(struct _aac_decoder_api_media_handle_t *handle);
/**< The AAC decoder stop function. */aac_decoder_api_status_t (*flush)(struct _aac_decoder_api_media_handle_t *handle,int32_t flush_data_flag);
} aac_decoder_api_media_handle_t;

炬芯的ATS3503_WIFI

淘宝/ATS3503_WIFI/samples/storyapp/src/storyplayer/storyplayer_main.c

主要文件为storyplayer_main.c和storyplayer_play.c

在storyplayer_main.c中
storyapp_main函数调用k_thread_spawn创建主线程,运行storyapp_main_loop

在storyapp_main_loop循环中,switch (msg.type),调用不同的函数。
case类型为
MSG_EXIT_APP:退出app
MSG_PLAY_DEFAULT_MUSIC:播放默认音乐
MSG_PLAY_NEW_LIST:播放新的列表
MSG_PLAY_PAUSE_RESUME:播放暂停/恢复
MSG_PLAY_NEXT_MUSIC:播放下一首
MSG_PLAY_PREVIOUS_MUSIC:播放上一首
MSG_PLAY_CUR_MUSIC:播放当前音乐
MSG_PLAY_URL
MSG_PLAY_SEEK
MSG_PLAY_HANDLE_CARD_EVENT
MSG_PLAY_MUSIC_ERROR

以MSG_PLAY_DEFAULT_MUSIC播放默认音乐为例,会调用 handle_default_play_msg,进而调用storyplayer_play.c中的storyplay_default_music。
忽略playlist的相关操作,会调用storyplay_cur_music→play_cur_local_music,获取播放流的type和url。其中stream type有五种,但就播放部分应该只用到了file stream和net stream。
然后会调用send_msg_to_storyplayer(MSG_PLAY_URL, &parm),发送消息给storyplayer,再次在loop的switch中进行判断,case MSG_PLAY_URL。
调用handle_play_url_msg→storyplay_play_url,根据播放流的type和url,创建play_stream,再调用mplayer_start_stream。

但是stream_create和mplayer_star_stream这两个函数只在app_common_api.h中找到函数声明,且decode部分也未找到,代码可能不全?
相当于只有预处理部分,decode和output流程不明。

在ext/lib/actions/libAL/有找到一些.a文件,在arch/mips/soc/ats3503/linker.ld 有用到,但具体流程不明。
./ext/lib/actions/libAL/libdecaac.a
./ext/lib/actions/libAL/libdecact.a
./ext/lib/actions/libAL/libdecamr.a
./ext/lib/actions/libAL/libdecape.a
./ext/lib/actions/libAL/libdecflac.a
./ext/lib/actions/libAL/libdecmp3.a
./ext/lib/actions/libAL/libdecwav.a
./ext/lib/actions/libAL/libdecwma.a

全志的XR871

先调用player_task_init,用OS_ThreadCreate创建player_task线程,同时创建一个observer,事件发生时回调将被触发,是用来监控gpio button的。
在player_task线程中,while (player_task_run)进行循环。player_task_run在player_task_init中设为1,在player_task_deinit中设为0,当退出循环时线程就自我删除。
线程中调用read_payer_ctrl_cmd,根据按键状态获取cmd。switch (cmd),然后调用不同的函数。
case共五种
case CMD_PLAYER_NEXT:
case CMD_PLAYER_PERV:
case CMD_PLAYER_VOLUME_UP:
case CMD_PLAYER_VOLUME_DOWN:
case CMD_PLAYER_PAUSE:
以CMD_PLAYER_NEXT为例,忽略ui部分,调用player_read_songs,读取mp3文件名,再调用play_songs,根据传入参数song_name,去播放file://music/song_name。
再往下调用play→XPlayerStart→XPlayerStart。只在xplayer.h中找到声明,找不到具体函数,似乎也是代码不全?
https://github.com/XradioTech/XR871SDK 中也没有找到具体函数。

解码部分找到一个cedarx库,在03_SDK\xr871sdk\src\smartlink\voice_print中被调用,似乎是用作声纹识别。
http://linux-sunxi.org/CedarX

版权问题:

乐鑫ESP32
esp-adf的LICENSE

ESPRESSIF MIT License

Copyright © 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>

Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
it is free of charge, to any person obtaining a copy of this software and associated
documentation files (the “Software”), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

LinkIt的player
/* Copyright Statement:
*

  • © 2005-2016 MediaTek Inc. All rights reserved.
  • This software/firmware and related documentation (“MediaTek Software”) are
  • protected under relevant copyright laws. The information contained herein
  • is confidential and proprietary to MediaTek Inc. (“MediaTek”) and/or its licensors.
  • Without the prior written permission of MediaTek and/or its licensors,
  • any reproduction, modification, use or disclosure of MediaTek Software,
  • and information contained herein, in whole or in part, shall be strictly prohibited.
  • You may only use, reproduce, modify, or distribute (as applicable) MediaTek Software
  • if you have agreed to and been bound by the applicable license agreement with
  • MediaTek (“License Agreement”) and been granted explicit permission to do so within
  • the License Agreement (“Permitted User”). If you are not a Permitted User,
  • please cease any access or use of MediaTek Software immediately.
  • BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
  • THAT MEDIATEK SOFTWARE RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES
  • ARE PROVIDED TO RECEIVER ON AN “AS-IS” BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
  • WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
  • MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
  • NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
  • SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
  • SUPPLIED WITH MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
  • THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
  • THAT IT IS RECEIVER’S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
  • CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
  • SOFTWARE RELEASES MADE TO RECEIVER’S SPECIFICATION OR TO CONFORM TO A PARTICULAR
  • STANDARD OR OPEN FORUM. RECEIVER’S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK’S ENTIRE AND
  • CUMULATIVE LIABILITY WITH RESPECT TO MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
  • AT MEDIATEK’S OPTION, TO REVISE OR REPLACE MEDIATEK SOFTWARE AT ISSUE,
  • OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
  • MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
    */

炬芯的ATS3503_WIFI的story_player.c
/*

  • Copyright © 2017 Actions Semi Co., Ltd.
  • Licensed under the Apache License, Version 2.0 (the “License”);
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  • http://www.apache.org/licenses/LICENSE-2.0
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an “AS IS” BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.

全志的XR817的audio_player.c

  • Copyright © 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
  • 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.
    1. 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.
    1. Neither the name of XRADIO TECHNOLOGY CO., LTD. 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.

RTOS系统 音频player对比分析相关推荐

  1. Linux 音频player对比

    条件:linux下,主要由C语言编写,且开源的音乐播放器. 名称 Rhythmbox DeaDBeef Pragha 简介 Ubuntu的默认播放器 类unix系统下的终极播放器 适用于GNU / L ...

  2. X86 android r7 z3735,安卓工业平板电脑android系统下各大主流CPU性能大对比分析

    原标题:安卓工业平板电脑android系统下各大主流CPU性能大对比分析 针对工控领域客户在选择工业平板电脑时的困惑,南京研维组织多位业内专家,为大家连续推出10期工业平板电脑的选型要点分析,本文作为 ...

  3. 什么是RTOS系统定义分析

    实时系统(Real-time operating system,RTOS)的正确性不仅依赖系统计算的逻辑结果,还依赖于产生这个结果的时间.实时系统能够在指定或者确定的时间内完成系统功能和外部或内部.同 ...

  4. 致远项目管理SPM系统进度控制之进度对比分析

    卷首语 致远SPM系统进度计划管理是项目管理的核心业务,是站在企业层面对现行组织中所有的项目进行筛选.评估.计划.执行与控制的项目管理方式. 致远SPM系统与P6集成,具有全面的项目更新数据分析功能. ...

  5. 区块链技术背景下数字音频商业模式变革的逻辑 - 基于云听、喜马拉雅FM和CastBox的对比分析

    本文经过<传媒>杂志老师的授权.2022-08-24 ,我在微信公众号 乐生活与爱IT Plus上发表了原创文章<观念即商品.传播即分销.互动即迭代 |元宇宙和新媒体>,并提出 ...

  6. matlab语音频谱,信号与系统:用matlab分析wav音频的频谱

    信号与系统:用matlab分析wav音频的频谱 [天水浪客一门课程的平时作业,matlab确实强大,用它做这个有点杀鸡用牛刀的意味 ... 软件太大了,直接靠安装了此软件的同学搞定,程序也是参考网上的 ...

  7. 转载 多家在线考试系统对比分析

    在百度网上输入"在线考试系统"."网上考试系统"等关键字,就会搜出多家考试系统提供商,有的是花钱在百度买的排名推广,有的是因为搜索率高排在前台.初步计算一下,专 ...

  8. matlab相关性分析频谱_信号与系统:用matlab分析wav音频的频谱

    信号与系统:用matlab分析wav音频的频谱 2018-11-25 [天水浪客一门课程的平时作业,matlab确实强大,用它做这个有点杀鸡用牛刀的意味...软件太大了,直接靠安装了此软件的同学搞定, ...

  9. 华为鸿蒙系统与安卓系统对比,华为鸿蒙系统与安卓系统对比分析,区别在哪里?网友:细节定成败!...

    原标题:华为鸿蒙系统与安卓系统对比分析,区别在哪里?网友:细节定成败! 安卓系统大家都很熟悉,已经发展了数十年时间,软件生态可以说是相当完善,但流畅度依然不及苹果IOS.从系统设计上看,安卓有着不少的 ...

最新文章

  1. Slim Span UVA - 1395
  2. idea 用iterm 终端_帅气逼人的终端环境
  3. JAVA中线程同步的方法(7种)汇总
  4. Oracle数据库三种备份方案
  5. 4g模块注册上网 移远_通信模组企业 移远通信amp;广和通
  6. 终于修好了MacBook
  7. 在VS 2010中查询和导航代码
  8. mysql 断言,mysql触发器模拟断言
  9. 如何循环数据库中的所有表名?
  10. 无所不在的性能测试——《LoadRunner 没有告诉你的》之五
  11. 2020服务器虚拟化市场容量,2020年服务器市场的五大技术和市场趋势
  12. 假设法求最大值和数组的优点
  13. PHPMailer 报错:SMTP ERROR: Password command failed: 535 Login Fail
  14. oracle 11g 01017,oracle 11G OEM 出现问题 ORA-01017: inv
  15. 任正非:一江春水向东流
  16. python 12306查询不到车次_(经典!!!详细解析!!!)python实现12306余票查询
  17. phpAdmin中id字段如何设置自增
  18. OpenGL中phong光照模型详解
  19. 编写电话号码查询系统
  20. 有向图的强联通分量之:【求最长链】【求最长链的方案数(图论中的方案数DP)】【最长链和最大半联通子图 节点数相同】【最长链与最大半联通子图等价又不完全等价】

热门文章

  1. gmail收件箱标签设置_如何在Gmail中自动分类的收件箱选项卡之间移动电子邮件...
  2. Oracle导出空(无数据)表
  3. Ubantu安装JDK(ppa源的方式)
  4. 10个超高质量Python数据分析公众号!
  5. 写在世界读书日 - 光读书不能让你成为供应链管理专家
  6. 锐捷多网卡问题破解-----过河拆桥解决完整性校验
  7. 《精解Windows8》——2.12 个性化Metro界面
  8. idea连接数据库测试
  9. hi3518ev300开发板烧写历程
  10. 国外存储器专利筑起高墙?大陆半导体怎么破