labplus-cn / mpython

mpython掌控板文档和固件源码
MIT License
129 stars 54 forks source link

audio模块释放播放器时写入不允许访问的内存地址报错重启 #30

Open wojiaoyishang opened 1 year ago

wojiaoyishang commented 1 year ago

描述BUG audio模块释放播放器时写入不允许访问的内存地址报错重启。详情: 当调用 audio.play("local.mp3") 播放本地音乐时,会阻塞代码运行,直到音乐播放结束,通过 audio.player_deinit() 释放播放器并未捕获异常。但是,如果采用阻塞的方式播放本地文件,audio模块中提供的暂停、继续播放函数将会没有意义。、 奇怪的是。当调用 audio.play("http://xxx.mp3") 播放在线音乐时,并不会阻塞代码运行,通过 audio.player_deinit() 释放播放器会造成写入不允许访问的内存地址报错重启。

复现BUG 通过一下步骤:

  1. 连接 WIFI
  2. 导入 audio 模块并播放在线音乐,并等待音乐播放到中途某一个阶段
  3. 使用 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

修改建议

代码停止音乐播放的逻辑是:先将引脚输出“禁用”,然后将文件播放到文件尾。这种方式对于长的音乐文件不太友好,建议直接将所有任务终止。