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
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 上相关方法进行操作。
duration number
initial-time number
loop boolean
codec string
show-play-btn boolean
show-mute-btn boolean
show-fullscreen-btn boolean
show-progress boolean
enable-progress-gesture boolean
poster string
controls boolean
show-center-play-btn boolean
show-loading boolean
@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}
@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>

# 参见