OpenHarmony 音频管理

前言

音频可以通过超级终端在其他外部设备上播放本地的音频流

例如使用 Openharmony 或者 HarmonyOS 设备与一台华为sound使用超级终端连接并播放一首歌曲

下面是音频管理的介绍和运行实例的代码片段

官方代码仓库 multimedia_audio_framework: Audio management implementation | 音频管理功能实现

介绍

音频组件用于实现音频相关功能,包括播放、音量管理、设备管理等

架构如下图

应用接入

音频播放

使用AudioRenderer实现音频播放

​ 1.使用Create接口和所需要流的类型来获取AudioRenderer实例

1
2
AudioStreamType streamType = STREAM_MUSIC; // 流类型
std::unique_ptr<AudioRenderer> audioRenderer = AudioRenderer::Create(streamType);

​ 2.[选]静态接口

GetSupportedFormats(),GetSupportedChannels(),GetSupportedEncodingTypes(),GetSupportedSamplingRates() 来获取参数

​ 3.调用实例的SetParams

1
2
3
4
5
6
7
AudioRendererParams rendererParams;
rendererParams.sampleFormat = SAMPLE_S16LE;
rendererParams.sampleRate = SAMPLE_RATE_44100;
rendererParams.channelCount = STEREO;
rendererParams.encodingType = ENCODING_PCM;

audioRenderer->SetParams(rendererParams);

​ 4.[选]使用audioRenderer->GetParams(rendererParams)验证SetParams

​ 5.AudioRenderer实例调用audioRenderer->Start() 函数启动播放Task

​ 6.使用GetBufferSize接口获取需写入缓冲区长度

1
audioRenderer->GetBufferSize(bufferLen);

​ 7.读取源需播放的音频数据并传输到流中,重复调用Write函数写入渲染数据

1
2
3
4
5
6
bytesToWrite = fread(buffer, 1, bufferLen, wavFile);
while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)){
bytesWritten = audioRenderer->Write(buffer + bytesWritten, bytesToWrite - bytesWritten);
if (bytesWritten < 0)
break;
}

​ 8.调用audioRenderer->Drain()清空播放流

​ 9.调用audioRenderer->Stop()停止输出流

​ 10.在播放任务完成后,调用AudioRenderer实例的audioRenderer->Release()释放资源

​ 11.使用audioRenderer->SetVolume(float)audioRenderer->GetVolume()设置和获取当前流音量,可选范围为[0.0,1.0]

音频录制

使用仓库内提供的接口让应用程序完成使用输入设备进行声音录制,将语音转换为音频数据,并管理录制的任务

下面的步骤将描述如何使用AudioCapturer开发音频录制功能

  1. 使用Create接口和所需流类型来获取AudioCapturer实例

    1
    2
    AudioStreamType streamType = STREAM_MUSIC;
    std::unique_ptr<AudioCapturer> audioCapturer = AudioCapturer::Create(streamType);
  2. [选]静态接口

    GetSupportedFormats(),GetSupportedChannels(),GetSupportedEncodingTypes(),GetSupportedSamplingRates()可用于获取支持的参数

  3. 准备设备,调用实例的SetParams

    1
    2
    3
    4
    5
    6
    7
    AudioCapturerParams capturerParams;
    capturerParams.sampleFormat = SAMPLE_S16LE;
    capturerParams.sampleRate = SAMPLE_RATE_44100;
    capturerParams.channelCount = STEREO;
    capturerParams.encodingType = ENCODING_PCM;

    audioCapturer->SetParams(capturerParams);
  4. [选]使用audioCapturer->GetParams(capturerParams)验证SetParams()

  5. AudioCapturer实例调用AudioCapturer->Start()启动录音任务

  6. 使用GetBufferSize接口获取写入的缓冲区长度

    1
    audioCapturer->GetBufferSize(bufferLen);
  7. 读取录制的音频数据并将其转换为字节流,重复调用read函数读取数据直到主动停止

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // set isBlocking = true/false for blocking/non-blocking read
    bytesRead = audioCapturer->Read(*buffer, bufferLen, isBlocking);
    while (numBuffersToCapture) {
    bytesRead = audioCapturer->Read(*buffer, bufferLen, isBlockingRead);
    if (bytesRead < 0) {
    break;
    } else if (bytesRead > 0) {
    fwrite(buffer, size, bytesRead, recFile); // example shows writes the recorded data into a file
    numBuffersToCapture--;
    }
    }
  8. audioCapturer->Flush()清空录音流缓冲区

  9. AudioCapturer实例调用audioCapturer->Stop()停止录音

  10. 在录音任务完成后,调用AudioCapturer实例的audioCapturer->Release()释放资源

音频管理

