1e41f4b71Sopenharmony_ci# Using the Call Device Switching Component
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Basic Concepts
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciThe system no longer provides APIs for switching audio output devices. To switch an audio output device, you must 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).
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThis topic describes how to integrate the **AVCastPicker** component to implement the switching of call devices.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciCurrently, the system provides the default style and custom style for the **AVCastPicker** component. In the default style, the system displays the default component style based on the selected device during device switching. In the custom style, the application must refresh the style based on the device changes.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci## How to Develop
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ci### Implementing the Default Style
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci1. 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.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci   ```ts
18e41f4b71Sopenharmony_ci   import { avSession } from '@kit.AVSessionKit';
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci   private session: avSession.AVSession | undefined = undefined;
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci   // Create an AVSession of the voice_call type.
23e41f4b71Sopenharmony_ci   this.session = await avSession.createAVSession(getContext(this), 'voiptest', 'voice_call');
24e41f4b71Sopenharmony_ci   ```
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci2. Create the **AVCastPicker** component on the call page that provides device switching.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci   ```ts
29e41f4b71Sopenharmony_ci   import { AVCastPicker } from '@kit.AVSessionKit';
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci   // Create the component and set its size.
32e41f4b71Sopenharmony_ci   build() {
33e41f4b71Sopenharmony_ci     Row() {
34e41f4b71Sopenharmony_ci       Column() {
35e41f4b71Sopenharmony_ci         AVCastPicker()
36e41f4b71Sopenharmony_ci           .size({ height:45, width:45 })
37e41f4b71Sopenharmony_ci       }
38e41f4b71Sopenharmony_ci     }
39e41f4b71Sopenharmony_ci   }
40e41f4b71Sopenharmony_ci   ```
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci3. 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).
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ci   ```ts
45e41f4b71Sopenharmony_ci   import { audio } from '@kit.AudioKit';
46e41f4b71Sopenharmony_ci   import { BusinessError } from '@kit.BasicServicesKit';
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci   private audioRenderer: audio.AudioRenderer | undefined = undefined;
49e41f4b71Sopenharmony_ci   private audioStreamInfo: audio.AudioStreamInfo = {
50e41f4b71Sopenharmony_ci     // Set the parameters based on project requirements. The following parameters are for reference only.
51e41f4b71Sopenharmony_ci     samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate.
52e41f4b71Sopenharmony_ci     channels: audio.AudioChannel.CHANNEL_2, // Channel.
53e41f4b71Sopenharmony_ci     sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format.
54e41f4b71Sopenharmony_ci     encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format.
55e41f4b71Sopenharmony_ci   }
56e41f4b71Sopenharmony_ci   private audioRendererInfo: audio.AudioRendererInfo = {
57e41f4b71Sopenharmony_ci     // Set the parameters related to the call scenario.
58e41f4b71Sopenharmony_ci     usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, // Audio stream usage type: VoIP call.
59e41f4b71Sopenharmony_ci     rendererFlags: 0 // AudioRenderer flag. The default value is 0.
60e41f4b71Sopenharmony_ci   }
61e41f4b71Sopenharmony_ci   private audioRendererOptions: audio.AudioRendererOptions = {
62e41f4b71Sopenharmony_ci     streamInfo: this.audioStreamInfo,
63e41f4b71Sopenharmony_ci     rendererInfo: this.audioRendererInfo
64e41f4b71Sopenharmony_ci   }
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci   // Create an AudioRenderer instance, and set the events to listen for.
67e41f4b71Sopenharmony_ci   try {
68e41f4b71Sopenharmony_ci    this.audioRenderer = await audio.createAudioRenderer(this.audioRendererOptions);
69e41f4b71Sopenharmony_ci   } catch (err) {
70e41f4b71Sopenharmony_ci    console.error(`audioRender create :  Error: ${JSON.stringify(err)}`);
71e41f4b71Sopenharmony_ci   }
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci   this.audioRenderer?.start((err: BusinessError) => {
74e41f4b71Sopenharmony_ci    if (err) {
75e41f4b71Sopenharmony_ci      console.error(`audioRender start faild :  Error: ${JSON.stringify(err)}`);
76e41f4b71Sopenharmony_ci    } else {
77e41f4b71Sopenharmony_ci      console.error('audioRender start success');
78e41f4b71Sopenharmony_ci    }
79e41f4b71Sopenharmony_ci   });
80e41f4b71Sopenharmony_ci   ```
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci4. (Optional) Subscribe to audio output device change events if you want to know the device change status.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci   ```ts
85e41f4b71Sopenharmony_ci   import { audio } from '@kit.AudioKit';
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci   let audioManager = audio.getAudioManager(); // Create an AudioManager instance.
88e41f4b71Sopenharmony_ci   let audioRoutingManager = audioManager.getRoutingManager(); // Call an API of AudioManager to create an AudioRoutingManager instance.
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci   // (Optional) Listen for audio output device changes.
91e41f4b71Sopenharmony_ci   audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
92e41f4b71Sopenharmony_ci     console.info(`device change To : ${desc[0].deviceType}`); // Device type.
93e41f4b71Sopenharmony_ci   });
94e41f4b71Sopenharmony_ci   ```
95e41f4b71Sopenharmony_ci
96e41f4b71Sopenharmony_ci5. Destroy the AVSession when the call ends.
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ci   ```ts
99e41f4b71Sopenharmony_ci   // Destroy the AVSession created in step 1 when the call ends.
100e41f4b71Sopenharmony_ci   this.session?.destroy((err) => {
101e41f4b71Sopenharmony_ci     if (err) {
102e41f4b71Sopenharmony_ci       console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
103e41f4b71Sopenharmony_ci     } else {
104e41f4b71Sopenharmony_ci       console.info(`Destroy : SUCCESS `);
105e41f4b71Sopenharmony_ci     }
106e41f4b71Sopenharmony_ci   });
107e41f4b71Sopenharmony_ci   ```
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci### Implementing a Custom Style
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ciYou can customize a style by setting the **customPicker** parameter of the [CustomBuilder](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md) type.
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ciThe 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).
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ciThe differences are as follows:
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ci1. When creating a custom **AVCastPicker** component, you must add a custom parameter. (This step corresponds to step 2 in the default style implementation.)
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci   ```ts
120e41f4b71Sopenharmony_ci   import { AVCastPicker } from '@kit.AVSessionKit';
121e41f4b71Sopenharmony_ci
122e41f4b71Sopenharmony_ci   @State pickerImage:ResourceStr = $r('app.media.earpiece'); // Custom resources.
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci   build() {
125e41f4b71Sopenharmony_ci     Row() {
126e41f4b71Sopenharmony_ci       Column() {
127e41f4b71Sopenharmony_ci         AVCastPicker(
128e41f4b71Sopenharmony_ci           {
129e41f4b71Sopenharmony_ci             customPicker: (): void => this.ImageBuilder() // Add a custom parameter.
130e41f4b71Sopenharmony_ci           }
131e41f4b71Sopenharmony_ci         ).size({ height: 45, width:45 })
132e41f4b71Sopenharmony_ci       }
133e41f4b71Sopenharmony_ci     }
134e41f4b71Sopenharmony_ci   }
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci   // Custom content
137e41f4b71Sopenharmony_ci   @Builder
138e41f4b71Sopenharmony_ci   ImageBuilder(): void {
139e41f4b71Sopenharmony_ci     Image(this.pickerImage)
140e41f4b71Sopenharmony_ci       .size({ width: '100%', height: '100%' })
141e41f4b71Sopenharmony_ci       .backgroundColor('#00000000')
142e41f4b71Sopenharmony_ci       .fillColor(Color.Black)
143e41f4b71Sopenharmony_ci   }
144e41f4b71Sopenharmony_ci   ```
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci2. 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.)
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci   ```ts
149e41f4b71Sopenharmony_ci   import { audio } from '@kit.AudioKit';
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci   async observerDevices() {
152e41f4b71Sopenharmony_ci     let audioManager = audio.getAudioManager();
153e41f4b71Sopenharmony_ci     let audioRoutingManager = audioManager.getRoutingManager();
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci     // When the AVCastPicker component is started for the first time, obtain the current device and refresh the content displayed.
156e41f4b71Sopenharmony_ci     this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci     // Listen for the switching of the audio output device and display different styles based on the device type.
159e41f4b71Sopenharmony_ci     audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
160e41f4b71Sopenharmony_ci       this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
161e41f4b71Sopenharmony_ci     });
162e41f4b71Sopenharmony_ci   }
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci   // Refresh the custom resource pickerImage after the device is changed.
165e41f4b71Sopenharmony_ci   private changePickerShow(desc: audio.AudioDeviceDescriptors) {
166e41f4b71Sopenharmony_ci     if (desc[0].deviceType === 2) {
167e41f4b71Sopenharmony_ci       this.pickerImage = $r('app.media.sound');
168e41f4b71Sopenharmony_ci     } else if (desc[0].deviceType === 7) {
169e41f4b71Sopenharmony_ci       this.pickerImage = $r('app.media.bluetooth');
170e41f4b71Sopenharmony_ci     } else {
171e41f4b71Sopenharmony_ci       this.pickerImage = $r('app.media.earpiece');
172e41f4b71Sopenharmony_ci     }
173e41f4b71Sopenharmony_ci   }
174e41f4b71Sopenharmony_ci   ```
175