• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 应用接入AVSession场景介绍
2
3音视频应用在实现音视频功能的同时,需要接入媒体会话即AVSession Kit,下文将提供一些典型的接入AVSession的展示和控制场景,方便开发者根据场景进行适配。
4
5对于不同的场景,将会在系统的播控中心看到不同的UI呈现。同时,在不同的场景下,应用的接入处理也需要遵循不同的规范约束。
6
7## 哪些场景下需要接入AVSession
8
9AVSession会对后台的音频播放、VOIP通话做约束,所以通常来说,长音频应用、听书类应用、长视频应用、VOIP类应用等都需要接入AVSession。当应用在没有创建接入AVSession的情况下进行了上述业务,那么系统会在检测到应用后台时,停止对应的音频播放,静音通话声音,以达到约束应用行为的目的。这种约束,应用上架前在本地就可以验证。
10
11对于其他使用到音频播放的应用,比如游戏,直播等场景,接入AVSession不是必选项,只是可选,取决于应用是否有后台播放的使用诉求。若应用需要后台播放,那么接入AVSession仍然是必须的,否则业务的正常功能会受到限制。
12
13当应用需要实现后台播放等功能时,需要使用[BackgroundTasks Kit](../../task-management/background-task-overview.md)(后台任务管理)的能力,申请对应的长时任务,避免进入挂起(Suspend)状态。
14
15## 接入流程
16
17应用接入AVSession流程分为如下几个步骤:
18
191. 确定应用需要创建的会话类型,[创建对应的会话](#创建不同类型的会话),不同类型决定了播控中心展示的控制模板样式。
202. 按需[创建后台任务](#创建后台任务)。
213. [设置必要的元数据(Metadata)](#设置元数据),以在播控中心展示响应的信息,包括不限于:当前媒体的ID(assetId),上一首媒体的ID(previousAssetId),下一首媒体的ID(nextAssetId),标题(title),专辑作者(author),专辑名称(album),词作者(writer),媒体时长(duration)等属性。
224. [设置播放相关的状态](#设置播放状态),包括不限于:当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体Id(activeItemId)、自定义媒体数据(extras)等属性。
235. 按需[注册不同的控制命令](#注册控制命令),包括不限于:播放/暂停、上下一首、快进快退、收藏、循环模式、进度条。
246. 应用退出或者无对应业务时,注销会话。
25
26## 创建不同类型的会话
27
28AVSession在构造方法中支持不同的类型参数,由 [AVSessionType](../../reference/apis-avsession-kit/js-apis-avsession.md#avsessiontype10) 定义,不同的类型代表了不同场景的控制能力,对于播控中心来说,会展示不同的控制模版。
29
30- audio类型,播控中心的控制样式为:收藏,上一首,播放/暂停,下一首,循环模式。
31
32- video类型,播控中心的控制样式为:快退,上一首,播放/暂停,下一首,快进。
33
34- voice_call类型,通话类型。
35
36使用代码示例:
37
38```ts
39import AVSessionManager from '@ohos.multimedia.avsession';
40
41// 开始创建并激活媒体会话
42// 创建session
43let context: Context = getContext(this);
44async function createSession() {
45let type: AVSessionManager.AVSessionType = 'audio';
46let session = await AVSessionManager.createAVSession(context,'SESSION_NAME', type);
47
48// 激活接口要在元数据、控制命令注册完成之后再执行
49await session.activate();
50  console.info(`session create done : sessionId : ${session.sessionId}`);
51}
52```
53
54## 创建后台任务
55
56当应用需要实现后台播放等功能时,需要使用[BackgroundTasks Kit](../../task-management/background-task-overview.md)(后台任务管理)的能力,申请对应的长时任务,避免进入挂起(Suspend)状态。
57
58对媒体类播放来说,需要申请[AUDIO_PLAYBACK BackgroundMode](../../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md#backgroundmode)的长时任务。
59
60## 设置元数据
61
62### 通用元数据
63
64应用可以通过setAVMetadata把会话的一些元数据信息设置给系统,从而在播控中心界面进行展示,包括不限制:当前媒体的ID(assetId),上一首媒体的ID(previousAssetId),下一首媒体的ID(nextAssetId),标题(title),专辑作者(author),专辑名称(album),词作者(writer),媒体时长(duration)等。
65
66```ts
67import AVSessionManager from '@ohos.multimedia.avsession';
68import { BusinessError } from '@ohos.base';
69
70let context: Context = getContext(this);
71async function setSessionInfo() {
72  // 假设已经创建了一个session,如何创建session可以参考之前的案例
73  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
74  // 设置必要的媒体信息
75  let metadata: AVSessionManager.AVMetadata = {
76    assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体
77    title: 'TITLE',
78    artist: 'ARTIST'
79  };
80  session.setAVMetadata(metadata).then(() => {
81    console.info(`SetAVMetadata successfully`);
82  }).catch((err: BusinessError) => {
83    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
84  });
85 }
86```
87
88### 歌词
89
90对于长音频来说,播控中心提供了歌词的展示页面,对于应用来说,接入也比较简单,只需要把歌词内容设置给系统。播控中心会解析歌词内容,并根据播放进度进行同步的刷新。
91
92```ts
93import AVSessionManager from '@ohos.multimedia.avsession';
94import { BusinessError } from '@ohos.base';
95
96let context: Context = getContext(this);
97async function setListener() {
98  // 假设已经创建了一个session,如何创建session可以参考之前的案例
99  let type: AVSessionManager.AVSessionType = 'audio';
100  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
101
102  // 把歌词信息设置给AVSession
103  let metadata: AVSessionManager.AVMetadata = {
104    assetId: '0',
105    lyric: 'http://www.test.lyric',
106  };
107   session.setAVMetadata(metadata).then(() => {
108    console.info(`SetAVMetadata successfully`);
109  }).catch((err: BusinessError) => {
110    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
111  });
112}
113```
114
115### 媒体资源金标
116
117对于长音频,播控中心提供了媒体资源金标的展示,媒体资源金标又可称为应用媒体音频音源的标识,目前暂时只支持展示AudioVivid标识。
118对于应用来说,接入只需要在AVMetadata中通知系统,当前播放音频的音源标识,播控就会同步展示。
119
120```ts
121import AVSessionManager from '@ohos.multimedia.avsession';
122import { BusinessError } from '@ohos.base';
123
124let context: Context = getContext(this);
125async function setListener() {
126  // 假设已经创建了一个session,如何创建session可以参考之前的案例
127  let type: AVSessionManager.AVSessionType = 'audio';
128  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
129
130  // 把媒体音源信息设置给AVSession
131  let metadata: AVSessionManager.AVMetadata = {
132    assetId: '0',
133    // 标识该媒体音源是AudioVivid
134    displayTags: AVSessionManager.DisplayTag.TAG_AUDIO_VIVID,
135  };
136  session.setAVMetadata(metadata).then(() => {
137    console.info(`SetAVMetadata successfully`);
138  }).catch((err: BusinessError) => {
139    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
140  });
141}
142```
143
144## 设置播放状态
145
146### 通用播放状态
147
148应用可以通过[setAVPlaybackState](../../reference/apis-avsession-kit/js-apis-avsession.md#setavplaybackstate10)。把当前的播放状态设置给系统,以在播控中心界面进行展示。
149播放状态一般是在资源播放后会进行变化的内容,包括:当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体Id(activeItemId)、自定义媒体数据(extras)等。
150
151```ts
152import AVSessionManager from '@ohos.multimedia.avsession';
153import { BusinessError } from '@ohos.base';
154
155let context: Context = getContext(this);
156async function setSessionInfo() {
157  // 假设已经创建了一个session,如何创建session可以参考之前的案例
158  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
159
160  // 播放器逻辑··· 引发媒体信息与播放状态的变更
161  // 简单设置一个播放状态 - 暂停 未收藏
162  let playbackState: AVSessionManager.AVPlaybackState = {
163    state:AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
164    isFavorite:false
165  };
166  session.setAVPlaybackState(playbackState, (err: BusinessError) => {
167    if (err) {
168      console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
169    } else {
170      console.info(`SetAVPlaybackState successfully`);
171    }
172  });
173}
174```
175
176### 进度条
177
178应用如果支持在播控中心展示进度,那么在媒体资源播放中,需要设置资源的时长、播放状态(暂停、播放)、播放位置、倍速,播控中心会使用这些信息进行进度的展示:
179
180```ts
181import AVSessionManager from '@ohos.multimedia.avsession';
182
183let context: Context = getContext(this);
184async function setListener() {
185  // 假设已经创建了一个session,如何创建session可以参考之前的案例
186  let type: AVSessionManager.AVSessionType = 'audio';
187  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
188
189  // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间,资源的时长
190  let playbackState: AVSessionManager.AVPlaybackState = {
191    state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态
192    position: {
193      elapsedTime: 1000, // 已经播放的位置,以ms为单位
194      updateTime: 30000, // 应用更新当前位置的时间戳,以ms为单位
195    },
196    speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验
197    bufferedTime: 14000, // 可选,资源缓存的时间,以ms为单位
198    duration: 23000, // 资源的时长,以ms为单位
199  };
200  session.setAVPlaybackState(playbackState, (err) => {
201    if (err) {
202      console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
203    } else {
204      console.info(`SetAVPlaybackState successfully`);
205    }
206  });
207}
208```
209
210系统的播控中心会根据应用设置的信息自行进行播放进度的计算,而不需要应用实时更新播放进度;
211但是应用需要如下状态发生变化的时候,更新AVPlaybackState,否则系统会发生计算错误:
212
213- state
214- position
215- speed
216
217关于进度条有一些特殊情况需要处理:
218
2191. 歌曲支持试听
220
221    如果VIP歌曲支持试听,这样应用就不需要设置完整的歌曲时长,则只需要设置歌曲的试听时长。
222    当应用仅设置歌曲的试听时长而不是完整时长,用户在播控中心触发进度控制时,应用收到的时长也是VIP试听时长内的相对时间戳位置,而不是完整歌曲的绝对时间戳位置,应用需要重新计算歌曲从零开始的绝对时间戳进行实际响应处理。
223
2242. 歌曲不支持试听
225
226    如果歌曲不支持试听,那么理论上应用内也不支持播放,这时可以把 duration 设置为 -1,以通知系统不显示实际的时长。
227
2283. 广告等内容的时长设置
229
230    对于有前贴广告、后贴广告的资源来说,建议这么处理:
231    - 播放广告时,单独设置广告的时长 duration
232    - 当进入到正片播放的时候,则重新设置一次新的时长,以与广告进行区分。
233
234## 注册控制命令
235
236应用接入AVSession,可以通过注册不同的控制命令来实现播控中心界面上的控制操作,即通过on接口注册不同的控制命令参数,即可实现对应的功能。
237具体的接口参考[接口注册](../../reference/apis-avsession-kit/js-apis-avsession.md#onplay10)。
238> **说明:**
239>
240> 创建AVSession后,请先注册应用支持的控制命令,再激活 Session
241
242媒体资源支持的控制命令列表:
243
244| 控制命令 | 功能说明   |
245| ------  | -------------------------|
246| play    | 播放命令。 |
247| pause    | 暂停命令。 |
248| stop    | 停止命令。 |
249| playNext    | 播放下一首命令。 |
250| playPrevious    | 播放上一首命令。 |
251| fastForward    | 快进命令。 |
252| rewind    | 快退命令。 |
253| playFromAssetId    | 根据某个资源id进行播放命令。 |
254| seek    | 跳转命令。 |
255| setSpeed    | 设置播放速率命令。 |
256| setLoopMode    | 设置循环模式命令。 |
257| toggleFavorite    | 设置是否收藏命令。 |
258| skipToQueueItem    | 设置播放列表其中某项被选中播放的命令。 |
259| handleKeyEvent    | 设置按键事件的命令。 |
260| commonCommand    | 设置自定义控制命令。 |
261
262通话类应用支持的控制:
263
264| 控制命令 | 功能说明   |
265| ------  | -------------------------|
266| answer    | 接听电话的命令。 |
267| hangUp    | 通话挂断的命令。 |
268| toggleCallMute    | 通话静音或解除静音的命令。 |
269
270### 不支持命令的处理
271
272系统支持的控制命令对于不支持的控制,比如应用不支持“上一首”的命令处理,只需要使用off 接口注销对应的控制命令,系统的播控中心会相应的对该控制界面进行置灰处理,以明确告知用户此控制命令不支持。
273
274```ts
275import AVSessionManager from '@ohos.multimedia.avsession';
276
277let context: Context = getContext(this);
278async function unregisterSessionListener() {
279  // 假设已经创建了一个session,如何创建session可以参考之前的案例
280  let type: AVSessionManager.AVSessionType = 'audio';
281  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
282
283  // 取消指定session下的相关监听
284  session.off('play');
285  session.off('pause');
286  session.off('stop');
287  session.off('playNext');
288  session.off('playPrevious');
289}
290```
291
292### 快进快退
293
294系统支持三种快进快退的时长,应用可以通过接口进行设置;同时注册快进快退的回调命令,以响应控制。
295
296```ts
297import AVSessionManager from '@ohos.multimedia.avsession';
298import { BusinessError } from '@ohos.base';
299
300let context: Context = getContext(this);
301async function unregisterSessionListener() {
302  // 假设已经创建了一个session,如何创建session可以参考之前的案例
303  let type: AVSessionManager.AVSessionType = 'audio';
304  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
305
306  // 设置支持的快进快退的时长设置给AVSession
307  let metadata: AVSessionManager.AVMetadata = {
308    assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体
309    skipIntervals: SkipIntervals.SECONDS_10,
310  };
311  session.setAVMetadata(metadata).then(() => {
312    console.info(`SetAVMetadata successfully`);
313  }).catch((err: BusinessError) => {
314    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
315  });
316
317  session.on('fastForward', (time ?: number) => {
318    console.info(`on fastForward , do fastForward task`);
319    // do some tasks ···
320  });
321  session.on('rewind', (time ?: number) => {
322    console.info(`on rewind , do rewind task`);
323    // do some tasks ···
324  });
325}
326```
327
328### 收藏
329
330音乐类应用实现收藏功能,那么需要注册收藏的控制响应[on('toggleFavorite')](../../reference/apis-avsession-kit/js-apis-avsession.md#ontogglefavorite10)。
331
332```ts
333import AVSessionManager from '@ohos.multimedia.avsession';
334import { BusinessError } from '@ohos.base';
335
336let context: Context = getContext(this);
337async function setListener() {
338  // 假设已经创建了一个session,如何创建session可以参考之前的案例
339  let type: AVSessionManager.AVSessionType = 'audio';
340  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
341  session.on('toggleFavorite', (assetId) => {
342    console.info(`on toggleFavorite `);
343    // 应用收到收藏命令,进行收藏处理
344
345    // 应用内完成或者取消收藏,把新的收藏状态设置给AVSession
346    let playbackState: AVSessionManager.AVPlaybackState = {
347      isFavorite:true,
348    };
349    session.setAVPlaybackState(playbackState).then(() => {
350      console.info(`SetAVPlaybackState successfully`);
351    }).catch((err: BusinessError) => {
352      console.info(`SetAVPlaybackState BusinessError: code: ${err.code}, message: ${err.message}`);
353    });
354  });
355}
356```
357
358### 循环模式
359
360针对音乐类应用,系统的播控中心界面会默认展示循环模式的控制操作,目前系统支持四种固定的循环模式控制,参考: [LoopMode](../../reference/apis-avsession-kit/js-apis-avsession.md#loopmode10)。
361
362播控中心支持固定的四种循环模式的切换,即: 随机播放、顺序播放、单曲循环、列表循环。播控中心会按照固定的切换顺序通知应用,应用收到对应的循环模式命令后进行响应。
363
364实现参考:
365
366```ts
367import AVSessionManager from '@ohos.multimedia.avsession';
368import { BusinessError } from '@ohos.base';
369
370let context: Context = getContext(this);
371async function setListener() {
372  // 假设已经创建了一个session,如何创建session可以参考之前的案例
373  let type: AVSessionManager.AVSessionType = 'audio';
374  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
375
376  // 应用启动时,需要把应用内的循环模式设置给AVSession
377  let playBackState: AVSessionManager.AVPlayBackState= {
378    loopMode: AVSessionManager.LoopMode.LOOP_MODE_SINGLE,
379  };
380  session.setAVPlayBackState(playBackState).then(() => {
381    console.info(`set AVPlayBackStatesuccessfully`);
382  }).catch((err: BusinessError) => {
383    console.error(`Failed to set AVPlayBackState. Code: ${err.code}, message: ${err.message}`);
384  });
385
386  // 应用注册循环模式的控制监听
387  session.on('setLoopMode', (mode) => {
388    console.info(`on setLoopMode ${mode}`);
389    // 应用收到设置循环模式后,切换对应的循环模式
390  });
391}
392```
393
394### 进度控制
395
396应用如果支持进度显示,进一步也可以支持进度控制。应用需要响应seek的控制命令,那么当用户在播控中心的界面上进行拖动操作时,应用就会收到对应的回调。参考实现:
397
398```ts
399import AVSessionManager from '@ohos.multimedia.avsession';
400
401let context: Context = getContext(this);
402async function setListener() {
403 // 假设已经创建了一个session,如何创建session可以参考之前的案例
404 let type: AVSessionManager.AVSessionType = 'audio';
405 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
406
407 session.on('seek', (time: number) => {
408   console.info(`on seek , the time is ${JSON.stringify(time)}`);
409
410   // 由于应用内seek可能会触发较长的缓冲等待,一般先把状态设置为 Buffering
411   let playbackState: AVSessionManager.AVPlaybackState = {
412     state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // 缓冲状态
413   };
414   session.setAVPlaybackState(playbackState, (err) => {
415     if (err) {
416       console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
417     } else {
418       console.info(`SetAVPlaybackState successfully`);
419     }
420   });
421
422   // 应用响应seek命令,使用应用内播放器完成seek实现
423
424   // 应用内更新新的位置后,也需要同步更新状态给系统
425   playbackState.state = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY; // 播放状态
426   playbackState.position = {
427     elapsedTime: 4000, // 已经播放的位置,以ms为单位
428     updateTime: 34000, // 应用更新当前位置的时间戳,以ms为单位
429   }
430   session.setAVPlaybackState(playbackState, (err) => {
431     if (err) {
432       console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
433     } else {
434       console.info(`SetAVPlaybackState successfully`);
435     }
436   });
437
438 });
439}
440```
441
442## 适配媒体通知
443
444当前系统不直接向应用提供主动发送媒体控制通知的接口,那么当应用进入播放状态时,系统会自动发送通知,同时在通知和锁屏界面进行展示。
445
446> **说明:**
447>
448> 1. 目前仅audio类型的媒体会话会在通知入口展示,video类型暂时不支持展示。
449> 2. 通知中心、锁屏下的播控卡片的展示,由系统进行发送,并控制相应的生命周期。