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