• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import media from '@ohos.multimedia.media';
16import Logger from '../utils/Logger'
17
18const TAG: string = '[AVPlayerModel]'
19
20export default  class AVPlayerModel {
21  private avPlayer: media.AVPlayer;
22  private count: number = 1;
23  private surfaceID: string = ''; // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法
24  private isSeek: boolean = true; // 用于区分模式是否支持seek操作
25
26  private context;
27
28  constructor(context) {
29    this.context = context;
30  }
31
32  // 注册avplayer回调函数
33  setAVPlayerCallback() {
34    // seek操作结果回调函数
35    this.avPlayer.on('seekDone', (seekDoneTime) => {
36      Logger.info(TAG, `AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
37    })
38    // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程
39    this.avPlayer.on('error', (err) => {
40      Logger.info(TAG, `Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
41      this.avPlayer.reset(); // 调用reset重置资源,触发idle状态
42    })
43    // 状态机变化回调函数
44    this.avPlayer.on('stateChange', async (state, reason) => {
45      switch (state) {
46        case 'idle': // 成功调用reset接口后触发该状态机上报
47          Logger.info(TAG, 'AVPlayer state idle called.');
48          this.avPlayer.release(); // 调用release接口销毁实例对象
49          break;
50        case 'initialized': // avplayer 设置播放源后触发该状态上报
51          Logger.info(TAG, 'AVPlayerstate initialized called.');
52          if (this.surfaceID) {
53            this.avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置
54          }
55          this.avPlayer.prepare().then(() => {
56            Logger.info(TAG, 'AVPlayer prepare succeeded.');
57          }, (err) => {
58            Logger.info(TAG, `Invoke prepare failed, code is ${err.code}, message is ${err.message}`);
59          });
60          break;
61        case 'prepared': // prepare调用成功后上报该状态机
62          Logger.info(TAG, 'AVPlayer state prepared called.');
63          this.avPlayer.play(); // 调用播放接口开始播放
64          break;
65        case 'playing': // play成功调用后触发该状态机上报
66          Logger.info(TAG, 'AVPlayer state playing called.');
67          if (this.count !== 0) {
68            if (this.isSeek) {
69              Logger.info(TAG, 'AVPlayer start to seek.');
70            } else {
71              // 当播放模式不支持seek操作时继续播放到结尾
72              Logger.info(TAG, 'AVPlayer wait to play end.');
73            }
74          } else {
75            this.avPlayer.pause(); // 调用暂停接口暂停播放
76          }
77          this.count++;
78          break;
79        case 'paused': // pause成功调用后触发该状态机上报
80          Logger.info(TAG, 'AVPlayer state paused called.');
81          this.avPlayer.loop = true;
82          break;
83        case 'completed': // 播放结束后触发该状态机上报
84          Logger.info(TAG, 'AVPlayer state completed called.');
85          this.avPlayer.play(); // 再次播放接口开始播放
86          break;
87        case 'stopped': // stop接口成功调用后触发该状态机上报
88          Logger.info(TAG, 'AVPlayer state stopped called.');
89          this.avPlayer.reset(); // 调用reset接口初始化avplayer状态
90          break;
91        case 'released':
92          Logger.info(TAG, 'AVPlayer state released called.');
93          break;
94        default:
95          Logger.info(TAG, 'AVPlayer state unknown called.');
96          break;
97      }
98    })
99  }
100
101  public play(){
102    if (this.avPlayer) {
103      this.avPlayer.play();
104    }
105  }
106  public paused(){
107    if (this.avPlayer) {
108      this.avPlayer.pause();
109    }
110  }
111
112  // 以下demo为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例
113  async avPlayerFdSrcDemo(avName: string, surfaceID?: string) {
114    if (surfaceID) {
115      this.surfaceID = surfaceID;
116    }
117    // 创建avPlayer实例对象
118    this.avPlayer = await media.createAVPlayer();
119    // 创建状态机变化回调函数
120    this.setAVPlayerCallback();
121    // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
122    // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
123    let context = this.context;
124    let fileDescriptor = await context.resourceManager.getRawFd(avName);
125    this.isSeek = false; // 支持seek操作
126    // 为fdSrc赋值触发initialized状态机上报
127    this.avPlayer.fdSrc = fileDescriptor;
128  }
129
130  // 以下demo为通过url设置网络地址来实现播放直播码流的demo
131  async avPlayerLiveDemo() {
132    // 创建avPlayer实例对象
133    this.avPlayer = await media.createAVPlayer();
134    // 创建状态机变化回调函数
135    this.setAVPlayerCallback();
136    this.isSeek = false; // 不支持seek操作
137    this.avPlayer.url = 'http://xxx.xxx.xxx.xxx:xx/xx/index.m3u8'; // 播放hls网络直播码流
138  }
139}
140