# miniprogram-ar-play

> ar-play组件从服务端拉取实时流。

Latest version **1.0.9** (published 2019-11-12) · MIT license · 0 weekly downloads

## Install

```sh
npm install miniprogram-ar-play
pnpm add miniprogram-ar-play
yarn add miniprogram-ar-play
bun add miniprogram-ar-play
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.9 |
| Published | 2019-11-12 |
| First published | 2018-12-10 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 34.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | ar-team |
| Maintainers | ar-team |

## Links

- npm: https://www.npmjs.com/package/miniprogram-ar-play
- npm.io page: https://npm.io/package/miniprogram-ar-play

## Recent versions

- 1.0.9 (latest) — 2019-11-12
- 1.0.8 — 2019-11-12
- 1.0.7 — 2019-07-11
- 1.0.6 — 2019-07-02
- 1.0.5 — 2019-07-02
- 1.0.4 — 2019-01-17
- 1.0.3 — 2019-01-07
- 1.0.2 — 2019-01-06
- 1.0.1 — 2019-01-06
- 1.0.0 — 2018-12-10

## README

# ar-play 拉流组件

ar-play组件从服务端拉取实时流。

小程序自定义组件

> 使用此组件需要依赖小程序基础库 2.2.1 以上版本，同时依赖开发者工具的 npm 构建。具体详情可查阅[官方 npm 文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html)。

# 准备工作

1. 注册微信小程序，登录小程序后台获取微信小程序appid，appSecrert，修改类目审核（社交、教育、医疗、政务民生、金融，目前只有这些支持），配置socket合法域名wss://域名:9095
2. 获取开发者信息
3. 开发-配置中开启“使用npm模块”，基础库选择2.4.0及以上，打开“不校验合法域名”、真机调试打开“调试”。集成miniprogram-ar-meet、miniprogram-ar-push、miniprogram-ar-play

# 使用说明

> 1.结合[小程序会议SDK](https://www.npmjs.com/package/miniprogram-ar-meet)使用  
> 2.结合[小程序推流组件](https://www.npmjs.com/package/miniprogram-ar-push)和[小程序拉流组件](https://www.npmjs.com/package/miniprogram-ar-play)使用

# 使用方法

1. 安装 ar-play  

```
npm install --save miniprogram-ar-play
```

2. 在需要使用 slide-view 的页面 page.json 中添加 ar-play 自定义组件配置

```
{
  "usingComponents": {
    "ar-play": "miniprogram-ar-play"
  }
}
```

WXML 文件中引用 ar-play

```
<!-- 拉流组件 -->
<ar-play 
  id="{{pubID}}-play"
  data-id="{{pubID}}"
  enableAudio="{{enableAudio}}"
  playURL="{{playURL}}" 
  bindNetStateChange="handlePlayNetChange"
  bindPlayStatus="handlePlayStatus">
</ar-play>
```

组件可递归、可用view包裹自定义样式。例如：

```
<view wx:for="{{members}}" wx:key="index">
  <ar-play 
    id="{{item.pubID}}-play" 
    data-id="{{item.pubID}}"
    pubID="{{item.pubID}}" 
    playURL="{{item.playURL}}" 
    bindNetStateChange="handlePlayNetChange"
    bindPlayStatus="handlePlayStatus">
  </ar-play>
  <button data-id="{{item.pubID}}" bindtap="pause">暂停</button>
  <button data-id="{{item.pubID}}" bindtap="play">播放</button>
  <button data-id="{{item.pubID}}" bindtap="full">全屏</button>
</view>
```

### ar-play的属性介绍如下：

|属性名|类型|默认值|是否必须|说明|
|--|--|--|--|--|--|
|id|String|-|是|用户获取组件的```LivePlayerContext```来暂停、播放等[操作](https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.html)。|
|playURL|String|-|是|ar-play组件拉流URL|
|objectFit|String|`contain`|否|`contain`图像长边填满屏幕，短边区域会被填充⿊⾊; `fillCrop`图像铺满屏幕，超出显示区域的部分将被截掉|
|orientation|String|`vertical`|否|画面方向：`vertical`竖直; `horizontal`水平|
|enableAudio|Boolean|true|否|ar-play组件是否静音|
|bindNetStateChange|Function|-|否|监听ar-play组件拉流网络质量|
|bindPlayStatus|Function|-|否|ar-play组件播放状态的回调|

# 完整代码（以实时视频会议为例）

WXML

```
<!--pages/room/room.wxml-->

<!-- 推流组件，view包裹可自定义样式 -->
<view>
  <ar-push 
    id="arPush"
    coverImg=""
    enableAudio="{{enableAudio}}"
    enableVideo="{{enableVideo}}"
    pushURL="{{pushURL}}" 
    bindNetStateChange="handlePushNetChange"
    bindRoomEvent="handleRoomEvent">
  </ar-push>
</view>

<button class="meet_btn" bindtap="pausePush">暂停推流</button>
<button class="meet_btn" bindtap="resumePush">恢复推流</button>
<button class="meet_btn" bindtap="switchCamera">切换前后摄像头</button>
<button class="" bindtap="enableCamera">开关摄像头 ：： 当前状态{{enableVideo ? '开' : '关'}}</button>
<button class="" bindtap="enableMicphone">开关麦克风 ：： 当前状态{{enableAudio ? '开' : '关'}}</button>

<!-- 拉流组件，view包裹可自定义样式-->
<view wx:for="{{members}}" wx:key="index">
  <ar-play 
    id="{{item.pubID}}-play" 
    data-id="{{item.pubID}}"
    pubID="{{item.pubID}}" 
    playURL="{{item.playURL}}" 
    bindNetStateChange="handlePlayNetChange"
    bindPlayStatus="handlePlayStatus">
  </ar-play>
  <button class="meet_btn" data-id="{{item.pubID}}" bindtap="pause">暂停</button>
  <button class="meet_btn" data-id="{{item.pubID}}" bindtap="play">播放</button>
  <button class="meet_btn" data-id="{{item.pubID}}" bindtap="full">全屏</button>
