1/* 2 * Copyright (c) 2021-2022 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 audio from '@ohos.multimedia.audio'; 17import { BusinessError } from 'basic'; 18import Log from '../../../../../../../../common/src/main/ets/default/Log'; 19import getSingleInstance, { getAudioManager 20} from '../../../../../../../../common/src/main/ets/default/SingleInstanceHelper'; 21import { AudioVolumeType, VolumeInfo } from '../common/Constants'; 22 23const TAG = 'VolumePanelModel'; 24 25export interface VolumeListener { 26 updateVolumeInfo(status: VolumeInfo): void; 27} 28 29export interface VolumeCallQueueItemData { 30 interfaceName: InterfaceName, 31 params: boolean | number[], 32 33 callbackFunction(err: BusinessError, data?: boolean | number): void; 34} 35 36enum InterfaceName { 37 isMute, 38 mute, 39 getVolume, 40 setVolume 41} 42 43export class VolumePanelService { 44 mIsStart = false; 45 mListeners = new Set<VolumeListener>(); 46 mAudioManager = getAudioManager(); 47 mInterfaceCallQueue: VolumeCallQueueItemData[] = [] ; 48 49 constructor() { 50 Log.showInfo(TAG, 'constructor'); 51 } 52 53 startService(): void { 54 if (this.mIsStart) { 55 return; 56 } 57 this.mIsStart = true; 58 Log.showInfo(TAG, 'startService'); 59 this.mAudioManager.on('volumeChange', this.onVolumeChange.bind(this)); 60 } 61 62 stopService(): void { 63 if (!this.mIsStart) { 64 return; 65 } 66 Log.showInfo(TAG, 'stopService'); 67 this.mIsStart = false; 68 } 69 70 registerListener(listener: VolumeListener): void { 71 let res = this.mListeners.add(listener); 72 Log.showInfo(TAG, `registser VolumeListener ${res}`); 73 } 74 75 unregisterListener(listener: VolumeListener): void { 76 let res = this.mListeners.delete(listener); 77 Log.showInfo(TAG, `unregistser VolumeListener ${res}`); 78 } 79 80 async onVolumeChange(data): Promise<void> { 81 Log.showInfo(TAG, 'onVolumeChange'); 82 let volumeType = this.formatAudioVolumeTypeFromInterface(data.volumeType); 83 this.isMute(volumeType, (volumeType2: AudioVolumeType, data2: boolean) => { 84 Log.showInfo(TAG, `onVolumeChange->isMute, volumeType2: ${volumeType2} data2: ${String(data2)}`); 85 let volumeInfo: VolumeInfo = { 86 volumeType: volumeType, 87 volume: data.volume, 88 isMute: data2, 89 updateUi: data.updateUi 90 }; 91 this.mListeners.forEach(listener => listener.updateVolumeInfo(volumeInfo)); 92 }); 93 } 94 95 isMute(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: boolean) => void): void { 96 Log.showInfo(TAG, `isMute, volumeType: ${volumeType}`); 97 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 98 this.addInterfaceCallQueue({ 99 interfaceName: InterfaceName.isMute, 100 params: [interfaceVolumeType], 101 callbackFunction: (err, data: boolean) => { 102 Log.showInfo(TAG, `isMute, err: ${err} data: ${JSON.stringify(data)}`); 103 if (err) { 104 return; 105 } 106 callback(volumeType, data); 107 } 108 }); 109 } 110 111 getVolumeInfo(volumeType: AudioVolumeType, callback?: (volumeInfo: VolumeInfo) => void): void { 112 Log.showInfo(TAG, `getVolumeInfo, volumeType: ${volumeType}`); 113 this.getVolume(volumeType, (volumeType: AudioVolumeType, data: number) => { 114 Log.showInfo(TAG, `getVolumeInfo->getVolume`); 115 this.isMute(volumeType, (volumeType2: AudioVolumeType, data2: boolean) => { 116 Log.showInfo(TAG, `getVolumeInfo->isMute`); 117 let volumeInfo: VolumeInfo = { 118 volumeType: volumeType, 119 volume: data, 120 isMute: data2, 121 updateUi: false 122 }; 123 this.mListeners.forEach(listener => listener.updateVolumeInfo(volumeInfo)); 124 if (callback) { 125 callback(volumeInfo); 126 } 127 }); 128 }); 129 } 130 131 isActive(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: boolean) => void): void { 132 Log.showInfo(TAG, `isActive, volumeType: ${volumeType}`); 133 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 134 this.mAudioManager.isActive(interfaceVolumeType, (err: BusinessError, data: boolean) => { 135 Log.showInfo(TAG, `isActive, err: ${err} data: ${JSON.stringify(data)}`); 136 if (err) { 137 return; 138 } 139 callback(volumeType, data); 140 }); 141 } 142 143 getVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 144 Log.showInfo(TAG, `getVolume, volumeType: ${volumeType}`); 145 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 146 this.addInterfaceCallQueue({ 147 interfaceName: InterfaceName.getVolume, 148 params: [interfaceVolumeType], 149 callbackFunction: (err: BusinessError, data: number) => { 150 Log.showInfo(TAG, `getVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 151 if (err) { 152 return; 153 } 154 callback(volumeType, data); 155 } 156 }); 157 } 158 159 getMaxVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 160 Log.showInfo(TAG, `getMaxVolume, volumeType: ${volumeType}`); 161 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 162 this.mAudioManager.getMaxVolume(interfaceVolumeType, (err: BusinessError, data: number) => { 163 Log.showInfo(TAG, `getMaxVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 164 if (err) { 165 return; 166 } 167 callback(volumeType, data); 168 }); 169 } 170 171 getMinVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 172 Log.showInfo(TAG, `getMinVolume, volumeType: ${volumeType}`); 173 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 174 this.mAudioManager.getMinVolume(interfaceVolumeType, (err: BusinessError, data: number) => { 175 Log.showInfo(TAG, `getMinVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 176 if (err) { 177 return; 178 } 179 callback(volumeType, data); 180 }); 181 } 182 183 setVolumeAndMute(volumeType: AudioVolumeType, volume: number, mute: boolean, callback?: () => void): void { 184 Log.showInfo(TAG, `setVolumeAndMute, volumeType: ${volumeType} volume: ${volume} mute: ${mute}`); 185 if (volume !== undefined && mute !== undefined) { 186 this.setVolume(volumeType, volume, () => { 187 Log.showInfo(TAG, `setVolume`); 188 this.setMute(volumeType, mute, callback); 189 }); 190 } else if (volume !== undefined) { 191 this.setVolume(volumeType, volume); 192 } else if (mute !== undefined) { 193 this.setMute(volumeType, mute, callback); 194 } 195 } 196 197 setVolume(volumeType: AudioVolumeType, volume: number, callback?: () => void): void { 198 Log.showInfo(TAG, `setVolume, volumeType: ${volumeType} volume: ${volume}`); 199 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 200 this.addInterfaceCallQueue({ 201 interfaceName: InterfaceName.setVolume, 202 params: [interfaceVolumeType, volume], 203 callbackFunction: (err: BusinessError) => { 204 Log.showInfo(TAG, `setVolume, callback err: ${err} `); 205 if (err) { 206 return; 207 } 208 if (callback) { 209 callback(); 210 } 211 } 212 }); 213 } 214 215 setMute(volumeType: AudioVolumeType, mute: boolean, callback?: () => void): void { 216 Log.showInfo(TAG, `setMute, volumeType: ${volumeType} mute: ${mute}`); 217 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 218 this.addInterfaceCallQueue({ 219 interfaceName: InterfaceName.mute, 220 params: [interfaceVolumeType, mute], 221 callbackFunction: (err: BusinessError) => { 222 Log.showInfo(TAG, `setMute, err: ${JSON.stringify(err)}`); 223 if (err) { 224 return; 225 } 226 this.getVolumeInfo(volumeType, (volumeInfo: VolumeInfo) => { 227 Log.showInfo(TAG, `setMute, volumeInfo: ${JSON.stringify(volumeInfo)}`); 228 if (callback) { 229 callback(); 230 } 231 }); 232 } 233 }); 234 } 235 236 formatAudioVolumeTypeFromInterface(audioVolumeType): AudioVolumeType { 237 let formatValue: AudioVolumeType; 238 if (audioVolumeType == audio.AudioVolumeType.VOICE_CALL) { 239 formatValue = AudioVolumeType.VOICE_CALL; 240 } else if (audioVolumeType == audio.AudioVolumeType.RINGTONE) { 241 formatValue = AudioVolumeType.RINGTONE; 242 } else if (audioVolumeType == audio.AudioVolumeType.MEDIA) { 243 formatValue = AudioVolumeType.MEDIA; 244 } else if (audioVolumeType == audio.AudioVolumeType.VOICE_ASSISTANT) { 245 formatValue = AudioVolumeType.VOICE_ASSISTANT; 246 } 247 return formatValue; 248 } 249 250 formatAudioVolumeTypeToInterface(audioVolumeType: AudioVolumeType) { 251 let formatValue; 252 if (audioVolumeType == AudioVolumeType.VOICE_CALL) { 253 formatValue = audio.AudioVolumeType.VOICE_CALL; 254 } else if (audioVolumeType == AudioVolumeType.RINGTONE) { 255 formatValue = audio.AudioVolumeType.RINGTONE; 256 } else if (audioVolumeType == AudioVolumeType.MEDIA) { 257 formatValue = audio.AudioVolumeType.MEDIA; 258 } else if (audioVolumeType == AudioVolumeType.VOICE_ASSISTANT) { 259 formatValue = audio.AudioVolumeType.VOICE_ASSISTANT; 260 } 261 return formatValue; 262 } 263 264 addInterfaceCallQueue(data: VolumeCallQueueItemData): void { 265 Log.showDebug(TAG, `addInterfaceCallQueue, interfaceName: ${data.interfaceName} params: ${JSON.stringify(data.params)}`); 266 this.mInterfaceCallQueue.push(data); 267 if (this.mInterfaceCallQueue.length == 1) { 268 this.execInterfaceCallQueueFirst(); 269 } 270 } 271 272 execInterfaceCallQueueFirst(): void { 273 Log.showInfo(TAG, `execInterfaceCallQueueFirst, ${this.mInterfaceCallQueue.length}`); 274 let queueData = this.mInterfaceCallQueue[0]; 275 if (queueData.interfaceName == InterfaceName.isMute) { 276 this.mAudioManager.isMute(queueData.params[0], (err: BusinessError, data: boolean) => { 277 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, isMute callback'); 278 this.execInterfaceCallQueueNext().then(() => { 279 }).catch((e) => { 280 }); 281 queueData.callbackFunction(err, data); 282 }); 283 } else if (queueData.interfaceName == InterfaceName.mute) { 284 this.mAudioManager.mute(queueData.params[0], queueData.params[1], (err: BusinessError) => { 285 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, mute callback'); 286 this.execInterfaceCallQueueNext().then(() => { 287 }).catch((e) => { 288 }); 289 queueData.callbackFunction(err); 290 }); 291 } else if (queueData.interfaceName == InterfaceName.getVolume) { 292 this.mAudioManager.getVolume(queueData.params[0], (err: BusinessError, data: number) => { 293 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, getVolume callback'); 294 this.execInterfaceCallQueueNext().then(() => { 295 }).catch((e) => { 296 }); 297 queueData.callbackFunction(err, data); 298 }); 299 } else if (queueData.interfaceName == InterfaceName.setVolume) { 300 this.mAudioManager.setVolume(queueData.params[0], queueData.params[1], (err: BusinessError) => { 301 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, setVolume callback'); 302 this.execInterfaceCallQueueNext().then(() => { 303 }).catch((e) => { 304 }); 305 queueData.callbackFunction(err); 306 }); 307 } 308 } 309 310 async execInterfaceCallQueueNext(): Promise<void> { 311 Log.showInfo(TAG, `execInterfaceCallQueueNext, ${this.mInterfaceCallQueue.length}`); 312 this.mInterfaceCallQueue.splice(0, 1); 313 if (this.mInterfaceCallQueue.length > 0) { 314 this.execInterfaceCallQueueFirst(); 315 } 316 } 317} 318 319let volumePanelService = getSingleInstance(VolumePanelService, TAG); 320 321export default volumePanelService;