• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (C) 2023 Huawei Device 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*/
15
16import image from '@ohos.multimedia.image';
17import avSession from '@ohos.multimedia.avsession';
18import Log from '../common/Log';
19import MediaData from '../common/MediaData';
20import resourceManager from '@ohos.resourceManager';
21import WantAgent from '@ohos.app.ability.wantAgent';
22import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
23
24export class ProviderFeature {
25  private constants = new MediaData();
26  private session: avSession.AVSession = null;
27  private isPlayLink: SubscribedAbstractProperty<boolean> = null;
28  private currentPlayItemLink: SubscribedAbstractProperty<avSession.AVQueueItem> = null;
29  private currentAVMetadataLink: SubscribedAbstractProperty<avSession.AVMetadata> = null;
30  private currentImageLink: SubscribedAbstractProperty<PixelMap> = null;
31  private currentLyricLink: SubscribedAbstractProperty<string> = null;
32  private queueItems: Array<avSession.AVQueueItem> = [this.constants.queueItemFirst, this.constants.queueItemSecond, this.constants.queueItemThird];
33  private lyrics: Array<string> = this.constants.lyricsForDemo;
34  private currentLyricLine: number = 0;
35  private isSendLyrics: boolean = false;
36  private pixelMap: PixelMap = null;
37  private queueItemPixelMapArray: Array<PixelMap> = [];
38  private MetadataPixelMapArray: Array<PixelMap> = [];
39  private resourceManager: resourceManager.ResourceManager = globalThis.context.resourceManager;
40  private avMetadataList: Array<avSession.AVMetadata> = [this.constants.avMetadataFirst, this.constants.avMetadataSecond, this.constants.avMetadataThird];
41  private currentState: avSession.AVPlaybackState = {
42    state: avSession.PlaybackState.PLAYBACK_STATE_PAUSE
43  }
44  private constantsForControl: MediaData = new MediaData();
45
46  constructor() {
47    this.isPlayLink = AppStorage.SetAndLink('IsPlaying', false);
48    this.currentPlayItemLink = AppStorage.SetAndLink('CurrentPlayItem', undefined);
49    this.currentAVMetadataLink = AppStorage.SetAndLink('CurrentAVMetadata', undefined);
50    this.currentImageLink = AppStorage.SetAndLink('CurrentImage', undefined);
51    this.currentLyricLink = AppStorage.SetAndLink('CurrentLyric', 'No lyric');
52    this.currentImageLink.set(null);
53    this.currentAVMetadataLink.set(this.avMetadataList[0]);
54    this.Init();
55
56  }
57
58  async Init(): Promise<void> {
59    await this.prepareImageResources();
60    await this.prepareResourcesForController();
61    await this.InitFirstMusicState();
62    await this.startContinuousTask();
63  }
64
65  async startContinuousTask(): Promise<void> {
66    let wantAgentInfo = {
67      wants: [
68        {
69          bundleName: "com.samples.mediaprovider",
70          abilityName: "com.samples.mediaprovider.EntryAbility"
71        }
72      ],
73      operationType: WantAgent.OperationType.START_ABILITY,
74      requestCode: 0,
75      wantAgentFlags: [WantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
76    };
77    let want = await WantAgent.getWantAgent(wantAgentInfo);
78    await backgroundTaskManager.startBackgroundRunning(globalThis.context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, want);
79  }
80
81  async CreateAVSession(): Promise<boolean> {
82    this.handleLyrics();
83
84    Log.info(`Start create AVSession`)
85    let ret: boolean = true;
86    this.session = await avSession.createAVSession(globalThis.context, "AVSessionDemo", 'audio').catch((err) => {
87      Log.error(`Failed to create AVSession, error info: ${JSON.stringify(err)}`);
88      ret = false;
89      return null;
90    });
91    await this.session.activate().catch((err) => {
92      Log.error(`Failed to activate AVSession, error info: ${JSON.stringify(err)}`);
93      ret = false;
94    });
95    await this.session.setAVQueueItems(this.queueItems).catch((err) => {
96      Log.error(`Failed to set AVQueue items, error info: ${JSON.stringify(err)}`);
97      ret = false;
98    });
99    await this.session.setAVQueueTitle('Queue title').catch((err) => {
100      Log.error(`Failed to set AVQueue title, error info: ${JSON.stringify(err)}`);
101      ret = false;
102    });
103    return ret;
104  }
105
106  async InitFirstMusicState(): Promise<void> {
107    let that = this;
108    that.isPlayLink.set(false);
109    that.currentLyricLine = 0;
110    that.currentImageLink.set(that.MetadataPixelMapArray[0]);
111    that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PAUSE;
112    await that.session.setAVPlaybackState(that.currentState);
113
114    await that.setAVMetadataToController(0);
115    that.currentPlayItemLink.set(that.queueItems[0]);
116    that.currentAVMetadataLink.set(that.avMetadataList[0]);
117  }
118
119  async RegisterListener(): Promise<void> {
120    let that = this;
121    this.session.on('play', async () => {
122      console.info(`on play , do play task`);
123      let that = this;
124      that.isPlayLink.set(true);
125      that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PLAY;
126      await that.session.setAVPlaybackState(that.currentState);
127    });
128    this.session.on('pause', async () => {
129      console.info(`on pause , do pause task`);
130      that.isPlayLink.set(false);
131      that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PAUSE;
132      await that.session.setAVPlaybackState(that.currentState);
133    });
134    this.session.on('stop', async () => {
135      console.info(`on stop , do stop task`);
136      that.isPlayLink.set(false);
137      that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PAUSE;
138      await that.session.setAVPlaybackState(that.currentState);
139    });
140    this.session.on('playNext', async () => {
141      console.info(`on playNext , do playNext task`);
142      let nextId: number = that.currentPlayItemLink.get().itemId + 1;
143      nextId = that.queueItems.length > nextId ? nextId : nextId - that.queueItems.length;
144      await that.handleNewItem(nextId);
145    });
146    this.session.on('playPrevious', async () => {
147      console.info(`on playPrevious , do playPrevious task`);
148      let previousId: number = that.currentPlayItemLink.get().itemId - 1;
149      previousId = previousId < 0 ? previousId + that.queueItems.length : previousId;
150      await that.handleNewItem(previousId);
151    });
152    this.session.on('skipToQueueItem', async (itemId) => {
153      console.info(`on skipToQueueItem , do skip task`);
154      await that.handleNewItem(itemId);
155    });
156    this.session.on('commonCommand', (commandString, args) => {
157      console.info(`on commonCommand , command is ${commandString}, args are ${JSON.stringify(args)}`);
158      that.handleCommonCommand(commandString, args);
159    });
160  }
161
162  async play(): Promise<void> {
163    console.info(`Start do play task`);
164    let that = this;
165    that.isPlayLink.set(true);
166    that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PLAY;
167    await that.session.setAVPlaybackState(that.currentState);
168  }
169
170  async setAVMetadataToController(itemId): Promise<void> {
171    let that = this;
172    switch (itemId) {
173      case 0:
174        await that.session.setAVMetadata(that.constantsForControl.avMetadataList[0]);
175        break;
176      case 1:
177        await that.session.setAVMetadata(that.constantsForControl.avMetadataList[1]);
178        break;
179      case 2:
180        await that.session.setAVMetadata(that.constantsForControl.avMetadataList[2]);
181        break;
182    }
183  }
184
185  async pause(): Promise<void> {
186    console.info(`on pause , do pause task`);
187    let that = this;
188    that.isPlayLink.set(false);
189    that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PAUSE;
190    await that.session.setAVPlaybackState(that.currentState);
191  }
192
193  async previous(): Promise<void> {
194    console.info(`on playPrevious , do playPrevious task`);
195    let that = this;
196    let previousId: number = that.currentPlayItemLink.get().itemId - 1;
197    previousId = previousId < 0 ? previousId + that.queueItems.length : previousId;
198    await that.handleNewItem(previousId);
199  }
200
201  async next(): Promise<void> {
202    console.info(`on playNext , do playNext task`);
203    let that = this;
204    let nextId: number = that.currentPlayItemLink.get().itemId + 1;
205    nextId = that.queueItems.length > nextId ? nextId : nextId - that.queueItems.length;
206    await that.handleNewItem(nextId);
207  }
208
209  async handleNewItem(itemId): Promise<void> {
210    let that = this;
211    that.isPlayLink.set(true);
212    that.currentLyricLine = 0;
213    that.currentLyricLink.set(that.lyrics[that.currentLyricLine]);
214    that.currentImageLink.set(that.MetadataPixelMapArray[itemId]);
215    that.currentState.state = avSession.PlaybackState.PLAYBACK_STATE_PLAY;
216    await that.session.setAVPlaybackState(that.currentState);
217    await that.setAVMetadataToController(itemId);
218    that.currentPlayItemLink.set(that.queueItems[itemId]);
219    that.currentAVMetadataLink.set(that.avMetadataList[that.currentPlayItemLink.get().itemId]);
220  }
221
222  async handleCommonCommand(commandString, args): Promise<void> {
223    let that = this;
224    switch (commandString) {
225      case 'lyrics':
226        that.isSendLyrics = args.lyrics;
227        await that.session.setAVMetadata(that.constantsForControl.avMetadataList[that.currentPlayItemLink.get()
228          .itemId]);
229        await that.session.setExtras({ lyricsLineNumber: that.currentLyricLine });
230        await that.session.dispatchSessionEvent('lyrics', { lyrics: that.lyrics[that.currentLyricLine] });
231        break;
232      case 'updateQueueItems':
233        that.updateQueueItems();
234        break;
235      default:
236        Log.warn(`Unknow command, please check`);
237        break;
238    }
239  }
240
241  async handleLyrics(): Promise<void> {
242    let that = this;
243    that.currentLyricLink.set(that.lyrics[that.currentLyricLine]);
244    setInterval(async function () {
245      if (that.isPlayLink.get()) {
246        Log.info('Switch lyrics line for every 10s.' + that.isSendLyrics);
247        if (that.isSendLyrics) {
248          await that.session.setExtras({ lyricsLineNumber: that.currentLyricLine });
249          await that.session.dispatchSessionEvent('lyrics', { lyrics: that.lyrics[that.currentLyricLine] });
250        }
251        that.currentLyricLine++;
252        if (that.currentLyricLine > 20) {
253          that.next();
254          that.currentLyricLine = 0;
255        }
256      }
257      that.currentLyricLink.set(that.lyrics[that.currentLyricLine]);
258    }, 2000);
259  }
260
261  async updateQueueItems(): Promise<void> {
262    let that = this;
263    await that.session.setAVQueueItems(that.queueItems).catch((err) => {
264      Log.error(`Failed to set AVQueueItems, error info: ${JSON.stringify(err)}`);
265    });
266  }
267
268  async prepareImageResources(): Promise<void> {
269    let that = this;
270    that.queueItemPixelMapArray.push(await that.saveRawFileToPixelMap('first.png'));
271    that.queueItemPixelMapArray.push(await that.saveRawFileToPixelMap('second.png'));
272    that.queueItemPixelMapArray.push(await that.saveRawFileToPixelMap('third.png'));
273    that.MetadataPixelMapArray.push(await that.saveRawFileToPixelMap('first_with_background.png'));
274    that.MetadataPixelMapArray.push(await that.saveRawFileToPixelMap('second_with_background.png'));
275    that.MetadataPixelMapArray.push(await that.saveRawFileToPixelMap('third_with_background.png'));
276    for (let i = 0;i < that.queueItemPixelMapArray.length; i++) {
277      that.queueItems[i].description.mediaImage = that.queueItemPixelMapArray[i];
278      that.avMetadataList[i].mediaImage = that.MetadataPixelMapArray[i];
279    }
280    this.currentPlayItemLink.set(this.queueItems[0]);
281    that.currentImageLink.set(that.MetadataPixelMapArray[0]);
282    this.currentAVMetadataLink.set(this.avMetadataList[0]);
283  }
284
285  async saveRawFileToPixelMap(rawFilePath): Promise<image.PixelMap> {
286    let that = this;
287    let value: Uint8Array = await that.resourceManager.getRawFileContent(rawFilePath);
288    let imageBuffer: ArrayBuffer = value.buffer;
289    let imageSource: image.ImageSource = image.createImageSource(imageBuffer);
290    let imagePixel: image.PixelMap = await imageSource.createPixelMap({ desiredSize: { width: 900, height: 900 } });
291    return imagePixel;
292  }
293
294  async prepareResourcesForController(): Promise<void> {
295    let that = this;
296    that.constantsForControl.avMetadataList[0].mediaImage = await that.saveRawFileToPixelMap('first.png');
297    that.constantsForControl.avMetadataList[1].mediaImage = await that.saveRawFileToPixelMap('second.png');
298    that.constantsForControl.avMetadataList[2].mediaImage = await that.saveRawFileToPixelMap('third.png');
299  }
300}
301