</view>

<button type="button" bindtap="leaveRoom">退出房间</button>

```

JS

```
const config = require('../../config.js');
let wxRTMeet = require('miniprogram-ar-meet');

// pages/room/room.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    arPusherComponent: null,
    wxmeet: null,
    pushURL: '',
    enableVideo: true,
    enableAudio: false,
    members: []
  },

  //停止推流
  pausePush () {
    this.data.arPusherComponent.pause();
  },
  //恢复推流
  resumePush () {
    this.data.arPusherComponent.resume();
  },
  //切换摄像头
  switchCamera () {
    this.data.arPusherComponent.switchCamera();
  },
  //截图
  takeSnapshot () {
    this.data.arPusherComponent.snapshot(res => {
      console.log("截图结果", res);
    });
  },
  //打开/关闭摄像头
  enableCamera () {
    this.setData({
      enableVideo: !this.data.enableVideo
    });
  },
  //打开/关闭麦克风
  enableMicphone () {
    this.setData({
      enableAudio: !this.data.enableAudio
    });
  },
  //退出房间
  leaveRoom() {
    this.data.wxmeet.leaveRoom();
    wx.navigateBack();
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    let that = this;

    let roomId = '' + options.roomid;

    let wxmeet = new wxRTMeet();

    that.setData({
      wxmeet: wxmeet,
      arPusherComponent: that.selectComponent('#arPush')
    });

    wxmeet.initEngine(config.DEV_ID, config.APP_ID, config.APP_KEY, config.APP_TOKEN, config.APP_DOMAIN);

    let userid = '' + parseInt(Math.random() * 10000);
    let username = '' + parseInt(Math.random() * 1000000);

    wxmeet.joinRoom(roomId, userid, username,JSON.stringify({ userid }));

    wxmeet.on("onJoinRoomOK", () => {
      wx.showToast({
        title: '加入房间成功',
      });
    });

    wxmeet.on("onJoinRoomFaild", (code, info) => {
      console.log("加入房间失败：", code, info ? info : "");
    });

    //收到离开房间指令,收到该回调需要离开房间
    wxmeet.on("onLeaveMeet", (code, info) => {
      console.log("离开房间的原因：", info ? info : "");
    });
    
    wxmeet.on("onGetPushUrl", (code, data) => {
      console.log('onGetPushUrl', code, data);
      if (code === 0) {//成功
        that.setData({
          pushURL: data.pushURL
        });
      } else {
        wx.showToast({
          icon: 'none',
          title: '获取房间签名失败',
        });
      }
    });

    wxmeet.on("onUserMessage", (strUserId, strUserName, strHeaderUrl, strUserData) => {
      console.log("onUserMessage", strUserId, strUserName, strHeaderUrl, strUserData);
    });
  },

  //监听房间事件
  handleRoomEvent (e) {
    let that = this;
    let data = e.detail;

    console.log('handleRoomEvent', data);
    switch (data.tag) {
      case "MemberChange":
        let arrMember = data.detail;
        arrMember.map(item => {
          item.width = 100;
          item.height = 100;
        });

        that.setData({
          members: arrMember
        });
        break;
      case "PushError":
        //重新进会
        break;
    }
  },

  //监听推流网络质量
  handlePushNetChange (e) {
    let that = this;
    let data = e.detail;

    console.log('handlePushNetChange ====> 音频码率: %d , 视频码率: %d , 网络偏移: %d , 帧率：%d , 视频分辨率： %d * %d , GOP： %d', data.audioBitrate, data.videoBitrate, data.netJitter ? data.netJitter : 0, data.videoFPS, data.videoWidth, data.videoHeight, data.videoGOP);
  },

  //监听拉流网络质量
  handlePlayNetChange(e) {
    let that = this;
    let data = e.detail;

    console.log('handlePlayNetChange 用户PubId：', e.currentTarget.id.replace('user_', '').replace('-play', ''), ' , 用户网络状态: ', data);
  },

  //监听播放状态
  handlePlayStatus (e) {
    let that = this;
    let data = e.detail;

    //错误码参考 https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html
    console.log('handlePlayStatus', `pubID为 ${data.pubID} 的播放状态为 ${data.code}`);
  },

  pause (e) {
    let that = this;
    let data = e.currentTarget.dataset;

    console.log('pause', data);
    console.log('selectComponent', that.selectComponent(`#${data.id}-play`));

    //参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.pause.html
    that.selectComponent(`#${data.id}-play`).pause({
      complete: res => {
        console.log('selectComponent pause', res);
      }
    });
  },

  play (e) {
    let that = this;
    let data = e.currentTarget.dataset;

    //参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.play.html
    that.selectComponent(`#${data.id}-play`).play({
      complete: res => {
        console.log('selectComponent pause', res);
      }
    });
  },

  full (e) {
    let that = this;
    let data = e.currentTarget.dataset;

    //参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.requestFullScreen.html
    that.selectComponent(`#${data.id}-play`).requestFullScreen({
      direction: 90,
      complete: res => {
        console.log('selectComponent pause', res);
      }
    });
    //此处由于只做演示，所以2秒之后结束全屏
    setTimeout(() => {
      that.selectComponent(`#${data.id}-play`).exitFullScreen({
        complete: res => {
          console.log('selectComponent pause', res);
        }
      });
    }, 2000);
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    this.data.wxmeet.leaveRoom();
  },
})
```

---
_Source: https://npm.io/package/miniprogram-ar-play · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
