1e41f4b71Sopenharmony_ci# Developing Audio Call 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciDuring an audio call, audio output (playing the peer voice) and audio input (recording the local voice) are carried out simultaneously. You can use the AudioRenderer to implement audio output and the AudioCapturer to implement audio input. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciBefore starting or stopping using the audio call service, the application needs to check the [audio scene](audio-call-overview.md#audio-scene) and [ringer mode](audio-call-overview.md#ringer-mode) to adopt proper audio management and prompt policies. 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciThe sample code below demonstrates the basic process of using the AudioRenderer and AudioCapturer to implement the audio call service, without the process of call data transmission. In actual development, the peer call data transmitted over the network needs to be decoded and played, and the sample code uses the process of reading an audio file instead; the local call data needs to be encoded and packed and then sent to the peer over the network, and the sample code uses the process of writing an audio file instead. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci## Using AudioRenderer to Play the Peer Voice 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciThis process is similar to the process of [using AudioRenderer to develop audio playback](using-audiorenderer-for-playback.md). The key differences lie in the **audioRendererInfo** parameter and audio data source. In the **audioRendererInfo** parameter used for audio calling, **content** must be set to **CONTENT_TYPE_SPEECH**, and **usage** must be set to **STREAM_USAGE_VOICE_COMMUNICATION**. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci```ts 14e41f4b71Sopenharmony_ciimport { audio } from '@kit.AudioKit'; 15e41f4b71Sopenharmony_ciimport { fileIo } from '@kit.CoreFileKit'; 16e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ciconst TAG = 'VoiceCallDemoForAudioRenderer'; 19e41f4b71Sopenharmony_ci// The process is similar to the process of using AudioRenderer to develop audio playback. The key differences lie in the audioRendererInfo parameter and audio data source. 20e41f4b71Sopenharmony_ciclass Options { 21e41f4b71Sopenharmony_ci offset?: number; 22e41f4b71Sopenharmony_ci length?: number; 23e41f4b71Sopenharmony_ci} 24e41f4b71Sopenharmony_cilet context = getContext(this); 25e41f4b71Sopenharmony_cilet bufferSize: number = 0; 26e41f4b71Sopenharmony_cilet renderModel: audio.AudioRenderer | undefined = undefined; 27e41f4b71Sopenharmony_cilet audioStreamInfo: audio.AudioStreamInfo = { 28e41f4b71Sopenharmony_ci samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // Sampling rate. 29e41f4b71Sopenharmony_ci channels: audio.AudioChannel.CHANNEL_2, // Channel. 30e41f4b71Sopenharmony_ci sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 31e41f4b71Sopenharmony_ci encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 32e41f4b71Sopenharmony_ci} 33e41f4b71Sopenharmony_cilet audioRendererInfo: audio.AudioRendererInfo = { 34e41f4b71Sopenharmony_ci // Set the parameters related to the call scenario. 35e41f4b71Sopenharmony_ci usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, // Audio stream usage type: VoIP call. 36e41f4b71Sopenharmony_ci rendererFlags: 0 // AudioRenderer flag. The default value is 0. 37e41f4b71Sopenharmony_ci} 38e41f4b71Sopenharmony_cilet audioRendererOptions: audio.AudioRendererOptions = { 39e41f4b71Sopenharmony_ci streamInfo: audioStreamInfo, 40e41f4b71Sopenharmony_ci rendererInfo: audioRendererInfo 41e41f4b71Sopenharmony_ci} 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_cilet path = getContext().cacheDir; 44e41f4b71Sopenharmony_ci// Ensure that the resource exists in the sandbox path. 45e41f4b71Sopenharmony_cilet filePath = path + '/StarWars10s-2C-48000-4SW.wav'; 46e41f4b71Sopenharmony_cilet file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY); 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_cilet writeDataCallback = (buffer: ArrayBuffer) => { 49e41f4b71Sopenharmony_ci let options: Options = { 50e41f4b71Sopenharmony_ci offset: bufferSize, 51e41f4b71Sopenharmony_ci length: buffer.byteLength 52e41f4b71Sopenharmony_ci } 53e41f4b71Sopenharmony_ci fileIo.readSync(file.fd, buffer, options); 54e41f4b71Sopenharmony_ci bufferSize += buffer.byteLength; 55e41f4b71Sopenharmony_ci} 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci// Create an AudioRenderer instance, and set the events to listen for. 58e41f4b71Sopenharmony_ciaudio.createAudioRenderer(audioRendererOptions, (err: BusinessError, renderer: audio.AudioRenderer) => { // Create an AudioRenderer instance. 59e41f4b71Sopenharmony_ci if (!err) { 60e41f4b71Sopenharmony_ci console.info(`${TAG}: creating AudioRenderer success`); 61e41f4b71Sopenharmony_ci renderModel = renderer; 62e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 63e41f4b71Sopenharmony_ci renderModel.on('stateChange', (state: audio.AudioState) => { // Set the events to listen for. A callback is invoked when the AudioRenderer is switched to the specified state. 64e41f4b71Sopenharmony_ci if (state == 1) { 65e41f4b71Sopenharmony_ci console.info('audio renderer state is: STATE_PREPARED'); 66e41f4b71Sopenharmony_ci } 67e41f4b71Sopenharmony_ci if (state == 2) { 68e41f4b71Sopenharmony_ci console.info('audio renderer state is: STATE_RUNNING'); 69e41f4b71Sopenharmony_ci } 70e41f4b71Sopenharmony_ci }); 71e41f4b71Sopenharmony_ci renderModel.on('markReach', 1000, (position: number) => { // Subscribe to the markReach event. A callback is triggered when the number of rendered frames reaches 1000. 72e41f4b71Sopenharmony_ci if (position == 1000) { 73e41f4b71Sopenharmony_ci console.info('ON Triggered successfully'); 74e41f4b71Sopenharmony_ci } 75e41f4b71Sopenharmony_ci }); 76e41f4b71Sopenharmony_ci renderModel.on('writeData', writeDataCallback); 77e41f4b71Sopenharmony_ci } 78e41f4b71Sopenharmony_ci } else { 79e41f4b71Sopenharmony_ci console.info(`${TAG}: creating AudioRenderer failed, error: ${err.message}`); 80e41f4b71Sopenharmony_ci } 81e41f4b71Sopenharmony_ci}); 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci// Start audio rendering. 84e41f4b71Sopenharmony_ciasync function start() { 85e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 86e41f4b71Sopenharmony_ci let stateGroup: number[] = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 87e41f4b71Sopenharmony_ci if (stateGroup.indexOf(renderModel.state.valueOf()) === -1) { // Rendering can be started only when the AudioRenderer is in the STATE_PREPARED, STATE_PAUSED, or STATE_STOPPED state. 88e41f4b71Sopenharmony_ci console.error(TAG + 'start failed'); 89e41f4b71Sopenharmony_ci return; 90e41f4b71Sopenharmony_ci } 91e41f4b71Sopenharmony_ci renderModel.start((err: BusinessError) => { 92e41f4b71Sopenharmony_ci if (err) { 93e41f4b71Sopenharmony_ci console.error('Renderer start failed.'); 94e41f4b71Sopenharmony_ci } else { 95e41f4b71Sopenharmony_ci console.info('Renderer start success.'); 96e41f4b71Sopenharmony_ci } 97e41f4b71Sopenharmony_ci }); 98e41f4b71Sopenharmony_ci } 99e41f4b71Sopenharmony_ci} 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ci// Pause the rendering. 102e41f4b71Sopenharmony_ciasync function pause() { 103e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 104e41f4b71Sopenharmony_ci // Rendering can be paused only when the AudioRenderer is in the STATE_RUNNING state. 105e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() !== audio.AudioState.STATE_RUNNING) { 106e41f4b71Sopenharmony_ci console.info('Renderer is not running'); 107e41f4b71Sopenharmony_ci return; 108e41f4b71Sopenharmony_ci } 109e41f4b71Sopenharmony_ci await renderModel.pause(); // Pause rendering. 110e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() === audio.AudioState.STATE_PAUSED) { 111e41f4b71Sopenharmony_ci console.info('Renderer is paused.'); 112e41f4b71Sopenharmony_ci } else { 113e41f4b71Sopenharmony_ci console.error('Pausing renderer failed.'); 114e41f4b71Sopenharmony_ci } 115e41f4b71Sopenharmony_ci } 116e41f4b71Sopenharmony_ci} 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci// Stop rendering. 119e41f4b71Sopenharmony_ciasync function stop() { 120e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 121e41f4b71Sopenharmony_ci // The AudioRenderer can be stopped only when it is in the STATE_RUNNING or STATE_PAUSED state. 122e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() !== audio.AudioState.STATE_RUNNING && renderModel.state.valueOf() !== audio.AudioState.STATE_PAUSED) { 123e41f4b71Sopenharmony_ci console.info('Renderer is not running or paused.'); 124e41f4b71Sopenharmony_ci return; 125e41f4b71Sopenharmony_ci } 126e41f4b71Sopenharmony_ci await renderModel.stop(); // Stop rendering. 127e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() === audio.AudioState.STATE_STOPPED) { 128e41f4b71Sopenharmony_ci console.info('Renderer stopped.'); 129e41f4b71Sopenharmony_ci } else { 130e41f4b71Sopenharmony_ci console.error('Stopping renderer failed.'); 131e41f4b71Sopenharmony_ci } 132e41f4b71Sopenharmony_ci } 133e41f4b71Sopenharmony_ci} 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci// Release the instance. 136e41f4b71Sopenharmony_ciasync function release() { 137e41f4b71Sopenharmony_ci if (renderModel !== undefined) { 138e41f4b71Sopenharmony_ci // The AudioRenderer can be released only when it is not in the STATE_RELEASED state. 139e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() === audio.AudioState.STATE_RELEASED) { 140e41f4b71Sopenharmony_ci console.info('Renderer already released'); 141e41f4b71Sopenharmony_ci return; 142e41f4b71Sopenharmony_ci } 143e41f4b71Sopenharmony_ci await renderModel.release(); // Release the instance. 144e41f4b71Sopenharmony_ci if (renderModel.state.valueOf() === audio.AudioState.STATE_RELEASED) { 145e41f4b71Sopenharmony_ci console.info('Renderer released'); 146e41f4b71Sopenharmony_ci } else { 147e41f4b71Sopenharmony_ci console.error('Renderer release failed.'); 148e41f4b71Sopenharmony_ci } 149e41f4b71Sopenharmony_ci } 150e41f4b71Sopenharmony_ci} 151e41f4b71Sopenharmony_ci``` 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ci## Using AudioCapturer to Record the Local Voice 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ciThis process is similar to the process of [using AudioCapturer to develop audio recording](using-audiocapturer-for-recording.md). The key differences lie in the **audioCapturerInfo** parameter and audio data stream direction. In the **audioCapturerInfo** parameter used for audio calling, **source** must be set to **SOURCE_TYPE_VOICE_COMMUNICATION**. 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ciYou must request the **ohos.permission.MICROPHONE** permission for all recording tasks. For details, see [Requesting User Authorization](../../security/AccessToken/request-user-authorization.md). 158e41f4b71Sopenharmony_ci 159e41f4b71Sopenharmony_ci```ts 160e41f4b71Sopenharmony_ciimport { audio } from '@kit.AudioKit'; 161e41f4b71Sopenharmony_ciimport { fileIo } from '@kit.CoreFileKit'; 162e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 163e41f4b71Sopenharmony_ci 164e41f4b71Sopenharmony_cilet context = getContext(this); 165e41f4b71Sopenharmony_ciconst TAG = 'VoiceCallDemoForAudioCapturer'; 166e41f4b71Sopenharmony_ciclass Options { 167e41f4b71Sopenharmony_ci offset?: number; 168e41f4b71Sopenharmony_ci length?: number; 169e41f4b71Sopenharmony_ci} 170e41f4b71Sopenharmony_ci// The process is similar to the process of using AudioCapturer to develop audio recording. The key differences lie in the audioCapturerInfo parameter and audio data stream direction. 171e41f4b71Sopenharmony_cilet bufferSize: number = 0; 172e41f4b71Sopenharmony_cilet audioCapturer: audio.AudioCapturer | undefined = undefined; 173e41f4b71Sopenharmony_cilet audioStreamInfo: audio.AudioStreamInfo = { 174e41f4b71Sopenharmony_ci samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, // Sampling rate. 175e41f4b71Sopenharmony_ci channels: audio.AudioChannel.CHANNEL_1, // Channel. 176e41f4b71Sopenharmony_ci sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // Sampling format. 177e41f4b71Sopenharmony_ci encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // Encoding format. 178e41f4b71Sopenharmony_ci} 179e41f4b71Sopenharmony_cilet audioCapturerInfo: audio.AudioCapturerInfo = { 180e41f4b71Sopenharmony_ci // Set the parameters related to the call scenario. 181e41f4b71Sopenharmony_ci source: audio.SourceType.SOURCE_TYPE_VOICE_COMMUNICATION, // Audio source type: voice communication. 182e41f4b71Sopenharmony_ci capturerFlags: 0 // AudioCapturer flag. The default value is 0. 183e41f4b71Sopenharmony_ci} 184e41f4b71Sopenharmony_cilet audioCapturerOptions: audio.AudioCapturerOptions = { 185e41f4b71Sopenharmony_ci streamInfo: audioStreamInfo, 186e41f4b71Sopenharmony_ci capturerInfo: audioCapturerInfo 187e41f4b71Sopenharmony_ci} 188e41f4b71Sopenharmony_ci 189e41f4b71Sopenharmony_cilet path = getContext().cacheDir; 190e41f4b71Sopenharmony_cilet filePath = path + '/StarWars10s-2C-48000-4SW.wav'; 191e41f4b71Sopenharmony_cilet file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); 192e41f4b71Sopenharmony_ci 193e41f4b71Sopenharmony_cilet readDataCallback = (buffer: ArrayBuffer) => { 194e41f4b71Sopenharmony_ci let options: Options = { 195e41f4b71Sopenharmony_ci offset: bufferSize, 196e41f4b71Sopenharmony_ci length: buffer.byteLength 197e41f4b71Sopenharmony_ci } 198e41f4b71Sopenharmony_ci fileIo.writeSync(file.fd, buffer, options); 199e41f4b71Sopenharmony_ci bufferSize += buffer.byteLength; 200e41f4b71Sopenharmony_ci} 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci// Create an AudioRenderer instance, and set the events to listen for. 203e41f4b71Sopenharmony_ciasync function init() { 204e41f4b71Sopenharmony_ci audio.createAudioCapturer(audioCapturerOptions, (err: BusinessError, capturer: audio.AudioCapturer) => { // Create an AudioCapturer instance. 205e41f4b71Sopenharmony_ci if (err) { 206e41f4b71Sopenharmony_ci console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`); 207e41f4b71Sopenharmony_ci return; 208e41f4b71Sopenharmony_ci } 209e41f4b71Sopenharmony_ci console.info(`${TAG}: create AudioCapturer success`); 210e41f4b71Sopenharmony_ci audioCapturer = capturer; 211e41f4b71Sopenharmony_ci if (audioCapturer !== undefined) { 212e41f4b71Sopenharmony_ci audioCapturer.on('markReach', 1000, (position: number) => { // Subscribe to the markReach event. A callback is triggered when the number of captured frames reaches 1000. 213e41f4b71Sopenharmony_ci if (position === 1000) { 214e41f4b71Sopenharmony_ci console.info('ON Triggered successfully'); 215e41f4b71Sopenharmony_ci } 216e41f4b71Sopenharmony_ci }); 217e41f4b71Sopenharmony_ci audioCapturer.on('periodReach', 2000, (position: number) => { // Subscribe to the periodReach event. A callback is triggered each time when the number of captured frames reaches 2000. 218e41f4b71Sopenharmony_ci if (position === 2000) { 219e41f4b71Sopenharmony_ci console.info('ON Triggered successfully'); 220e41f4b71Sopenharmony_ci } 221e41f4b71Sopenharmony_ci }); 222e41f4b71Sopenharmony_ci audioCapturer.on('readData', readDataCallback); 223e41f4b71Sopenharmony_ci } 224e41f4b71Sopenharmony_ci }); 225e41f4b71Sopenharmony_ci} 226e41f4b71Sopenharmony_ci 227e41f4b71Sopenharmony_ci// Start audio recording. 228e41f4b71Sopenharmony_ciasync function start() { 229e41f4b71Sopenharmony_ci if (audioCapturer !== undefined) { 230e41f4b71Sopenharmony_ci let stateGroup: number[] = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 231e41f4b71Sopenharmony_ci if (stateGroup.indexOf(audioCapturer.state.valueOf()) === -1) { // Recording can be started only when the AudioCapturer is in the STATE_PREPARED, STATE_PAUSED, or STATE_STOPPED state. 232e41f4b71Sopenharmony_ci console.error(`${TAG}: start failed`); 233e41f4b71Sopenharmony_ci return; 234e41f4b71Sopenharmony_ci } 235e41f4b71Sopenharmony_ci audioCapturer.start((err: BusinessError) => { 236e41f4b71Sopenharmony_ci if (err) { 237e41f4b71Sopenharmony_ci console.error('Capturer start failed.'); 238e41f4b71Sopenharmony_ci } else { 239e41f4b71Sopenharmony_ci console.info('Capturer start success.'); 240e41f4b71Sopenharmony_ci } 241e41f4b71Sopenharmony_ci }); 242e41f4b71Sopenharmony_ci } 243e41f4b71Sopenharmony_ci} 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci// Stop recording. 246e41f4b71Sopenharmony_ciasync function stop() { 247e41f4b71Sopenharmony_ci if (audioCapturer !== undefined) { 248e41f4b71Sopenharmony_ci // The AudioCapturer can be stopped only when it is in STATE_RUNNING or STATE_PAUSED state. 249e41f4b71Sopenharmony_ci if (audioCapturer.state.valueOf() !== audio.AudioState.STATE_RUNNING && audioCapturer.state.valueOf() !== audio.AudioState.STATE_PAUSED) { 250e41f4b71Sopenharmony_ci console.info('Capturer is not running or paused'); 251e41f4b71Sopenharmony_ci return; 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci await audioCapturer.stop(); // Stop recording. 254e41f4b71Sopenharmony_ci if (audioCapturer.state.valueOf() === audio.AudioState.STATE_STOPPED) { 255e41f4b71Sopenharmony_ci console.info('Capturer stopped'); 256e41f4b71Sopenharmony_ci } else { 257e41f4b71Sopenharmony_ci console.error('Capturer stop failed'); 258e41f4b71Sopenharmony_ci } 259e41f4b71Sopenharmony_ci } 260e41f4b71Sopenharmony_ci} 261e41f4b71Sopenharmony_ci 262e41f4b71Sopenharmony_ci// Release the instance. 263e41f4b71Sopenharmony_ciasync function release() { 264e41f4b71Sopenharmony_ci if (audioCapturer !== undefined) { 265e41f4b71Sopenharmony_ci // The AudioCapturer can be released only when it is not in the STATE_RELEASED or STATE_NEW state. 266e41f4b71Sopenharmony_ci if (audioCapturer.state.valueOf() === audio.AudioState.STATE_RELEASED || audioCapturer.state.valueOf() === audio.AudioState.STATE_NEW) { 267e41f4b71Sopenharmony_ci console.info('Capturer already released'); 268e41f4b71Sopenharmony_ci return; 269e41f4b71Sopenharmony_ci } 270e41f4b71Sopenharmony_ci await audioCapturer.release(); // Release the instance. 271e41f4b71Sopenharmony_ci if (audioCapturer.state.valueOf() === audio.AudioState.STATE_RELEASED) { 272e41f4b71Sopenharmony_ci console.info('Capturer released'); 273e41f4b71Sopenharmony_ci } else { 274e41f4b71Sopenharmony_ci console.error('Capturer release failed'); 275e41f4b71Sopenharmony_ci } 276e41f4b71Sopenharmony_ci } 277e41f4b71Sopenharmony_ci} 278e41f4b71Sopenharmony_ci``` 279