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 '@ohos.base'; 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.showDebug(TAG, `isActive, volumeType: ${volumeType}`); 133 134 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 135 this.mAudioManager.isActive(interfaceVolumeType, (err: BusinessError, data: boolean) => { 136 Log.showDebug(TAG, `isActive, err: ${err} data: ${JSON.stringify(data)}`); 137 if (err) { 138 return; 139 } 140 callback(volumeType, data); 141 }); 142 } 143 144 getVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 145 Log.showDebug(TAG, `getVolume, volumeType: ${volumeType}`); 146 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 147 this.addInterfaceCallQueue({ 148 interfaceName: InterfaceName.getVolume, 149 params: [interfaceVolumeType], 150 callbackFunction: (err: BusinessError, data: number) => { 151 Log.showDebug(TAG, `getVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 152 if (err) { 153 return; 154 } 155 callback(volumeType, data); 156 } 157 }); 158 } 159 160 getMaxVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 161 Log.showInfo(TAG, `getMaxVolume, volumeType: ${volumeType}`); 162 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 163 this.mAudioManager.getMaxVolume(interfaceVolumeType, (err: BusinessError, data: number) => { 164 Log.showInfo(TAG, `getMaxVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 165 if (err) { 166 return; 167 } 168 callback(volumeType, data); 169 }); 170 } 171 172 getMinVolume(volumeType: AudioVolumeType, callback: (volumeType: AudioVolumeType, data: number) => void): void { 173 Log.showInfo(TAG, `getMinVolume, volumeType: ${volumeType}`); 174 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 175 this.mAudioManager.getMinVolume(interfaceVolumeType, (err: BusinessError, data: number) => { 176 Log.showInfo(TAG, `getMinVolume, err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`); 177 if (err) { 178 return; 179 } 180 callback(volumeType, data); 181 }); 182 } 183 184 setVolumeAndMute(volumeType: AudioVolumeType, volume: number, mute: boolean, callback?: () => void): void { 185 Log.showInfo(TAG, `setVolumeAndMute, volumeType: ${volumeType} volume: ${volume} mute: ${mute}`); 186 if (volume !== undefined && mute !== undefined) { 187 this.setVolume(volumeType, volume, () => { 188 Log.showInfo(TAG, `setVolume`); 189 this.setMute(volumeType, mute, callback); 190 }); 191 } else if (volume !== undefined) { 192 this.setVolume(volumeType, volume); 193 } else if (mute !== undefined) { 194 this.setMute(volumeType, mute, callback); 195 } 196 } 197 198 setVolume(volumeType: AudioVolumeType, volume: number, callback?: () => void): void { 199 Log.showDebug(TAG, `setVolume, volumeType: ${volumeType} volume: ${volume}`); 200 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 201 this.addInterfaceCallQueue({ 202 interfaceName: InterfaceName.setVolume, 203 params: [interfaceVolumeType, volume], 204 callbackFunction: (err: BusinessError) => { 205 Log.showDebug(TAG, `setVolume, callback err: ${err} `); 206 if (err) { 207 return; 208 } 209 if (callback) { 210 callback(); 211 } 212 } 213 }); 214 } 215 216 setMute(volumeType: AudioVolumeType, mute: boolean, callback?: () => void): void { 217 Log.showDebug(TAG, `setMute, volumeType: ${volumeType} mute: ${mute}`); 218 let interfaceVolumeType = this.formatAudioVolumeTypeToInterface(volumeType); 219 this.addInterfaceCallQueue({ 220 interfaceName: InterfaceName.mute, 221 params: [interfaceVolumeType, mute], 222 callbackFunction: (err: BusinessError) => { 223 Log.showDebug(TAG, `setMute, err: ${JSON.stringify(err)}`); 224 if (err) { 225 return; 226 } 227 this.getVolumeInfo(volumeType, (volumeInfo: VolumeInfo) => { 228 Log.showDebug(TAG, `setMute, volumeInfo: ${JSON.stringify(volumeInfo)}`); 229 if (callback) { 230 callback(); 231 } 232 }); 233 } 234 }); 235 } 236 237 formatAudioVolumeTypeFromInterface(audioVolumeType): AudioVolumeType { 238 let formatValue: AudioVolumeType; 239 if (audioVolumeType == audio.AudioVolumeType.VOICE_CALL) { 240 formatValue = AudioVolumeType.VOICE_CALL; 241 } else if (audioVolumeType == audio.AudioVolumeType.RINGTONE) { 242 formatValue = AudioVolumeType.RINGTONE; 243 } else if (audioVolumeType == audio.AudioVolumeType.MEDIA) { 244 formatValue = AudioVolumeType.MEDIA; 245 } else if (audioVolumeType == audio.AudioVolumeType.VOICE_ASSISTANT) { 246 formatValue = AudioVolumeType.VOICE_ASSISTANT; 247 } 248 return formatValue; 249 } 250 251 formatAudioVolumeTypeToInterface(audioVolumeType: AudioVolumeType) { 252 let formatValue; 253 if (audioVolumeType == AudioVolumeType.VOICE_CALL) { 254 formatValue = audio.AudioVolumeType.VOICE_CALL; 255 } else if (audioVolumeType == AudioVolumeType.RINGTONE) { 256 formatValue = audio.AudioVolumeType.RINGTONE; 257 } else if (audioVolumeType == AudioVolumeType.MEDIA) { 258 formatValue = audio.AudioVolumeType.MEDIA; 259 } else if (audioVolumeType == AudioVolumeType.VOICE_ASSISTANT) { 260 formatValue = audio.AudioVolumeType.VOICE_ASSISTANT; 261 } 262 return formatValue; 263 } 264 265 addInterfaceCallQueue(data: VolumeCallQueueItemData): void { 266 Log.showDebug(TAG, `addInterfaceCallQueue, interfaceName: ${data.interfaceName} params: ${JSON.stringify(data.params)}`); 267 this.mInterfaceCallQueue.push(data); 268 if (this.mInterfaceCallQueue.length == 1) { 269 this.execInterfaceCallQueueFirst(); 270 } 271 } 272 273 execInterfaceCallQueueFirst(): void { 274 Log.showInfo(TAG, `execInterfaceCallQueueFirst, ${this.mInterfaceCallQueue.length}`); 275 let queueData = this.mInterfaceCallQueue[0]; 276 if (queueData.interfaceName == InterfaceName.isMute) { 277 this.mAudioManager.isMute(queueData.params[0], (err: BusinessError, data: boolean) => { 278 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, isMute callback'); 279 this.execInterfaceCallQueueNext().then(() => { 280 }).catch((e) => { 281 }); 282 queueData.callbackFunction(err, data); 283 }); 284 } else if (queueData.interfaceName == InterfaceName.mute) { 285 this.mAudioManager.mute(queueData.params[0], queueData.params[1], (err: BusinessError) => { 286 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, mute callback'); 287 this.execInterfaceCallQueueNext().then(() => { 288 }).catch((e) => { 289 }); 290 queueData.callbackFunction(err); 291 }); 292 } else if (queueData.interfaceName == InterfaceName.getVolume) { 293 this.mAudioManager.getVolume(queueData.params[0], (err: BusinessError, data: number) => { 294 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, getVolume callback'); 295 this.execInterfaceCallQueueNext().then(() => { 296 }).catch((e) => { 297 }); 298 queueData.callbackFunction(err, data); 299 }); 300 } else if (queueData.interfaceName == InterfaceName.setVolume) { 301 this.mAudioManager.setVolume(queueData.params[0], queueData.params[1], (err: BusinessError) => { 302 Log.showInfo(TAG, 'execInterfaceCallQueueFirst, setVolume callback'); 303 this.execInterfaceCallQueueNext().then(() => { 304 }).catch((e) => { 305 }); 306 queueData.callbackFunction(err); 307 }); 308 } 309 } 310 311 async execInterfaceCallQueueNext(): Promise<void> { 312 Log.showInfo(TAG, `execInterfaceCallQueueNext, ${this.mInterfaceCallQueue.length}`); 313 this.mInterfaceCallQueue.splice(0, 1); 314 if (this.mInterfaceCallQueue.length > 0) { 315 this.execInterfaceCallQueueFirst(); 316 } 317 } 318} 319 320let volumePanelService = getSingleInstance(VolumePanelService, TAG); 321 322export default volumePanelService;