• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用通话设备切换组件
2<!--Kit: AVSession Kit-->
3<!--Subsystem: Multimedia-->
4<!--Owner: @ccfriend; @liao_qian-->
5<!--Designer: @ccfriend-->
6<!--Tester: @chenmingxi1_huawei-->
7<!--Adviser: @zengyawen-->
8
9## 切换通话输出设备
10
11系统不再提供音频输出设备切换的API,如果需要应用内切换音频输出设备,请实现AVCastPicker组件,相关参数可参考[@ohos.multimedia.avCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md) 和 [@ohos.multimedia.avCastPickerParam](../../reference/apis-avsession-kit/js-apis-avCastPickerParam.md)。
12
13本文将主要介绍AVCastPicker组件接入,实现通话输出设备切换功能。
14
15当前系统支持两种组件样式的显示方式:默认样式显示和自定义样式显示。
16- 如果应用选择显示默认样式,当设备切换时,系统将根据当前选择的设备显示系统默认的组件样式。
17- 如果应用选择显示自定义样式,那么需要应用根据设备的变化刷新自己定义的样式。
18
19### 默认样式实现
20
211. 创建voice_call类型的AVSession,AVSession在构造方法中支持不同的类型参数,由AVSessionType定义,voice_call表示通话类型,如果不创建,将显示空列表。
22
23   ```ts
24    import { avSession } from '@kit.AVSessionKit';
25    @Entry
26    @Component
27    struct Index {
28      @State message: string = 'hello world';
29
30      build() {
31        Column() {
32            Text(this.message)
33              .onClick(async ()=> {
34                try {
35                  let context = this.getUIContext().getHostContext() as Context;
36                // 通话开始时创建voice_call类型的avsession。
37                let session: AVSessionManager.AVSession = await AVSessionManager.createAVSession(context, 'voiptest', 'voice_call');
38                } catch (err) {
39                  console.error(`avsession create :  Error: ${JSON.stringify(err)}`);
40                }
41              })
42          }
43        .width('100%')
44        .height('100%')
45      }
46    }
47   ```
48
492. 在需要切换设备的通话界面创建AVCastPicker组件。
50
51   ```ts
52   import { AVCastPicker } from '@kit.AVSessionKit';
53
54   // 创建组件,并设置大小。
55   build() {
56     Row() {
57       Column() {
58         AVCastPicker()
59           .size({ height:45, width:45 })
60       }
61     }
62   }
63   ```
64
653. 创建VOICE_COMMUNICATION类型的AudioRenderer,并开始播放。具体通话音频播放等实现,请参考[AudioKit开发音频通话功能](../audio/audio-call-development.md)。
66
67   ```ts
68   import { audio } from '@kit.AudioKit';
69   import { BusinessError } from '@kit.BasicServicesKit';
70
71   private audioRenderer: audio.AudioRenderer | undefined = undefined;
72   private audioStreamInfo: audio.AudioStreamInfo = {
73     // 请按照实际场景设置,当前参数仅参考。
74     samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率。
75     channels: audio.AudioChannel.CHANNEL_2, // 通道。
76     sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
77     encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
78   }
79   private audioRendererInfo: audio.AudioRendererInfo = {
80     // 需使用通话场景相应的参数。
81     usage: audio.StreamUsage.STREAM_USAGE_VIDEO_COMMUNICATION, // 音频流使用类型:VOIP视频通话,默认为扬声器。
82     rendererFlags: 0 // 音频渲染器标志:默认为0即可。
83   }
84   private audioRendererOptions: audio.AudioRendererOptions = {
85     streamInfo: this.audioStreamInfo,
86     rendererInfo: this.audioRendererInfo
87   }
88
89   // 初始化,创建通话audiorenderer实例,设置监听事件。
90   try {
91    this.audioRenderer = await audio.createAudioRenderer(this.audioRendererOptions);
92   } catch (err) {
93    console.error(`audioRender create :  Error: ${JSON.stringify(err)}`);
94   }
95
96   this.audioRenderer?.start((err: BusinessError) => {
97    if (err) {
98      console.error(`audioRenderer start failed -Code : ${err.code}, Message ${err.message}`);
99    } else {
100      console.info('audioRender start success');
101    }
102   });
103   ```
104
1054. (可选)如果应用想知道设备切换情况,可以监听当前发声设备切换回调。
106
107   ```ts
108   import { audio } from '@kit.AudioKit';
109
110   let audioManager = audio.getAudioManager(); // 先创建audiomanager。
111   let audioRoutingManager = audioManager.getRoutingManager(); // 再调用AudioManager的方法创建AudioRoutingManager实例。
112
113   // 可选监听当前发声设备切换回调。
114   audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
115     console.info(`device change To : ${desc[0].deviceType}`); // 设备类型。
116   });
117   ```
118
1195. 通话结束后,销毁会话。
120
121   ```ts
122   // 通话结束销毁第一步创建的session。
123   this.session?.destroy((err) => {
124     if (err) {
125       console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
126     } else {
127       console.info(`Destroy : SUCCESS `);
128     }
129   });
130   ```
131
132### 自定义样式实现
133
134自定义样式通过设置[CustomBuilder](../../reference/apis-arkui/arkui-ts/ts-types.md#custombuilder8)类型的参数[customPicker](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md#avcastpicker)实现。
135
136实现自定义样式的步骤与实现默认样式基本相同,开发者可参考[默认样式实现](#默认样式实现),完成创建AVSession、实现音频播放等步骤。
137
138存在差异的步骤如下所示。
139
1401. 创建自定义AVCastPicker,需要新增自定义参数。(对应默认样式实现步骤2)
141
142   ```ts
143   import { AVCastPicker } from '@kit.AVSessionKit';
144
145   @State pickerImage:ResourceStr = $r('app.media.earpiece'); // 自定义资源。
146
147   build() {
148     Row() {
149       Column() {
150         AVCastPicker(
151           {
152             customPicker: (): void => this.ImageBuilder() // 新增自定义参数。
153           }
154         ).size({ height: 45, width:45 })
155       }
156     }
157   }
158
159   // 自定义内容。
160   @Builder
161   ImageBuilder(): void {
162     Image(this.pickerImage)
163       .size({ width: '100%', height: '100%' })
164       .backgroundColor('#00000000')
165       .fillColor(Color.Black)
166   }
167   ```
168
1692. 如果应用要根据出声设备变化而改变自定义样式,必须监听设备切换,然后实时刷新自定义样式。(对应默认样式实现步骤4)
170
171   ```ts
172   import { audio } from '@kit.AudioKit';
173
174   async observerDevices() {
175     let audioManager = audio.getAudioManager();
176     let audioRoutingManager = audioManager.getRoutingManager();
177
178     // 初次拉起AVCastPicker时需获取当前设备,刷新显示。
179     this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
180
181     // 监听当前发声设备切换,及时根据不同设备类型显示不同的样式。
182     audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
183       this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
184     });
185   }
186
187   // 设备更新后刷新自定义资源pickerImage。
188   private changePickerShow(desc: audio.AudioDeviceDescriptors) {
189     if(!desc || !desc.length || !desc[0]) {
190      return;
191     }
192     if (desc[0].deviceType === 2) {
193       this.pickerImage = $r('app.media.sound');
194     } else if (desc[0].deviceType === 7) {
195       this.pickerImage = $r('app.media.bluetooth');
196     } else {
197       this.pickerImage = $r('app.media.earpiece');
198     }
199   }
200   ```
201
202## 切换通话输入设备(仅在PC/2in设备可用)
203
204系统不再提供音频输入设备切换的API,如果需要在应用内切换音频输入设备,并实现AVInputCastPicker组件,相关参数可参考[@ohos.multimedia.avInputCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avinputcastpicker.md) 和 [@ohos.multimedia.avCastPickerParam](../../reference/apis-avsession-kit/js-apis-avCastPickerParam.md)。
205
206本文将主要介绍AVInputCastPicker组件接入,实现通话输入设备切换功能。
207
208当前系统支持两种组件样式的显示方式:默认样式显示和自定义样式显示。
209- 如果应用选择显示默认样式,当设备切换时,系统将根据当前选择的设备显示系统默认的组件样式。
210- 如果应用选择显示自定义样式,那么需要应用根据设备的变化刷新自己定义的样式。
211
212### 默认实现方式
213
2141. 在需要切换设备的通话界面创建AVInputCastPicker组件。
215
216   ```ts
217   import { AVCastPickerState, AVInputCastPicker } from '@kit.AVSessionKit';
218
219   // 设备列表显示状态变化回调(可选)。
220   private onStateChange(state: AVCastPickerState) {
221     if (state === AVCastPickerState.STATE_APPEARING) {
222       console.info('The picker starts showing.');
223     } else if (state === AVCastPickerState.STATE_DISAPPEARING) {
224       console.info('The picker finishes presenting.');
225     }
226   }
227
228   // 创建组件,并设置大小。
229   build() {
230     Row() {
231       Column() {
232         AVInputCastPicker(
233         {
234           onStateChange: this.onStateChange
235         }
236         ).size({ height:45, width:45 })
237       }
238     }
239   }
240   ```
241
2422. 实现通话功能,请参考[AudioKit开发音频通话功能](../audio/audio-call-development.md)。
243
244### 自定义实现方式
245
246自定义样式通过设置[AVInputCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avinputcastpicker.md#avinputcastpicker)中的参数customPicker实现。
247
2481. 创建自定义AVInputCastPicker,需要新增自定义参数。
249
250   ```ts
251   import { AVCastPickerState, AVInputCastPicker } from '@kit.AVSessionKit';
252
253   @State pickerImage: ResourceStr = $r('app.media.earpiece'); // 自定义资源。
254
255   // 设备列表显示状态变化回调(可选)。
256   private onStateChange(state: AVCastPickerState) {
257     if (state === AVCastPickerState.STATE_APPEARING) {
258       console.info('The picker starts showing.');
259     } else if (state === AVCastPickerState.STATE_DISAPPEARING) {
260       console.info('The picker finishes presenting.');
261     }
262   }
263
264   build() {
265     Row() {
266       Column() {
267         AVInputCastPicker(
268           {
269             customPicker: (): void => this.ImageBuilder(), // 新增自定义参数。
270             onStateChange: this.onStateChange
271           }
272         ).size({ height: 45, width:45 })
273       }
274     }
275   }
276
277   // 自定义内容。
278   @Builder
279   ImageBuilder(): void {
280     Image(this.pickerImage)
281       .size({ width: '100%', height: '100%' })
282       .backgroundColor('#00000000')
283       .fillColor(Color.Black)
284   }
285   ```
286
2872. 实现通话功能,请参考[AudioKit开发音频通话功能](../audio/audio-call-development.md)。