mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-10 12:46:15 -08:00
30 lines
19 KiB
JavaScript
30 lines
19 KiB
JavaScript
import{_ as i,o as n,c as e,ak as a,j as t}from"./chunks/framework.xxfEszSJ.js";const E=JSON.parse('{"title":"独立音轨","description":"","frontmatter":{},"headers":[],"relativePath":"plugin/audio-track.md","filePath":"plugin/audio-track.md","lastUpdated":1789504112000}'),p={name:"plugin/audio-track.md"};function l(r,s,h,d,k,c){return n(),e("div",null,s[0]||(s[0]=[a(`<h1 id="独立音轨" tabindex="-1">独立音轨 <a class="header-anchor" href="#独立音轨" aria-label="Permalink to "独立音轨""></a></h1><p><a href="./../en/plugin/audio-track.html">English</a></p><p>为视频同步播放一个单独的音频文件。插件创建一个 <code>HTMLAudioElement</code>,跟随主视频的播放、暂停、进度、音量和播放速率,不需要额外 SDK,也不提供音轨选择菜单。</p><p>本页描述当前重构分支。生命周期修复和 <code>/runtime</code> 精确类型尚未发布;未固定版本的 npm/CDN 安装不能当作本分支代码。</p><h2 id="安装" tabindex="-1">安装 <a class="header-anchor" href="#安装" aria-label="Permalink to "安装""></a></h2><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">yarn</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> artplayer</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> artplayer-plugin-audio-track</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Artplayer </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> artplayerPluginAudioTrack </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer-plugin-audio-track'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>通过 script 使用时,先加载 ArtPlayer,再加载插件的 <code>dist/artplayer-plugin-audio-track.js</code>,全局名称为 <code>artplayerPluginAudioTrack</code>。应用应固定依赖版本,并提供浏览器可解码和访问的音频地址。</p><h2 id="完整示例" tabindex="-1">完整示例 <a class="header-anchor" href="#完整示例" aria-label="Permalink to "完整示例""></a></h2><p>下面与<a href="https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio.track" target="_blank" rel="noreferrer">在线音轨示例</a>使用同一份代码。站点提供示例媒体和 <code>.artplayer-app</code> 容器;接入自己的应用时替换这些地址和容器。</p>`,10),t("div",{className:"run-code","data-libs":"./uncompiled/artplayer-plugin-audio-track/index.js"},"▶ Run Code",-1),a(`<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// npm i artplayer-plugin-audio-track</span></span>
|
||
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// import artplayerPluginAudioTrack from 'artplayer-plugin-audio-track';</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">var</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> art </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Artplayer</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> container: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'.artplayer-app'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/assets/sample/sprite-fight.mp4'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> plugins: [</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> artplayerPluginAudioTrack</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/assets/sample/sprite-fight.aac'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> offset: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sync: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><h2 id="配置与同步" tabindex="-1">配置与同步 <a class="header-anchor" href="#配置与同步" aria-label="Permalink to "配置与同步""></a></h2><p><code>artplayerPluginAudioTrack(option)</code> 返回插件工厂,<code>option</code> 必须提供。</p><table tabindex="0"><thead><tr><th>字段</th><th>类型与默认值</th><th>行为</th></tr></thead><tbody><tr><td><code>url</code></td><td><code>string</code>,必填</td><td>独立音频文件地址。构造时的空字符串不加载音源。</td></tr><tr><td><code>offset</code></td><td><code>number</code>,默认 <code>0</code></td><td>音频目标时间为视频时间加上此值,单位秒。正数读取音频中更靠后的内容。</td></tr><tr><td><code>sync</code></td><td><code>number</code>,默认 <code>0.3</code></td><td>音频与目标时间的差值绝对值严格大于此值时,才调整音频时间。单位秒。</td></tr></tbody></table><p>例如视频在10秒、offset为0.25时,目标音频时间是10.25秒。这是纠正媒体时间的阈值同步,不是逐采样的专业音频时钟。使用有限、合理的偏移和非负阈值;负目标时间或超过音频时长的目标依赖浏览器的媒体边界行为,插件没有另加延迟启动、循环或补静音功能。</p><p>播放、seek完成和恢复播放时会同步;正常播放期间也根据 timeupdate 校正漂移。等待缓冲、切源清空、原生暂停、seek开始和结束播放会暂停独立音频;主视频继续播放并达到可恢复状态后再恢复。视频暂停时不会仅因canplay事件自行播放音频。</p><h2 id="返回值和更新" tabindex="-1">返回值和更新 <a class="header-anchor" href="#返回值和更新" aria-label="Permalink to "返回值和更新""></a></h2><p>安装后通过 <code>art.plugins.artplayerPluginAudioTrack</code> 取得结果:</p><table tabindex="0"><thead><tr><th>字段</th><th>行为</th></tr></thead><tbody><tr><td><code>name</code></td><td>固定为 <code>artplayerPluginAudioTrack</code>。</td></tr><tr><td><code>audio</code></td><td>实际的 <code>HTMLAudioElement</code>;更新音源时保持同一个元素。</td></tr><tr><td><code>update(option)</code></td><td>同步更新部分字段,返回 <code>undefined</code>,不是加载完成的Promise。</td></tr></tbody></table><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> track</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> art.plugins.artplayerPluginAudioTrack;</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">track.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">update</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ offset: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.25</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, sync: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">track.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">update</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/audio/another-language.m4a'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>offset/sync更新不会立即强制seek,下一次同步事件才使用新值。只有非空且不同的url会替换音源;相同url不会重新加载,空url也不是停止或清空命令。若主视频正在播放,替换音源会尝试播放;音频的实际加载、解码和错误可从暴露的元素监听。</p><p>调用 <code>art.switchUrl()</code> 只更换主视频,不会自动选择另一份音频;应用需要同时管理视频与音轨的对应关系,并用 <code>track.update()</code> 指定新音源。需要等待媒体可用时监听原生媒体事件,不要把 <code>await track.update(...)</code> 当作等待加载。</p><h2 id="音量、播放失败与销毁" tabindex="-1">音量、播放失败与销毁 <a class="header-anchor" href="#音量、播放失败与销毁" aria-label="Permalink to "音量、播放失败与销毁""></a></h2><p>插件不会自动去掉主视频的原声。如果希望独立音轨是唯一声音,使用没有原声音轨的视频源。播放器的音量、静音和倍速会同步到独立音频;设置 <code>art.muted = true</code> 会一起静音,不能用它只关闭主视频声音。</p><p>独立音频的播放仍受浏览器策略约束。活动实例的 <code>audio.play()</code> 拒绝会通过 <code>console.warn</code> 报告,不会变成 <code>update()</code> 的Promise拒绝。主视频播放成功也不等于独立音频已经成功发声;应用可监听 <code>audio</code> 的 playing/error 等原生事件。</p><p>销毁ArtPlayer会移除插件订阅、暂停音频、移除src并释放媒体加载。保留的结果对象仍指向同一个audio,销毁后的update不再重新加载或播放。应用自己添加到audio上的监听器仍由应用负责移除;无需另外调用一个不存在的插件destroy方法。</p><h2 id="typescript" tabindex="-1">TypeScript <a class="header-anchor" href="#typescript" aria-label="Permalink to "TypeScript""></a></h2><p>根入口与 <code>/legacy</code> 保留旧 <code>Result.update(Option)</code> 声明,包含必填url,避免改变旧代码的参数提取与函数赋值。运行时一直支持部分字段更新;需要准确的部分更新类型时,选择同一实现的 <code>/runtime</code>:</p><div class="language-ts vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Artplayer </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> audioTrack </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer-plugin-audio-track/runtime'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> installTrack</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> audioTrack</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/audio/dialogue.m4a'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> art</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Artplayer</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> container: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'.artplayer-app'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/video/silent.mp4'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> plugins: [(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">player</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> track</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> installTrack</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(player);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> track.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">update</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ offset: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.25</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> track;</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>命名类型包括 <code>Option</code>、<code>UpdateOption</code>、旧 <code>Result</code>、<code>RuntimeResult</code> 与 <code>RuntimeFactory</code>。在线编辑器的全局默认类型也保留旧推导;选择精确更新类型时,可显式使用 <code>artplayerPluginAudioTrack as artplayerPluginAudioTrack.RuntimeFactory</code>。这不会创建第二份插件实现。</p><p>真实桌面测试覆盖音频/视频播放、暂停、seek、更新和销毁;它们不证明所有移动设备、代理播放器、音频格式或长时间同步组合都通过。完整支持范围仍需结合对应浏览器的解码能力与项目验收记录。</p><p>Windows WebKit 的 MP4/AAC 耗尽缓冲仍有原生媒体验证缺口:该复现中视频停滞不可靠地触发 waiting。换源顺序检查通过不代表这一独立问题已关闭。</p>`,22)]))}const u=i(p,[["render",l]]);export{E as __pageData,u as default};
|