可以使用audio_system_manager.h的接口来控制音量和设备

  1. 使用GetInstance接口获取AudioSystemManager实例

    1
    AudioSystemManager *audioSystemMgr = AudioSystemManager::GetInstance();

    音量控制

  2. 使用GetMaxVolumeGetMinVolume接口去查询音频流支持的最大和最小音量等级,在此范围内设置音量

    1
    2
    3
    AudioVolumeType streamType = AudioVolumeType::STREAM_MUSIC;
    int32_t maxVol = audioSystemMgr->GetMaxVolume(streamType);
    int32_t minVol = audioSystemMgr->GetMinVolume(streamType);
  3. 使用SetVolumeGetVolume接口来设置和获取指定音频流的音量等级

    1
    2
    int32_t result = audioSystemMgr->SetVolume(streamType, 10);
    int32_t vol = audioSystemMgr->GetVolume(streamType);
  4. 使用SetMuteIsStreamMute接口来设置和获取指定音频流的静音状态

    1
    2
    int32_t result = audioSystemMgr->SetMute(streamType, true);
    bool isMute = audioSystemMgr->IsStreamMute(streamType);
  5. 使用SetRingerModeGetRingerMode接口来设置和获取铃声模式,参考在audio_info.h定义的AudioRingerMode枚举来获取支持的铃声模式

    1
    2
    int32_t result = audioSystemMgr->SetRingerMode(RINGER_MODE_SILENT);
    AudioRingerMode ringMode = audioSystemMgr->GetRingerMode();
  6. 使用SetMicrophoneMuteIsMicrophoneMute接口来设置和获取麦克风的静音状态

    1
    2
    int32_t result = audioSystemMgr->SetMicrophoneMute(true);
    bool isMicMute = audioSystemMgr->IsMicrophoneMute();

    设备控制

  7. 使用GetDevices,deviceTypedeviceRole接口来获取音频输入输出设备信息,参考audio_info.h内定义的DeviceFlag,DeviceTypeDeviceRole枚举

    1
    2
    3
    4
    5
    6
    DeviceFlag deviceFlag = OUTPUT_DEVICES_FLAG;
    vector<sptr<AudioDeviceDescriptor>> audioDeviceDescriptors
    = audioSystemMgr->GetDevices(deviceFlag);
    sptr<AudioDeviceDescriptor> audioDeviceDescriptor = audioDeviceDescriptors[0];
    cout << audioDeviceDescriptor->deviceType_;
    cout << audioDeviceDescriptor->deviceRole_;
  8. 使用SetDeviceActiveIsDeviceActive接口去激活/去激活音频设备和获取音频设备激活状态

    1
    2
    3
    ActiveDeviceType deviceType = SPEAKER;
    int32_t result = audioSystemMgr->SetDeviceActive(deviceType, true);
    bool isDevActive = audioSystemMgr->IsDeviceActive(deviceType);
  9. 提供其他用途的接口如IsStreamActive,SetAudioParameterGetAudioParameter,详细请参考 audio_system_manager.h

  10. 应用程序可以使用AudioManagerNapi::On注册系统音量的更改,在此,如果应用程序监听到系统音量更改的事件,就会用以下参数通知应用程序
    volumeType : 更改的系统音量的类型
    volume : 当前的音量等级
    updateUi : 是否需要显示变化详细信息(如果音量被增大/减小,将updateUi标志设置为true,在其他情况下,updateUi设置为false)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const audioManager = audio.getAudioManager();

    export default {
    onCreate() {
    audioManager.on('volumeChange', (volumeChange) ==> {
    console.info('volumeType = '+volumeChange.volumeType);
    console.info('volume = '+volumeChange.volume);
    console.info('updateUi = '+volumeChange.updateUi);
    }
    }
    }

音频场景

  1. 使用SetAudioscenegetAudioScene接口去更改和检查音频策略

    1
    2
    int32_t result = audioSystemMgr->SetAudioScene(AUDIO_SCENE_PHONE_CALL);
    AudioScene audioScene = audioSystemMgr->GetAudioScene();

    有关支持的音频场景,请参阅AudioScene中的枚举audio_info.h

    音频流管理

    可以使用audio_stream_manager.h提供的接口用于流管理功能

  2. 使用GetInstance接口获得AudioSystemManager实例

    1
    AudioStreamManager *audioStreamMgr = AudioStreamManager::GetInstance();
  3. 使用RegisterAudioRendererEventListener为渲染器状态更改注册侦听器.渲染器状态更改回调,该回调将在渲染器流状态更改时调用,通过重写AudioRendererStateChangeCallback类中的函数OnRendererStateChange

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const int32_t clientUID;

    class RendererStateChangeCallback : public AudioRendererStateChangeCallback {
    public:
    RendererStateChangeCallback = default;
    ~RendererStateChangeCallback = default;
    void OnRendererStateChange(
    const std::vector<std::unique_ptr<AudioRendererChangeInfo>> &audioRendererChangeInfos) override
    {
    cout<<"OnRendererStateChange entered"<<endl;
    }
    };

    std::shared_ptr<AudioRendererStateChangeCallback> callback = std::make_shared<RendererStateChangeCallback>();
    int32_t state = audioStreamMgr->RegisterAudioRendererEventListener(clientUID, callback);
    int32_t result = audioStreamMgr->UnregisterAudioRendererEventListener(clientUID);
  4. 使用RegisterAudioCapturerEventListener为捕获器状态更改注册侦听器,捕获器状态更改回调,该回调将在捕获器流状态更改时调用,通过重写AudioCapturerStateChangeCallback类中的函数OnCapturerStateChange

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const int32_t clientUID;

    class CapturerStateChangeCallback : public AudioCapturerStateChangeCallback {
    public:
    CapturerStateChangeCallback = default;
    ~CapturerStateChangeCallback = default;
    void OnCapturerStateChange(
    const std::vector<std::unique_ptr<AudioCapturerChangeInfo>> &audioCapturerChangeInfos) override
    {
    cout<<"OnCapturerStateChange entered"<<endl;
    }
    };

    std::shared_ptr<AudioCapturerStateChangeCallback> callback = std::make_shared<CapturerStateChangeCallback>();
    int32_t state = audioStreamMgr->RegisterAudioCapturerEventListener(clientUID, callback);
    int32_t result = audioStreamMgr->UnregisterAudioCapturerEventListener(clientUID);
  5. 使用GetCurrentRendererChangeInfos获取所有当前正在运行的流渲染器信息包括clientuidsessionidrenderinforenderstate和输出设备详细信息

    1
    2
    std::vector<std::unique_ptr<AudioRendererChangeInfo>> audioRendererChangeInfos;
    int32_t currentRendererChangeInfo = audioStreamMgr->GetCurrentRendererChangeInfos(audioRendererChangeInfos);
  6. 使用GetCurrentCapturerChangeInfos获取所有当前正在运行的流捕获器信息,包括clientuidsessionidcapturerInfocapturerState和输入设备详细信息

    1
    2
    std::vector<std::unique_ptr<AudioCapturerChangeInfo>> audioCapturerChangeInfos;
    int32_t currentCapturerChangeInfo = audioStreamMgr->GetCurrentCapturerChangeInfos(audioCapturerChangeInfos);

    有关结构,请参阅audio_info.haudioRendererChangeInfosaudioCapturerChangeInfos

  7. 使用IsAudioRendererLowLatencySupported检查低延迟功能是否支持

    1
    2
    const AudioStreamInfo &audioStreamInfo;
    bool isLatencySupport = audioStreamMgr->IsAudioRendererLowLatencySupported(audioStreamInfo);

    JavaScript用法

    JavaScript应用可以使用系统提供的音频管理接口,来控制音量和设备

请参考js-apis-audio.md来获取音量和设备管理相关JavaScript接口的用法

铃声管理

可以使用提供的接口iringtone_sound_manager.hiringtone_player.h实现铃声播放功能

  1. 使用CreateRingtoneManager接口创建IRingtoneSoundManager实例

    1
    std::shared_ptr<IRingtoneSoundManager> ringtoneManagerClient = RingtoneFactory::CreateRingtoneManager();
  2. 使用SetSystemRingtoneUri接口设置系统铃声Uri

    1
    2
    3
    std::string uri = "/data/media/test.wav";
    RingtoneType ringtoneType = RINGTONE_TYPE_DEFAULT;
    ringtoneManagerClient->SetSystemRingtoneUri(context, uri, ringtoneType);
  3. 使用GetRingtonePlayer接口获取IRingtonePlayer实例

    1
    std::unique_ptr<IRingtonePlayer> ringtonePlayer = ringtoneManagerClient->GetRingtonePlayer(context, ringtoneType);
  4. 使用Configure接口配置铃声播放器

    1
    2
    3
    float volume = 1;
    bool loop = true;
    ringtonePlayer.Configure(volume, loop);
  5. 使用Start,StopRelease接口在铃声播放器实例上控制播放状态

    1
    2
    3
    ringtonePlayer.Start();
    ringtonePlayer.Stop();
    ringtonePlayer.Release();
  6. 使用GetTitle接口获取当前系统铃声的标题

  7. 使用GetRingtoneState接口获取铃声播放状态RingtoneState

  8. 使用GetAudioRendererInfo获取AudioRendererInfo检查内容类型和流使用情况

    蓝牙SCO呼叫

    可以使用提供的接口audio_bluetooth_manager.h实现同步连接导向链路(SCO)的蓝牙呼叫

  9. 为监听SCO状态更改,您可以使用OnScoStateChanged

    1
    2
    3
    const BluetoothRemoteDevice &device;
    int state;
    void OnScoStateChanged(const BluetoothRemoteDevice &device, int state);
  10. [选]静态接口RegisterBluetoothScoAgListener(),UnregisterBluetoothScoAgListener(),可用于注册蓝牙SCO的侦听器