听《富婆KTV》让我学到个新的API

起因

作为一名前端开发,我有在网页上听歌的习惯,那天我如常边听我的每日推荐边写代码,突然一首非常攒劲带感 的音乐成功引起了我的注意,我想去调大我耳机的声音,就点了下右下角任务栏的声音,我发现弹出来的面板上面竟然有播放控件歌曲名字作者专辑封面的信息。

好奇

突然让我思考一个问题:

操作系统是怎么知道我在网页上听的是什么歌呢?

在我一通探索下,发现了 MediaSession 这个 API

Media Session API 是一个 Web API

Media Session API 允许网页为媒体播放提供自定义行为,并与设备的原生媒体控制界面(如通知栏、锁屏、键盘媒体键、耳机按钮等)交互。主要功能包括: 元数据共享:通过 MediaMetadata 对象,网页可以向浏览器和操作系统提供当前播放媒体的标题、艺术家、专辑、封面等信息,这些信息会显示在设备的媒体控制界面上。

  1. 自定义控制行为:通过 setActionHandler 方法,开发者可以为播放、暂停、快进、快退、上一曲、下一曲等操作设置回调函数,响应用户通过设备媒体控制触发的动作。

  2. 播放状态同步:通过 playbackState 属性,网页可以声明媒体的播放状态(playingpausednone),确保设备界面与网页状态一致。

  3. 位置状态更新:通过 setPositionState 方法,网页可以更新媒体的当前播放位置、总时长和播放速度,供设备界面显示进度条等信息。

  4. 视频会议支持:支持视频会议相关的操作,如开关麦克风、摄像头或挂断通话(togglemicrophonetogglecamerahangup)。

  5. 画中画模式支持:在画中画(Picture-in-Picture)模式下,可以为幻灯片导航等场景提供自定义控制(如 previousslide、nextslide)。

Media Session API 广泛应用于音频播放器、视频播放器、播客应用、流媒体网站等场景,让用户可以通过设备的原生界面或硬件控制媒体播放。

navigator.mediaSession 是访问 Media Session API 的入口点,它是一个只读属性,返回一个 MediaSession 对象。开发者通过这个对象配置媒体元数据、设置动作处理程序等。

这些功能都怎么用呢?

设置媒体元数据

在播放歌曲的网页打开控制台,看看 navigator.mediaSession 的内容你就大概了解了:

js 复制代码
navigator.mediaSession.metadata = new MediaMetadata({
    title: '歌曲名称',
    artist: '作者',
    album: '专辑名称',
    artwork: [
      { src: 'https://xxx.image.com/96x96', sizes: '96x96', type: 'image/png' },
      { src: 'https://xxx.image.com/128x128', sizes: '128x128', type: 'image/png' },
      { src: 'https://xxx.image.com/512x512', sizes: '512x512', type: 'image/png' }
    ]
  });

需要注意的:

  • artwork 是一个 MediaImage 对象的数组,建议提供多种尺寸的图片(如 96x96、128x128、512x512)以适配不同设备。
  • 如果未设置 artwork,浏览器可能使用页面的 <link rel="icon"> 作为默认图片

设置动作处理程序

通过 setActionHandler 方法为媒体控制动作设置回调函数,支持的动作包括:

  • play:播放

  • pause:暂停

  • stop:停止

  • seekbackward:后退(默认 10 秒)

  • seekforward:前进(默认 10 秒)

  • seekto:跳转到指定时间

  • previoustrack:上一曲

  • nexttrack:下一曲

  • skipad:跳过广告

  • togglemicrophone:开关麦克风

  • togglecamera:开关摄像头

  • hangup:挂断通话

  • previousslide / nextslide:幻灯片导航(画中画模式)

给一个为播放和暂停设置动作处理程序,并同步播放状态的例子:

js 复制代码
const audio = document.querySelector('#player');
audio.src = 'song.mp3';

if ('mediaSession' in navigator) {
  // 设置播放动作
  navigator.mediaSession.setActionHandler('play', async () => {
    await audio.play();
    navigator.mediaSession.playbackState = 'playing';
  });

  // 设置暂停动作
  navigator.mediaSession.setActionHandler('pause', () => {
    audio.pause();
    navigator.mediaSession.playbackState = 'paused';
  });

  // 监听音频元素状态变化
  audio.addEventListener('play', () => {
    navigator.mediaSession.playbackState = 'playing';
  });
  audio.addEventListener('pause', () => {
    navigator.mediaSession.playbackState = 'paused';
  });
}

