mpython
mpython copied to clipboard
audio模块释放播放器时写入不允许访问的内存地址报错重启
描述BUG
audio模块释放播放器时写入不允许访问的内存地址报错重启。详情:
当调用 audio.play("local.mp3")
播放本地音乐时,会阻塞代码运行,直到音乐播放结束,通过 audio.player_deinit()
释放播放器并未捕获异常。但是,如果采用阻塞的方式播放本地文件,audio模块中提供的暂停、继续播放函数将会没有意义。、
奇怪的是。当调用 audio.play("http://xxx.mp3")
播放在线音乐时,并不会阻塞代码运行,通过 audio.player_deinit()
释放播放器会造成写入不允许访问的内存地址报错重启。
复现BUG 通过一下步骤:
- 连接 WIFI
- 导入 audio 模块并播放在线音乐,并等待音乐播放到中途某一个阶段
- 使用
audio.player_deinit()
释放播放器便会出现报错,代码如下:
import time
import audio
from mpython import *
wifi().connectWiFi("ssid", "password", timeout=10)
audio.player_init()
audio.play('http://wiki.labplus.cn/images/4/4e/Music_test.mp3') # 播放在线音乐,不阻塞代码
time.sleep(3) # 等待音乐播放起来
audio.player_deinit() # 是否音乐
同时,在播放在线文件的时候也会出现堆栈溢出的情况,如调用下面的音频文件:
audio.player_init()
audio.play('https://gitee.com/wojiaoyishang/TaoLiSystem-doc/releases/download/v114514/ctr1.mp3')
audio.stop()
audio.player_deinit()
附加说明
Q: 有没有可能是没有使用 audio.stop()
再 audio.player_deinit()
造成的报错?
A: 不存在这种情况,即使使用 audio.stop()
也会报错,查看源码 mpython/port/drivers/codec/audio_player.c
,发现如下:
void player_deinit(void)
{
EventBits_t uxBits;
if(player_instance){
if((player_instance->player_status == RUNNING) || (player_instance->player_status == PAUSED))
{
player_stop(); // 即使处于播放状态仍然会先停止
}
// something......
}
Q: 错误的原因是什么?
A: 原因是试图将一段数据试图写入一段不允许访问的内存中去,而写入内存的操作由 HTTP请求
完成,所以猜测是在释放 player 之后,并未停止 HTTP请求
。也就是没有停止代码中的 http_client_task
。
Q: 其它想说的。
A: 代码中的函数 player_play
有一段如下:
local_play(player_instance);
// xTaskCreate(local_play_task, "local_play_task", 8192, player_instance, ESP_TASK_PRIO_MIN + 1, NULL );
// ESP_LOGE(TAG, "4. Create local file read task, RAM left: %d", esp_get_free_heap_size());
xTaskCreate
函数执行被注释了,转而执行 local_play
函数,估计是当时官方发现发现本地播放的问题进行的临时补救。O(∩_∩)O
修改建议
代码停止音乐播放的逻辑是:先将引脚输出“禁用”,然后将文件播放到文件尾。这种方式对于长的音乐文件不太友好,建议直接将所有任务终止。