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 AVSessionManager from '@ohos.multimedia.avsession'; 17import bundle from '@ohos.bundle'; 18import Log from '../common/Logger'; 19 20const TAG = "ControllerComponent"; 21 22export default class control { 23 private isPlaying: boolean = false; 24 private isLyric: boolean = false; 25 private bundleNameMap: Map<string, string> = new Map(); 26 private controllerMap: Map<string, AVSessionManager.AVSessionController> = new Map(); 27 private metaDataMap: Map<string, AVSessionManager.AVMetadata> = new Map(); 28 private playStateMap: Map<string, AVSessionManager.AVMetadata> = new Map(); 29 private queueTitleMap: Map<string, string> = new Map(); 30 private queueItemsMap: Map<string, Array<AVSessionManager.AVQueueItem>> = new Map(); 31 private lyricMap: Map<string, string> = new Map(); 32 private sessionArray: Array<string> = new Array(); 33 private isPlayingLink: SubscribedAbstractProperty<undefined | boolean> | undefined = undefined; 34 private isLyricLink: SubscribedAbstractProperty<undefined | boolean> | undefined = undefined; 35 private bundleNameMapLink: SubscribedAbstractProperty<undefined | Map<string, string>> | undefined = undefined; 36 private metaDataMapLink: SubscribedAbstractProperty<undefined | Map<string, AVSessionManager.AVMetadata>> | undefined = undefined; 37 private playStateMapLink: SubscribedAbstractProperty<undefined | Map<string, AVSessionManager.AVMetadata>> | undefined = undefined; 38 private queueTitleMapLink: SubscribedAbstractProperty<undefined | Map<string, string>> | undefined = undefined; 39 private queueItemsMapLink: SubscribedAbstractProperty<undefined | Map<string, AVSessionManager.AVQueueItem[]>> | undefined = undefined; 40 private lyricMapLink: SubscribedAbstractProperty<undefined | Map<string, string>> | undefined = undefined; 41 private sessionArrayLink: SubscribedAbstractProperty<undefined | string[]> | undefined = undefined; 42 43 constructor() { 44 Log.info(TAG, 'constructor'); 45 this.initLink(); 46 Log.info(TAG, 'constructor done'); 47 this.interval(); 48 } 49 50 async initLink(): Promise<void> { 51 Log.info(TAG, 'initLink'); 52 this.isPlayingLink = AppStorage.setAndLink<undefined | boolean>('isPlaying', undefined); 53 this.isLyricLink = AppStorage.setAndLink<undefined | boolean>('isLyric', undefined); 54 this.bundleNameMapLink = AppStorage.setAndLink<undefined | Map<string, string>>('bundleNameMap', undefined); 55 this.metaDataMapLink = AppStorage.setAndLink<undefined | Map<string, AVSessionManager.AVMetadata>>('metaDataMap', undefined); 56 this.playStateMapLink = AppStorage.setAndLink<undefined | Map<string, AVSessionManager.AVMetadata>>('playStateMap', undefined); 57 this.queueItemsMapLink = AppStorage.setAndLink<undefined | Map<string, AVSessionManager.AVQueueItem[]>>('queueItemsMap', undefined); 58 this.queueTitleMapLink = AppStorage.setAndLink<undefined | Map<string, string>>('queueTitleMap', undefined); 59 this.lyricMapLink = AppStorage.setAndLink<undefined | Map<string, string>>('lyricMap', undefined); 60 this.sessionArrayLink = AppStorage.setAndLink<undefined | string[]>('sessionArray', undefined); 61 Log.info(TAG, 'initLink done'); 62 } 63 64 async startControl(): Promise<void> { 65 Log.info(TAG, 'startControl'); 66 let sessionDesList: Array<AVSessionManager.AVSessionDescriptor> = await AVSessionManager.getAllSessionDescriptors(); 67 Log.info(TAG, 'session des length : ' + sessionDesList.length); 68 for (let i = 0; i < sessionDesList.length; i++) { 69 let descriptor: AVSessionManager.AVSessionDescriptor = sessionDesList[i]; 70 let sessionId: string = descriptor.sessionId; 71 Log.info(TAG, 'session des sessionId : ' + sessionId); 72 let controller: AVSessionManager.AVSessionController = await AVSessionManager.createController(sessionId); 73 await this.getBundleName(descriptor); 74 Log.info(TAG, 'getBundleName done : ' + sessionId); 75 await this.makeListener(controller); 76 Log.info(TAG, 'makeListener done : ' + sessionId); 77 await this.getMetaData(controller); 78 Log.info(TAG, 'makeListener done : ' + sessionId); 79 this.sessionArray[i] = sessionId; 80 this.controllerMap[sessionId] = controller; 81 } 82 let hisSessionDesList: Array<AVSessionManager.AVSessionDescriptor> = 83 await AVSessionManager.getHistoricalSessionDescriptors(); 84 Log.info(TAG, 'historical session des length : ' + hisSessionDesList.length); 85 for (let j = 0; j < hisSessionDesList.length; j++) { 86 let descriptor: AVSessionManager.AVSessionDescriptor = hisSessionDesList[j]; 87 let sessionId: string = descriptor.sessionId; 88 Log.info(TAG, 'historical session des sessionId : ' + sessionId); 89 if (this.sessionArray.indexOf(sessionId) >= 0) { 90 Log.info(TAG, 'historical session already exist quit : sessionId : ' + sessionId); 91 continue; 92 } 93 await this.getBundleName(descriptor); 94 this.sessionArray.push(sessionId); 95 this.metaDataMap[sessionId] = { 96 title: '未在播放', 97 artist: '', 98 assetId: '' 99 } 100 } 101 this.isPlayingLink!.set(this.isPlaying); 102 Log.info(TAG, 'session info done to link isPlaying'); 103 this.metaDataMapLink!.set(this.metaDataMap); 104 Log.info(TAG, 'session info done to link metaDataMap'); 105 this.playStateMapLink!.set(this.playStateMap); 106 Log.info(TAG, 'session info done to link playStateMap'); 107 this.queueItemsMapLink!.set(this.queueItemsMap); 108 Log.info(TAG, 'session info done to link queueItemsMap'); 109 this.queueTitleMapLink!.set(this.queueTitleMap); 110 Log.info(TAG, 'session info done to link queueTitleMap'); 111 this.bundleNameMapLink!.set(this.bundleNameMap); 112 Log.info(TAG, 'session info done to link bundleNameMap'); 113 this.lyricMapLink!.set(this.lyricMap); 114 Log.info(TAG, 'session info done to link lyricMap'); 115 this.sessionArrayLink!.set(this.sessionArray); 116 Log.info(TAG, 'session info done to link sessionArray'); 117 Log.info(TAG, 'startControl done '); 118 } 119 120 async getBundleName(descriptor: AVSessionManager.AVSessionDescriptor): Promise<void> { 121 Log.info(TAG, 'getBundleName sessionId : ' + descriptor.sessionId); 122 let bundleAppName: string = await bundle.getAbilityLabel(descriptor.elementName.bundleName, 123 descriptor.elementName.abilityName); 124 Log.info(TAG, 'getBundleName name : ' + bundleAppName); 125 this.bundleNameMap[descriptor.sessionId] = '来自 ' + bundleAppName; 126 Log.info(TAG, 'getBundleName name finished'); 127 } 128 129 async getMetaData(controller: AVSessionManager.AVSessionController): Promise<void> { 130 let that = this; 131 let sessionId: string = controller.sessionId; 132 let metadata: AVSessionManager.AVMetadata = await controller.getAVMetadata(); 133 that.metaDataMap[sessionId] = metadata; 134 Log.info(TAG, 'get metadata : ' + metadata.title + ' for session :' + sessionId); 135 let queueTitle: string = await controller.getAVQueueTitle(); 136 Log.info(TAG, 'get queue queueTitle : ' + queueTitle); 137 that.queueTitleMap[sessionId] = queueTitle; 138 let queueItems: Array<AVSessionManager.AVQueueItem> = await controller.getAVQueueItems(); 139 Log.info(TAG, 'get queue items : ' + queueItems.length); 140 that.queueItemsMap[sessionId] = queueItems; 141 let avPlayState: AVSessionManager.AVPlaybackState = await controller.getAVPlaybackState(); 142 let playState: AVSessionManager.PlaybackState | undefined = avPlayState.state; 143 that.playStateMap[sessionId] = playState; 144 that.isPlaying = (playState == AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY); 145 Log.info(TAG, 'get playState : ' + that.isPlaying); 146 } 147 148 async makeListener(controller: AVSessionManager.AVSessionController): Promise<void> { 149 let that = this; 150 let sessionId: string = controller.sessionId; 151 controller.on('metadataChange', 'all', (metadata: AVSessionManager.AVMetadata) => { 152 Log.info(TAG, 'get metadata: ' + metadata.title + ' for session :' + sessionId); 153 let dataMap: Map<string, AVSessionManager.AVMetadata> | undefined = that.metaDataMapLink?.get(); 154 that.metaDataMapLink?.set(null); 155 Log.info(TAG, 'get metadata check link first: ' + JSON.stringify(that.metaDataMapLink?.get())); 156 dataMap?.set(sessionId, metadata); 157 if (that.metaDataMapLink?.get() == null) { 158 Log.info(TAG, 'get metadata check link NULL'); 159 } else { 160 Log.info(TAG, 'get metadata check link second: ' + 161 JSON.stringify((that.metaDataMapLink?.get()?.get(sessionId)))); 162 } 163 if (dataMap) { 164 Log.info(TAG, 'get metadata check map: ' + JSON.stringify((dataMap))); 165 } else { 166 Log.info(TAG, 'get metadata check map NULL'); 167 } 168 169 that.metaDataMapLink?.set(dataMap); 170 if (that.metaDataMapLink?.get() == null) { 171 Log.info(TAG, 'get metadata check link NULL'); 172 } else { 173 Log.info(TAG, 'get metadata check link end: ' + 174 JSON.stringify((that.metaDataMapLink?.get()?.get(sessionId))?.title)); 175 } 176 }); 177 controller.on('playbackStateChange', 'all', async (playState: AVSessionManager.AVPlaybackState) => { 178 Log.info(TAG, 'get playbackState: ' + playState.state + ' for session:' + sessionId); 179 that.playStateMap[sessionId] = playState.state; 180 that.isPlaying = (playState.state == AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY); 181 that.isPlayingLink!.set(that.isPlaying); 182 that.playStateMapLink!.set(that.playStateMap); 183 }); 184 controller.on('queueItemsChange', (items: Array<AVSessionManager.AVQueueItem>) => { 185 Log.info(TAG, 'get queueItems: ' + items.length + ' for session :' + sessionId); 186 that.queueItemsMap[sessionId] = items; 187 that.queueItemsMapLink!.set(that.queueItemsMap); 188 }); 189 controller.on('queueTitleChange', (title: string) => { 190 Log.info(TAG, 'get queueTitle : ' + title + ' for session :' + sessionId); 191 that.queueTitleMap[sessionId] = title; 192 that.queueTitleMapLink!.set(that.queueTitleMap); 193 }); 194 controller.on('sessionEvent', async (sessionEvent: string, args) => { 195 let lyricStruct = await controller.getExtras(); 196 let lyricLineNum: number = Number(lyricStruct.lyricsLineNumber); 197 that.lyricMap[sessionId] = String(lyricLineNum + ' : ' + args!.lyrics); 198 that.lyricMapLink!.set(that.lyricMap); 199 }); 200 } 201 202 async play(sessionId: string): Promise<void> { 203 let command: AVSessionManager.AVControlCommand = { 204 command: 'play', 205 parameter: undefined 206 } 207 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 208 await controller.sendControlCommand(command); 209 } 210 211 async pause(sessionId: string): Promise<void> { 212 let command: AVSessionManager.AVControlCommand = { 213 command: 'pause', 214 parameter: undefined 215 } 216 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 217 await controller.sendControlCommand(command); 218 } 219 220 async next(sessionId: string): Promise<void> { 221 let command: AVSessionManager.AVControlCommand = { 222 command: 'playNext', 223 parameter: undefined 224 } 225 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 226 await controller.sendControlCommand(command); 227 } 228 229 async previous(sessionId: string): Promise<void> { 230 let command: AVSessionManager.AVControlCommand = { 231 command: 'playPrevious', 232 parameter: undefined 233 } 234 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 235 await controller.sendControlCommand(command); 236 } 237 238 async skip(sessionId: string, itemId: number): Promise<void> { 239 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 240 Log.info(TAG, 'on skip to : ' + controller + ' | ' + itemId) 241 await controller.skipToQueueItem(itemId); 242 } 243 244 async getLyric(sessionId: string): Promise<void> { 245 let controller: AVSessionManager.AVSessionController = this.controllerMap[sessionId]; 246 this.isLyric = !this.isLyric; 247 this.isLyricLink!.set(this.isLyric); 248 await controller.sendCommonCommand('lyrics', { 249 'lyrics': this.isLyric 250 }); 251 } 252 253 async interval(): Promise<void> { 254 setInterval(async () => { 255 await this.controllerMap[this.sessionArray[0]].sendCommonCommand('lyrics', { 256 'lyrics': this.isLyric 257 }); 258 }, 1000) 259 } 260}