注意:

  1. 使用 try-catch 检测动作是否支持,因为某些动作(如 stop、seekto)可能在部分浏览器中不可用

  2. 要移除动作处理程序,可将回调设为 null:navigator.mediaSession.setActionHandler('play', null)

  3. 动作处理程序会持久存在,直到页面卸载或手动移除。

更新播放位置

通过 setPositionState 方法更新媒体的播放位置、时长和速度,适用于显示进度条或时间信息:

js 复制代码
function updatePositionState() {
  if ('setPositionState' in navigator.mediaSession) {
    navigator.mediaSession.setPositionState({
      duration: audio.duration, // 媒体总时长(秒)
      playbackRate: audio.playbackRate, // 播放速度
      position: audio.currentTime // 当前位置(秒)
    });
  }
}

// 在时间更新或动作触发时调用
audio.addEventListener('timeupdate', updatePositionState);

// 示例:处理快退动作
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  const skipTime = details.seekOffset || 10; // 默认后退 10 秒
  audio.currentTime = Math.max(audio.currentTime - skipTime, 0);
  updatePositionState();
});

注意:

  1. duration 必须为正数,直播流可用 Infinity 表示无固定时长。
  2. 在媒体加载完成前,audio.duration 可能为 NaN,需进行检查。

处理播放列表导航

支持 previoustracknexttrack 动作,用于切换播放列表中的曲目。

js 复制代码
const playlist = ['song1.mp3', 'song2.mp3', 'song3.mp3'];
let index = 0;

function playAudio() {
  audio.src = playlist[index];
  audio.play().then(() => {
    navigator.mediaSession.metadata = new MediaMetadata({
      title: `Song ${index + 1}`,
      artist: 'Artist Name',
      album: 'Album Name',
      artwork: [{ src: 'cover.jpg', sizes: '512x512', type: 'image/jpeg' }]
    });
    updatePositionState();
  });
}

navigator.mediaSession.setActionHandler('previoustrack', () => {
  index = (index - 1 + playlist.length) % playlist.length;
  playAudio();
});

navigator.mediaSession.setActionHandler('nexttrack', () => {
  index = (index + 1) % playlist.length;
  playAudio();
});

视频会议场景

为视频会议设置麦克风和摄像头控制。

js 复制代码
let isMicrophoneActive = false;
navigator.mediaSession.setActionHandler('togglemicrophone', () => {
  isMicrophoneActive = !isMicrophoneActive;
  // 切换麦克风状态的逻辑
  navigator.mediaSession.setMicrophoneActive(isMicrophoneActive);
});

视频会议动作(如 togglemicrophone)目前支持有限,主要在 Chrome 92+ 桌面版中可用

画中画模式支持

在画中画模式下,为幻灯片导航设置动作

js 复制代码
navigator.mediaSession.setActionHandler('previousslide', () => {
  // 切换到上一页幻灯片
});
navigator.mediaSession.setActionHandler('nextslide', () => {
  // 切换到下一页幻灯片
});

最后总结

MediaSession 通过 navigator.mediaSession 提供,允许网页与设备的媒体控制界面交互,支持元数据共享、自定义动作和状态同步。歌也听了,API 也学到了,要是觉得歌有意思或者这个API有用,就给点个关注点个赞吧,彦祖、亦菲们~。我是 Senar,是不是分享点有用没用的前端开发知识,我们下期再见~

相关推荐
网络点点滴1 小时前
将项目推到Github
javascript·github
HaanLen1 小时前
React19源码系列之 Hooks (useState、useReducer、useOptimistic)
服务器·前端
yuanyxh4 小时前
《精通正则表达式》精华摘要
前端·javascript·正则表达式
小飞大王6664 小时前
简单实现HTML在线编辑器
前端·编辑器·html
Jimmy5 小时前
CSS 实现卡牌翻转
前端·css·html
百万蹄蹄向前冲5 小时前
大学期末考,AI定制个性化考试体验
前端·人工智能·面试
向明天乄5 小时前
在 Vue 3 项目中集成高德地图(附 Key 与安全密钥申请全流程)
前端·vue.js·安全
sunshine_程序媛5 小时前
vue3中的watch和watchEffect区别以及demo示例
前端·javascript·vue.js·vue3
电商数据girl6 小时前
【经验分享】浅谈京东商品SKU接口的技术实现原理
java·开发语言·前端·数据库·经验分享·eclipse·json