1# Using the Call Device Switching Component 2<!--Kit: AVSession Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @ccfriend; @liao_qian--> 5<!--SE: @ccfriend--> 6<!--TSE: @chenmingxi1_huawei--> 7 8## Switching Call Output Devices 9 10The system no longer provides APIs for switching audio output devices. If you need to switch audio output devices within your application, implement the **AVCastPicker** component. For details about the component, see [@ohos.multimedia.avCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md) and [@ohos.multimedia.avCastPickerParam](../../reference/apis-avsession-kit/js-apis-avCastPickerParam.md). 11 12This topic describes how to integrate the **AVCastPicker** component to implement the switching of call output devices. 13 14Currently, the system provides the default style and custom style for the **AVCastPicker** component. 15- If the application chooses to display the default style, when the device switches, the system displays the default component style based on the currently selected device. 16- If the application opts for a custom style, it needs to refresh its defined style in response to device changes. 17 18### Implementing the Default Style 19 201. Create an AVSession of the voice_call type. The AVSession constructor provides **AVSessionType** to specify the session type, and **voice_call** indicates the call type. If no AVSession is created, an empty list is displayed. 21 22 ```ts 23 import { avSession } from '@kit.AVSessionKit'; 24 @Entry 25 @Component 26 struct Index { 27 @State message: string = 'hello world'; 28 29 build() { 30 Column() { 31 Text(this.message) 32 .onClick(()=>{ 33 let context = this.getUIContext().getHostContext() as Context; 34 // Create an AVSession of the voice_call type. 35 let session: AVSessionManager.AVSession = await AVSessionManager.createAVSession(context, 'voiptest', 'voice_call'); 36 }) 37 } 38 .width('100%') 39 .height('100%') 40 } 41 } 42 ``` 43 442. Create the **AVCastPicker** component on the call page that provides device switching. 45 46 ```ts 47 import { AVCastPicker } from '@kit.AVSessionKit'; 48 49 // Create the component and set its size. 50 build() { 51 Row() { 52 Column() { 53 AVCastPicker() 54 .size({ height:45, width:45 }) 55 } 56 } 57 } 58 ``` 59 603. Create an AudioRenderer of the VOICE_COMMUNICATION type and start playing. For details about the implementation, see [Developing Audio Call](../audio/audio-call-development.md). 61 62 ```ts 63 import { audio } from '@kit.AudioKit'; 64 import { BusinessError } from '@kit.BasicServicesKit'; 65 66 private audioRenderer: audio.AudioRenderer | undefined = undefined; 67 private audioStreamInfo: audio.AudioStreamInfo = { 68 // Set the parameters based on project requirements. The following parameters are for reference only. 69 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 70 channels: audio.AudioChannel.CHANNEL_2, // Channel. 71 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 72 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 73 } 74 private audioRendererInfo: audio.AudioRendererInfo = { 75 // Set the parameters related to the call scenario. 76 usage: audio.StreamUsage.STREAM_USAGE_VIDEO_COMMUNICATION, // Audio stream usage type: VoIP video call, speaker by default. 77 rendererFlags: 0 // AudioRenderer flag. The default value is 0. 78 } 79 private audioRendererOptions: audio.AudioRendererOptions = { 80 streamInfo: this.audioStreamInfo, 81 rendererInfo: this.audioRendererInfo 82 } 83 84 // Create an AudioRenderer instance, and set the events to listen for. 85 try { 86 this.audioRenderer = await audio.createAudioRenderer(this.audioRendererOptions); 87 } catch (err) { 88 console.error(`audioRender create : Error: ${JSON.stringify(err)}`); 89 } 90 91 this.audioRenderer?.start((err: BusinessError) => { 92 if (err) { 93 console.error(`audioRender start faild : Error: ${JSON.stringify(err)}`); 94 } else { 95 console.info('audioRender start success'); 96 } 97 }); 98 ``` 99 1004. (Optional) Subscribe to audio output device change events if you want to know the device change status. 101 102 ```ts 103 import { audio } from '@kit.AudioKit'; 104 105 let audioManager = audio.getAudioManager(); // Create an AudioManager instance. 106 let audioRoutingManager = audioManager.getRoutingManager(); // Call an API of AudioManager to create an AudioRoutingManager instance. 107 108 // (Optional) Listen for audio output device changes. 109 audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => { 110 console.info(`device change To : ${desc[0].deviceType}`); // Device type. 111 }); 112 ``` 113 1145. Destroy the AVSession when the call ends. 115 116 ```ts 117 // Destroy the AVSession created in step 1 when the call ends. 118 this.session?.destroy((err) => { 119 if (err) { 120 console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`); 121 } else { 122 console.info(`Destroy : SUCCESS `); 123 } 124 }); 125 ``` 126 127### Implementing a Custom Style 128 129You can customize a style by setting the **customPicker** parameter of the [CustomBuilder](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md) type. 130 131The procedure for implementing a custom style is similar to that for implementing the default style. You can create an AVSession and implement audio playback by referring to [Implementing the Default Style Implementation](#implementing-the-default-style). 132 133The differences are as follows: 134 1351. When creating a custom **AVCastPicker** component, you must add a custom parameter. (This step corresponds to step 2 in the default style implementation.) 136 137 ```ts 138 import { AVCastPicker } from '@kit.AVSessionKit'; 139 140 @State pickerImage:ResourceStr = $r('app.media.earpiece'); // Custom resources. 141 142 build() { 143 Row() { 144 Column() { 145 AVCastPicker( 146 { 147 customPicker: (): void => this.ImageBuilder() // Add a custom parameter. 148 } 149 ).size({ height: 45, width:45 }) 150 } 151 } 152 } 153 154 // Custom content. 155 @Builder 156 ImageBuilder(): void { 157 Image(this.pickerImage) 158 .size({ width: '100%', height: '100%' }) 159 .backgroundColor('#00000000') 160 .fillColor(Color.Black) 161 } 162 ``` 163 1642. If the application needs to change the custom style based on audio output device changes, the application must listen for device change events and refresh the custom style in real time. (This step corresponds to step 4 in the default style implementation.) 165 166 ```ts 167 import { audio } from '@kit.AudioKit'; 168 169 async observerDevices() { 170 let audioManager = audio.getAudioManager(); 171 let audioRoutingManager = audioManager.getRoutingManager(); 172 173 // When the AVCastPicker component is started for the first time, obtain the current device and refresh the content displayed. 174 this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo)); 175 176 // Listen for the switching of the audio output device and display different styles based on the device type. 177 audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => { 178 this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo)); 179 }); 180 } 181 182 // Refresh the custom resource pickerImage after the device is changed. 183 private changePickerShow(desc: audio.AudioDeviceDescriptors) { 184 if (desc[0].deviceType === 2) { 185 this.pickerImage = $r('app.media.sound'); 186 } else if (desc[0].deviceType === 7) { 187 this.pickerImage = $r('app.media.bluetooth'); 188 } else { 189 this.pickerImage = $r('app.media.earpiece'); 190 } 191 } 192 ``` 193 194## Switching Call Input Devices (for PCs and 2-in-1 Devices Only) 195 196The system no longer provides APIs for switching audio input devices. If you need to switch audio input devices within your application, implement the **AVInputCastPicker** component. For details about the component, see [@ohos.multimedia.avInputCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avinputcastpicker.md) and [@ohos.multimedia.avCastPickerParam](../../reference/apis-avsession-kit/js-apis-avCastPickerParam.md). 197 198This topic describes how to integrate the **AVInputCastPicker** component to implement the switching of call input devices. 199 200Currently, the system provides the default style and custom style for the **AVCastPicker** component. 201- If the application chooses to display the default style, when the device switches, the system displays the default component style based on the currently selected device. 202- If the application opts for a custom style, it needs to refresh its defined style in response to device changes. 203 204### Implementing the Default Style 205 2061. Create the **AVInputCastPicker** component on the call page that provides device switching. 207 208 ```ts 209 import { AVCastPickerState, AVInputCastPicker } from '@kit.AVSessionKit'; 210 211 // (Optional) Callback for the device list state change. 212 private onStateChange(state: AVCastPickerState) { 213 if (state == AVCastPickerState.STATE_APPEARING) { 214 console.info('The picker starts showing.'); 215 } else if (state == AVCastPickerState.STATE_DISAPPEARING) { 216 console.info('The picker finishes presenting.'); 217 } 218 } 219 220 // Create the component and set its size. 221 build() { 222 Row() { 223 Column() { 224 AVInputCastPicker( 225 { 226 onStateChange: this.onStateChange 227 } 228 ).size({ height:45, width:45 }) 229 } 230 } 231 } 232 ``` 233 2342. Implement the call feature. For details, see [Developing Audio Call](../audio/audio-call-development.md). 235 236### Implementing a Custom Style 237 238You can customize a style by setting the **customPicker** parameter of the [AVInputCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avinputcastpicker.md#avinputcastpicker). 239 2401. When creating a custom **AVInputCastPicker** component, you must add a custom parameter. 241 242 ```ts 243 import { AVCastPickerState, AVInputCastPicker } from '@kit.AVSessionKit'; 244 245 @State pickerImage: ResourceStr = $r('app.media.earpiece'); // Custom resources. 246 247 // (Optional) Callback for the device list state change. 248 private onStateChange(state: AVCastPickerState) { 249 if (state == AVCastPickerState.STATE_APPEARING) { 250 console.info('The picker starts showing.'); 251 } else if (state == AVCastPickerState.STATE_DISAPPEARING) { 252 console.info('The picker finishes presenting.'); 253 } 254 } 255 256 build() { 257 Row() { 258 Column() { 259 AVInputCastPicker( 260 { 261 customPicker: (): void => this.ImageBuilder(), // Add a custom parameter. 262 onStateChange: this.onStateChange 263 } 264 ).size({ height: 45, width:45 }) 265 } 266 } 267 } 268 269 // Custom content. 270 @Builder 271 ImageBuilder(): void { 272 Image(this.pickerImage) 273 .size({ width: '100%', height: '100%' }) 274 .backgroundColor('#00000000') 275 .fillColor(Color.Black) 276 } 277 ``` 278 2792. Implement the call feature. For details, see [Developing Audio Call](../audio/audio-call-development.md). 280