uni直播是DCloud与七牛云合作推出的直播服务,七牛云直播依托云边一体化架构和海量节点资源,构建高效的流媒体服务。通过多维度的节点监控与弹性的节点调度管理,确保高质量服务与成本效益的完美平衡。

live-player 组件是uni直播服务中的拉流(播放)组件,在 Android/iOS 平台使用需要申请绑定包名/Bundle ID(AppID),详情咨询

# live-player

实时音视频播放

# 兼容性

Web 微信小程序 Android iOS HarmonyOS
x 4.41 4.81 4.81 x

# 属性

名称 类型 默认值 兼容性 描述
src string(string.VideoURIString) -
音视频地址。微信小程序支持 flv, rtmp 格式,app平台支持 rtmp, hls 协议
mode string -
live(直播),RTC(实时通话)
合法值 兼容性 描述
RTC
-
live
-
autoplay boolean false
自动播放
muted boolean false
是否静音
orientation string "vertical"
画面方向,可选值有 vertical,horizontal
合法值 兼容性 描述
vertical
-
horizontal
-
object-fit string "contain"
填充模式,可选值有 contain,fillCrop
合法值 兼容性 描述
contain
-
fillCrop
-
background-mute boolean false
进入后台时是否静音
min-cache string -
最小缓冲区,单位s
max-cache string -
最大缓冲区,单位s
@statechange (event: UniLivePlayerStatechangeEvent) => void -
播放状态变化事件,event.detail = {code}
@fullscreenchange (event: UniLivePlayerFullscreenchangeEvent) => void -
全屏变化事件,event.detail = {direction, fullScreen}
@error (event: UniLivePlayerErrorEvent) => void -
错误事件,event.detail = {errCode, errMsg}
@netstatus (event: UniEvent) => void -
网络状态通知,detail = {info}
sound-mode string -
(string)
声音输出方式
合法值 兼容性 描述
speaker
扬声器
ear
听筒
auto-pause-if-navigate boolean -
(boolean)
当跳转到本小程序的其他页面时,是否自动暂停本页面的实时音视频播放
auto-pause-if-open-native boolean -
(boolean)
当跳转到其它微信原生页面时,是否自动暂停本页面的实时音视频播放
picture-in-picture-mode string/Array -
(string/Array)
设置小窗模式: push, pop,空字符串或通过数组形式设置多种模式(如: ["push", "pop"]
合法值 兼容性 描述
[]
取消小窗
push
路由 push 时触发小窗
pop
路由 pop 时触发小窗
picture-in-picture-init-position= string -
(string)
小窗模式下小窗的初始显示位置,格式为 (alignment, y),其中 alignment 表示小窗吸附屏幕左侧还是右侧,可选值为 left、right,y 代表小窗最顶部所在的屏幕高度百分比
enable-auto-rotation boolean -
(boolean)
是否开启手机横屏时自动全屏,当系统设置开启自动旋转时生效
referrer-policy string -
(string)
格式固定为 https://servicewechat.com/{appid}/{version}/page-frame.html,其中 {appid} 为小程序的 appid,{version} 为小程序的版本号,版本号为 0 表示为开发版、体验版以及审核版本,版本号为 devtools 表示为开发者工具,其余为正式版本;
合法值 兼容性 描述
origin
发送完整的referrer
no-referrer
不发送
enable-casting boolean -
(boolean)
是否支持投屏。开启后,可以通过 LivePlayerContext 上相关方法进行操作。
@audiovolumenotify eventhandler -
(eventhandler)
播放音量大小通知,detail = {}
@enterpictureinpicture eventhandler -
(eventhandler)
播放器进入小窗
@leavepictureinpicture eventhandler -
(eventhandler)
播放器退出小窗
@castinguserselect eventhandler -
(eventhandler)
用户选择投屏设备时触发 detail = { state: "success"/"fail" }
@castingstatechange eventhandler -
(eventhandler)
投屏成功/失败时触发 detail = { type, state: "success"/"fail" }
@castinginterrupt eventhandler -
(eventhandler)
投屏被中断时触发

# 事件

# UniLivePlayerStatechangeEvent

播放状态变化事件

# UniLivePlayerStatechangeEvent 的属性值
名称 类型 必填 默认值 兼容性 描述
detail UniLivePlayerStatechangeEventDetail - - -
名称 类型 必备 默认值 兼容性 描述
code number -
状态码
合法值 兼容性 描述
10000 - -
10001 - 初始化
10002 - 准备播放
10004 - 播放中
10006 - 停止渲染
10007 - 播放完成
10008 - 播放进度跳转中
10009 - 播放停止
10010 - 播放错误
10011 - 播放结束
10012 - -
10013 - 资源释放
bubbles boolean - - -
cancelable boolean - - -
type string - - -
target UniElement - - -
currentTarget UniElement - - -
timeStamp Long - - -
# UniLivePlayerStatechangeEvent 的方法
名称 类型 必填 默认值 兼容性 描述
stopPropagation () => void - - -
preventDefault () => void - - -

# UniLivePlayerFullscreenchangeEvent

全屏事件

# UniLivePlayerFullscreenchangeEvent 的属性值
名称 类型 必填 默认值 兼容性 描述
detail UniLivePlayerFullscreenchangeEventDetail - - -
名称 类型 必备 默认值 兼容性 描述
direction string -
屏幕方向
fullScreen boolean -
是否全屏
bubbles boolean - - -
cancelable boolean - - -
type string - - -
target UniElement - - -
currentTarget UniElement - - -
timeStamp Long - - -
# UniLivePlayerFullscreenchangeEvent 的方法
名称 类型 必填 默认值 兼容性 描述
stopPropagation () => void - - -
preventDefault () => void - - -

# UniLivePlayerErrorEvent

错误事件

# UniLivePlayerErrorEvent 的属性值
名称 类型 必填 默认值 兼容性 描述
detail UniLivePlayerError - - -
名称 类型 必备 默认值 兼容性 描述
errCode number - - -
合法值 兼容性 描述
3001 - 当前视频格式不支持,视频无法播放
3002 - 视频解码失败
3003 - 不支持的解码格式
3004 - 重连失败,请检查网络情况
3005 - 视频播放失败,请检查网络或视频资源
errSubject string - - 统一错误主题(模块)名称
data any - - 错误信息中包含的数据
cause Error - - 源错误信息,可以包含多个错误,详见SourceError
errMsg string - - -
bubbles boolean - - -
cancelable boolean - - -
type string - - -
target UniElement - - -
currentTarget UniElement - - -
timeStamp Long - - -
# UniLivePlayerErrorEvent 的方法
名称 类型 必填 默认值 兼容性 描述
stopPropagation () => void - - -
preventDefault () => void - - -

# 音视频协议

  • 支持 rtmp、hls 协议格式。

# 上下文对象API

uni.createLivePlayerContext()

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验

扫码体验(手机浏览器跳转到App直达页)
<template>
  <view class="uni-flex-item">
    <live-player id="live-player" class="live-player" :src="src" :autoplay="autoplay" :muted="muted"
      :object-fit="objectFit" :background-mute="backgroundMute" :sound-mode="soundMode" :orientation="orientation"
      @statechange="statechange" @fullscreenchange="fullscreenchange" @error="error">
    </live-player>
    <scroll-view class="uni-padding-wrap uni-common-mt uni-flex-item">
      <view class="uni-title">
        <text class="uni-title-text">API示例</text>
      </View>
      <view class="uni-btn-v">
        <button type="primary" @click="play" :disabled="playState">播放</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="pause" :disabled="!playState">暂停</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="resume" :disabled="initState || playState || stopState">恢复</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="stop" :disabled="!playState">停止</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="mute" :disabled="!playState">静音</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="requestFullScreen" :disabled="!playState">进入全屏</button>
      </view>
      <view class="uni-btn-v">
        <button type="primary" @click="exitFullScreen" :disabled="!playState">退出全屏</button>
      </view>
      <view class="uni-title">
        <text class="uni-title-text">属性示例</text>
      </view>
      <input class="input margin-10" type="string" placeholder="设置播放地址" @confirm="onSrcComfirm"></input>
      <boolean-data title="设置是否自动播放" :defaultValue="autoplay" @change="onAutoplayChange"></boolean-data>
      <boolean-data title="设置是否静音" :defaultValue="muted" @change="onMutedChange"></boolean-data>
      <boolean-data title="设置进入后台时是否静音" :defaultValue="backgroundMute" @change="onBackgroundMuteChange"></boolean-data>
      <enum-data title="设置填充模式" :items="objectFitItemTypes" @change="onObjectFitChange"></enum-data>
      <enum-data title="设置声音输出方式" :items="soundModeItemTypes" @change="onSoundModeChange"></enum-data>
      <enum-data title="设置画面方向" :items="orientationItemTypes" @change="onOrientationChange"></enum-data>
    </scroll-view>
  </view>
</template>

<script setup>
  import { ItemType } from '@/components/enum-data/enum-data-types';

  const context = ref(null as LivePlayerContext | null);
  const src = ref("");
  const autoplay = ref(false);
  const muted = ref(false);
  const objectFit = ref("contain");
  const backgroundMute = ref(false);
  const soundMode = ref("speaker");
  const orientation = ref("vertical");
  const initState = ref(true);
  const playState = ref(false);
  const stopState = ref(false);

  onReady(() => {
    context.value = uni.createLivePlayerContext("live-player", getCurrentInstance()!.proxy);
  });

  const statechange = (e : UniLivePlayerStatechangeEvent) => {
    console.log("statechange", e);
    switch (e.detail.code) {
      case 10004:
        initState.value = false;
        playState.value = true;
        stopState.value = false;
        break;
      case 10009:
        stopState.value = true;
      case 10006:
      case 10007:
      case 10010:
      case 10011:
        playState.value = false;
        break;
    }
  };
  const fullscreenchange = (e : UniLivePlayerFullscreenchangeEvent) => {
    console.log("fullscreenchange", e);
  };
  const error = (e : UniLivePlayerErrorEvent) => {
    console.log("error", e);
  };
  const isSrcValid = () : boolean => {
    const length = src.value.length;
    if (length <= 0) {
      uni.showToast({
        title: "请输入播放地址",
        icon: "none"
      });
    }
    return length > 0;
  };
  const play = () => {
    if (!isSrcValid()) return;
    context.value?.play({
      success: (res) => {
        console.log("play", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("play", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("play", JSON.stringify(res));
      }
    });
  };
  const pause = () => {
    if (!isSrcValid()) return;
    context.value?.pause({
      success: (res) => {
        console.log("pause", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("pause", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("pause", JSON.stringify(res));
      }
    });
  };
  const resume = () => {
    if (!isSrcValid()) return;
    context.value?.resume({
      success: (res) => {
        console.log("resume", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("resume", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("resume", JSON.stringify(res));
      }
    });
  };
  const stop = () => {
    if (!isSrcValid()) return;
    context.value?.stop({
      success: (res) => {
        console.log("stop", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("stop", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("stop", JSON.stringify(res));
      }
    });
  };
  const mute = () => {
    if (!isSrcValid()) return;
    context.value?.mute({
      success: (res) => {
        console.log("mute", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("mute", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("mute", JSON.stringify(res));
      }
    });
  };
  const requestFullScreen = () => {
    if (!isSrcValid()) return;
    context.value?.requestFullScreen({
      success: (res) => {
        console.log("requestFullScreen", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("requestFullScreen", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("requestFullScreen", JSON.stringify(res));
      }
    });
  };
  const exitFullScreen = () => {
    if (!isSrcValid()) return;
    context.value?.exitFullScreen({
      success: (res) => {
        console.log("exitFullScreen", JSON.stringify(res));
      },
      fail: (err) => {
        console.log("exitFullScreen", JSON.stringify(err));
      },
      complete: (res) => {
        console.log("exitFullScreen", JSON.stringify(res));
      }
    });
  };

  const objectFitItemTypes = [{ "value": 0, "name": "contain" }, { "value": 1, "name": "fillCrop" }] as ItemType[];
  const objectFitItems = ["contain", "fillCrop"];
  const soundModeItemTypes = [{ "value": 0, "name": "speaker" }, { "value": 1, "name": "ear" }] as ItemType[];
  const soundModeItems = ["speaker", "ear"];
  const orientationItemTypes = [{ "value": 0, "name": "vertical" }, { "value": 1, "name": "horizontal" }] as ItemType[];
  const orientationItems = ["vertical", "horizontal"];
  const onSrcComfirm = (event : UniInputConfirmEvent) => {
    let value = event.detail.value;
    if (value == '') return;
    src.value = value;
    console.log("src ->", value);
  };
  const onAutoplayChange = (value : boolean) => {
    autoplay.value = value;
    console.log("autoplay ->", autoplay.value);
  };
  const onMutedChange = (value : boolean) => {
    muted.value = value;
    console.log("muted ->", muted.value);
  };
  const onBackgroundMuteChange = (value : boolean) => {
    backgroundMute.value = value;
    console.log("background-mute ->", backgroundMute.value);
  };
  const onObjectFitChange = (value : number) => {
    objectFit.value = objectFitItems[value];
    console.log("object-fit ->", objectFit.value);
  };
  const onSoundModeChange = (value : number) => {
    soundMode.value = soundModeItems[value];
    console.log("sound-mode ->", soundMode.value);
  };
  const onOrientationChange = (value : number) => {
    orientation.value = orientationItems[value];
    console.log("orientation ->", orientation.value);
  };
</script>

<style>
  .live-player {
    width: 100%;
    height: 40%;
  }

  .input {
    height: 40px;
    background: #FFF;
    padding: 8px 13px;
  }

  .margin-10 {
    margin: 10px;
  }
</style>

# 参见