• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用通话设备切换组件
2
3## 基本概念
4
5系统不再提供音频输出设备切换的API,如果需要应用内切换音频输出设备,请实现AVCastPicker组件,相关参数可参考[@ohos.multimedia.avCastPicker](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md) 和 [@ohos.multimedia.avCastPickerParam](../../reference/apis-avsession-kit/js-apis-avCastPickerParam.md)。
6
7本文将主要介绍AVCastPicker组件接入,实现通话设备切换。
8
9当前系统支持两种组件样式的显示方式:默认样式显示和自定义样式显示。如果应用选择显示默认样式,当设备切换时,系统将根据当前选择的设备显示系统默认的组件样式;如果应用选择显示自定义样式,那么需要应用根据设备的变化刷新自己定义的样式。
10
11## 开发步骤
12
13### 默认样式实现
14
151. 创建voice_call类型的AVSession,AVSession在构造方法中支持不同的类型参数,由AVSessionType定义,voice_call表示通话类型,如果不创建,将显示空列表。
16
17   ```ts
18   import { avSession } from '@kit.AVSessionKit';
19   @Entry
20   @Component
21   struct Index {
22     @State message: string = 'hello world';
23
24     build() {
25       Column() {
26           Text(this.message)
27             .onClick(()=>{
28               let context = this.getUIContext().getHostContext() as Context;
29               // 通话开始时创建voice_call类型的avsession。
30               let session: AVSessionManager.AVSession = await AVSessionManager.createAVSession(context, 'voiptest', 'voice_call');
31             })
32         }
33       .width('100%')
34       .height('100%')
35     }
36   }
37   ```
38
392. 在需要切换设备的通话界面创建AVCastPicker组件。
40
41   ```ts
42   import { AVCastPicker } from '@kit.AVSessionKit';
43
44   // 创建组件,并设置大小。
45   build() {
46     Row() {
47       Column() {
48         AVCastPicker()
49           .size({ height:45, width:45 })
50       }
51     }
52   }
53   ```
54
553. 创建VOICE_COMMUNICATION类型的AudioRenderer,并开始播放。具体通话音频播放等实现,请参考[AudioKit开发音频通话功能](../audio/audio-call-development.md)。
56
57   ```ts
58   import { audio } from '@kit.AudioKit';
59   import { BusinessError } from '@kit.BasicServicesKit';
60
61   private audioRenderer: audio.AudioRenderer | undefined = undefined;
62   private audioStreamInfo: audio.AudioStreamInfo = {
63     // 请按照实际场景设置,当前参数仅参考。
64     samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率。
65     channels: audio.AudioChannel.CHANNEL_2, // 通道。
66     sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
67     encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
68   }
69   private audioRendererInfo: audio.AudioRendererInfo = {
70     // 需使用通话场景相应的参数。
71     usage: audio.StreamUsage.STREAM_USAGE_VIDEO_COMMUNICATION, // 音频流使用类型:VOIP视频通话,默认为扬声器。
72     rendererFlags: 0 // 音频渲染器标志:默认为0即可。
73   }
74   private audioRendererOptions: audio.AudioRendererOptions = {
75     streamInfo: this.audioStreamInfo,
76     rendererInfo: this.audioRendererInfo
77   }
78
79   // 初始化,创建通话audiorenderer实例,设置监听事件。
80   try {
81    this.audioRenderer = await audio.createAudioRenderer(this.audioRendererOptions);
82   } catch (err) {
83    console.error(`audioRender create :  Error: ${JSON.stringify(err)}`);
84   }
85
86   this.audioRenderer?.start((err: BusinessError) => {
87    if (err) {
88      console.error(`audioRender start faild :  Error: ${JSON.stringify(err)}`);
89    } else {
90      console.error('audioRender start success');
91    }
92   });
93   ```
94
954. (可选)如果应用想知道设备切换情况,可以监听当前发声设备切换回调。
96
97   ```ts
98   import { audio } from '@kit.AudioKit';
99
100   let audioManager = audio.getAudioManager(); // 先创建audiomanager。
101   let audioRoutingManager = audioManager.getRoutingManager(); // 再调用AudioManager的方法创建AudioRoutingManager实例。
102
103   // 可选监听当前发声设备切换回调。
104   audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
105     console.info(`device change To : ${desc[0].deviceType}`); // 设备类型。
106   });
107   ```
108
1095. 通话结束后,销毁会话。
110
111   ```ts
112   // 通话结束销毁第一步创建的session。
113   this.session?.destroy((err) => {
114     if (err) {
115       console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
116     } else {
117       console.info(`Destroy : SUCCESS `);
118     }
119   });
120   ```
121
122### 自定义样式实现
123
124自定义样式通过设置[CustomBuilder](../../reference/apis-avsession-kit/ohos-multimedia-avcastpicker.md)类型的参数customPicker实现。
125
126实现自定义样式的步骤与实现默认样式基本相同,开发者可参考[默认样式实现](#默认样式实现),完成创建AVSession、实现音频播放等步骤。
127
128存在差异的步骤如下所示。
129
1301. 创建自定义AVCastPicker,需要新增自定义参数。(对应默认样式实现步骤2)
131
132   ```ts
133   import { AVCastPicker } from '@kit.AVSessionKit';
134
135   @State pickerImage:ResourceStr = $r('app.media.earpiece'); // 自定义资源。
136
137   build() {
138     Row() {
139       Column() {
140         AVCastPicker(
141           {
142             customPicker: (): void => this.ImageBuilder() // 新增自定义参数。
143           }
144         ).size({ height: 45, width:45 })
145       }
146     }
147   }
148
149   // 自定义内容。
150   @Builder
151   ImageBuilder(): void {
152     Image(this.pickerImage)
153       .size({ width: '100%', height: '100%' })
154       .backgroundColor('#00000000')
155       .fillColor(Color.Black)
156   }
157   ```
158
1592. 如果应用要根据出声设备变化而改变自定义样式,必须监听设备切换,然后实时刷新自定义样式。(对应默认样式实现步骤4)
160
161   ```ts
162   import { audio } from '@kit.AudioKit';
163
164   async observerDevices() {
165     let audioManager = audio.getAudioManager();
166     let audioRoutingManager = audioManager.getRoutingManager();
167
168     // 初次拉起AVCastPicker时需获取当前设备,刷新显示。
169     this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
170
171     // 监听当前发声设备切换,及时根据不同设备类型显示不同的样式。
172     audioRoutingManager.on('preferOutputDeviceChangeForRendererInfo', this.audioRendererInfo, (desc: audio.AudioDeviceDescriptors) => {
173       this.changePickerShow(audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererInfo));
174     });
175   }
176
177   // 设备更新后刷新自定义资源pickerImage。
178   private changePickerShow(desc: audio.AudioDeviceDescriptors) {
179     if (desc[0].deviceType === 2) {
180       this.pickerImage = $r('app.media.sound');
181     } else if (desc[0].deviceType === 7) {
182       this.pickerImage = $r('app.media.bluetooth');
183     } else {
184       this.pickerImage = $r('app.media.earpiece');
185     }
186   }
187   ```
188
189<!--RP1-->
190<!--RP1End-->