# aardio 范例: TTS · Windows 原生流式播放



```aardio
// Windows native streaming playback; no BASS, browser, OCX or audio HTTP server.
// 最小流式朗读示例见: https://www.aardio.com/zh-cn/docs/examples/Media/Audio/edgeTTS-stream.html

import win.ui;
import web.edgeTextToSpeech;
import sys.mediaFoundation.streamingMp3Player;
/*DSG{{*/
var winform = win.form(text="TTS · Windows 原生流式播放";right=679;bottom=359;bgcolor=0xF8F8F8)
winform.add(
edit={cls="edit";text="这是 Windows 原生流式语音播放。收到前面的音频就开始解码播放，不需要等整段合成结束。";left=24;top=91;right=655;bottom=242;anchors={left=1;top=1;right=1;bottom=1};edge=1;font=LOGFONT(h=-16);multiline=1;vscroll=1;z=3};
hint={cls="static";text="音频在内存中增量解码；输入结束后继续播完，停止立即清理。";left=24;top=56;right=655;bottom=80;anchors={left=1;top=1;right=1};color=0x666666;z=2};
speak={cls="plus";text="开始朗读";left=24;top=258;right=171;bottom=303;anchors={left=1;bottom=1};bgcolor=0xD47800;border={radius=6};color=0xFFFFFF;font=LOGFONT(h=-16);notify=1;z=4};
status={cls="plus";text="就绪";left=24;top=318;right=655;bottom=344;anchors={left=1;right=1;bottom=1};bgcolor=0xF0F0F0;color=0x666666;edge=1;z=6};
stop={cls="plus";text="停止";left=185;top=258;right=295;bottom=303;anchors={left=1;bottom=1};bgcolor=0xEAEAEA;border={radius=6};color=0x444444;font=LOGFONT(h=-16);notify=1;z=5};
title={cls="static";text='MP3 \u2192 PCM \u2192 waveOut';left=24;top=18;right=655;bottom=49;anchors={left=1;top=1;right=1};font=LOGFONT(h=-22;weight=700);z=1}
)
/*}}*/

winform.speak.skin({background={default=0xFF0078D4;hover=0xFF168BE0;active=0xFF005A9E;disabled=0xFFE2E5E9};color={default=0xFFFFFFFF;disabled=0xFF888888}});
winform.stop.skin({background={default=0xFFEAEAEA;hover=0xFFDDDDDD;active=0xFFCCCCCC};color={default=0xFF444444;disabled=0xFFAAAAAA}});
winform.stop.disabled=true;

var engine=web.edgeTextToSpeech({voice="zh-CN-XiaoxiaoNeural";rate=1});
var task,player;

// 唯一的清理入口，可以重复调用，也可以在播放器事件中调用。
// 取消和关闭以后，旧的任务与播放器都不会再触发任何回调。
var stop=function(status){
    if(task) task.cancel();
    if(player) player.close();
    task,player=null,null;
    winform.speak.disabled=false;
    winform.stop.disabled=true;
    if(status) winform.status.text=status;
};

winform.speak.oncommand=function(){
    var text=string.trim(winform.edit.text);
    if(!#text){stop("请输入要朗读的文本。");return;}
    stop("正在连接语音服务");
    
    // 默认格式匹配 Edge TTS：24kHz、单声道 MP3。事件都在界面线程执行。
    var err;
    player,err=sys.mediaFoundation.streamingMp3Player({
        onEnd=function(){stop("播放完成");};
        onError=function(err){stop("朗读失败：" ++ err);}; // 合成失败也从这里报告
    });
    if(!player){stop(err);return;}
    
    task,err=engine.synthesize({text=text},player); // 音频直接写入播放器
    if(!task){stop(err.message);return;}
    
    winform.speak.disabled=true;
    winform.stop.disabled=false;
};

winform.stop.oncommand=function(){stop("已停止");};
winform.onClose=function(){stop();};

// 状态直接读播放器属性。
var stateText={buffering="正在缓冲";playing="正在播放";draining="合成结束，正在播完余音"};
winform.setInterval(function(){
    if(!player || !player.receivedBytes) return;
    winform.status.text=string.format("%s · 已播 %.2f 秒 · MP3 %.1f KiB",
        stateText[player.state] : player.state,player.playedSeconds,player.receivedBytes/1024);
},100);

winform.show();
win.loopMessage();

```

