智能客服
你问我答,随时在线为你解决问题

























在自定义相机中,自定义快门声音可以让用户根据个人喜好选择不同的快门声音,获得更加个性化的体验,如何自定义快门声音?
- import { media } from '@kit.MediaKit';
- import { audio } from '@kit.AudioKit';
- import { BusinessError } from '@kit.BasicServicesKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
-
- const DOMAIN: number = 0x0000;
- const TAG: string = '[SoundPoolPage]';
-
- export class SoundPoolUtil {
- private soundPool: media.SoundPool | undefined = undefined;
- private soundId: number = 0;
- private streamId: number = 0;
- private currentContext: Context;
-
- constructor(uiContext: Context) {
- this.currentContext = uiContext;
- this.create();
- }
-
- async create() {
- try {
- // audioRenderInfo中的参数usage取值为STREAM_USAGE_UNKNOWN,STREAM_USAGE_MUSIC,STREAM_USAGE_MOVIE
- // STREAM_USAGE_AUDIOBOOK时,SoundPool播放短音时为混音模式,不会打断其他音频播放
- let audioRendererInfo: audio.AudioRendererInfo = {
- usage: audio.StreamUsage.STREAM_USAGE_MUSIC, // 音频流使用类型:音乐
- rendererFlags: 1 // 音频渲染器标志
- };
- // 创建soundPool实例
- this.soundPool = await media.createSoundPool(14, audioRendererInfo);
- // 注册监听
- this.loadCallback();
- this.finishPlayCallback();
- this.setErrorCallback();
-
- // 加载音频资源,开发者需要在resources/rawfile目录下替换成快门音频资源
- let fileDescriptor = await this.currentContext!.resourceManager.getRawFd('shutter.mp3');
- hilog.info(DOMAIN, TAG, `Successfully get the fileDescriptor: ${fileDescriptor}`);
- this.soundId = await this.soundPool!.load(fileDescriptor.fd, fileDescriptor.offset, fileDescriptor.length);
- hilog.info(DOMAIN, TAG, `Successfully load soundPool soundId: ${this.soundId}`);
- } catch (e) {
- hilog.error(DOMAIN, TAG, `CreateSoundPool error: ${e}`);
- }
- }
-
- async loadCallback() {
- // 加载完成回调
- this.soundPool!.on('loadComplete', (soundId_: number) => {
- this.soundId = soundId_;
- hilog.info(DOMAIN, TAG, `Successfully loadComplete soundId: ${soundId_}`);
- });
- }
-
- // 设置播放完成监听
- async finishPlayCallback() {
- this.soundPool!.on('playFinished', () => {
- hilog.info(DOMAIN, TAG, 'receive play finished message');
- });
- }
-
- // 设置错误类型监听
- async setErrorCallback() {
- this.soundPool!.on('error', (error: BusinessError) => {
- hilog.error(DOMAIN, TAG, `error happened,message is: ${error.code}`);
- hilog.error(DOMAIN, TAG, `error happened,message is: ${error.message}`);
- });
- }
-
- async PlaySoundPool() {
- let playParameters: media.PlayParameters = {
- loop: 0, // 循环0次,即播放1次
- rate: 1, // 1倍速播放
- leftVolume: 0.5, // 取值范围0.0-1.0
- rightVolume: 0.5, // 取值范围0.0-1.0
- priority: 0, // 最低优先级
- };
- // 开始播放,请在音频资源加载完毕,即收到loadComplete回调之后再执行play操作
- this.soundPool!.play(this.soundId, playParameters, (error, streamID: number) => {
- if (error) {
- hilog.error(DOMAIN, TAG, `play sound Error: errCode is ${error.code}, errMessage is ${error.message}`);
- } else {
- this.streamId = streamID;
- hilog.info(DOMAIN, TAG, `play success soundid: ${this.streamId}`);
- }
- });
-
- // 设置循环播放次数
- await this.soundPool!.setLoop(this.streamId, 1);
- // 设置对应流的优先级
- await this.soundPool!.setPriority(this.streamId, 1);
- // 设置音量
- await this.soundPool!.setVolume(this.streamId, 0.5, 0.5);
- }
-
- async release() {
- // 终止指定流的播放
- await this.soundPool!.stop(this.streamId);
- // 卸载音频资源
- await this.soundPool!.unload(this.soundId);
- // 关闭监听
- this.setOffCallback();
- // 释放SoundPool
- await this.soundPool!.release();
- }
-
- async setOffCallback() {
- this.soundPool!.off('loadComplete');
- this.soundPool!.off('playFinished');
- this.soundPool!.off('error');
- }
- }
- import { camera } from '@kit.CameraKit';
- import { BusinessError } from '@kit.BasicServicesKit';
- import { photoAccessHelper } from '@kit.MediaLibraryKit';
- import { colorSpaceManager } from '@kit.ArkGraphics2D';
- import { image } from '@kit.ImageKit';
- import { hilog } from '@kit.PerformanceAnalysisKit';
-
- const DOMAIN: number = 0x0000;
- const TAG: string = '[CameraShooterPage]';
-
- let previewOutput: camera.PreviewOutput;
- let cameraInput: camera.CameraInput;
- let photoSession: camera.PhotoSession;
- let photoOutPut: camera.PhotoOutput;
- let currentContext: Context;
- // 期望的拍照图片尺寸
- let imageSize: image.Size = { width: 1920, height: 1440 };
-
- export async function cameraShooting(cameraPosition: number, surfaceId: string, context: Context): Promise<void> {
- currentContext = context;
- releaseCamera();
- try {
- // 获取相机管理对象
- let cameraManager: camera.CameraManager = camera.getCameraManager(context);
- let cameraArray: camera.CameraDevice[] = cameraManager.getSupportedCameras();
- if (cameraArray.length <= 0) {
- hilog.error(DOMAIN, TAG, 'No camera devices found!');
- return;
- }
- // 创建相机输入流
- cameraInput = cameraManager.createCameraInput(cameraArray[cameraPosition]);
- await cameraInput.open();
- // 获取支持的相机模式
- let sceneModes: camera.SceneMode[] = cameraManager.getSupportedSceneModes(cameraArray[cameraPosition]);
- // 获取支持的相机输出能力
- let cameraOutputCap: camera.CameraOutputCapability =
- cameraManager.getSupportedOutputCapability(cameraArray[cameraPosition], camera.SceneMode.NORMAL_PHOTO);
- let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
- if (!isSupportPhotoMode) {
- hilog.error(DOMAIN, TAG, 'No supported photo mode found!');
- return;
- }
- if (!cameraOutputCap) {
- hilog.error(DOMAIN, TAG, 'No supported camera OutputCap found!');
- return;
- }
- // 获取预览流的Profile列表
- let previewProfilesArray: camera.Profile[] = cameraOutputCap.previewProfiles;
- // 创建预览输出流,surfaceId为显示组件的id
- let previewProfile: camera.Profile | undefined = undefined;
- for (let index = previewProfilesArray.length - 1; index >= 0; index--) {
- if (previewProfilesArray[index].size.width / previewProfilesArray[index].size.height ===
- imageSize.width / imageSize.height) {
- previewProfile = previewProfilesArray[index];
- break;
- }
- }
-
- previewOutput = cameraManager.createPreviewOutput(previewProfile, surfaceId);
- if (previewOutput === undefined) {
- return;
- }
-
- // 获取支持的拍照流profile
- let photoProfilesArray: camera.Profile[] = cameraOutputCap.photoProfiles.slice().reverse();
- let photoProfile: camera.Profile | undefined = undefined;
- if (previewProfile !== undefined) {
- // 选择与预览流分辨率宽高比一致的拍照流分辨率
- photoProfile = photoProfilesArray.find((profile: camera.Profile) => {
- return profile.size.height * previewProfile!.size.width === previewProfile!.size.height * profile.size.width;
- });
- }
- // 获取支持的拍照输出能力
- photoOutPut = cameraManager.createPhotoOutput(photoProfile);
-
- if (photoOutPut === undefined) {
- return;
- }
- // 保存图片
- setPhotoOutputCb(photoOutPut);
- // 创建相机会话
- photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
- if (photoSession === undefined) {
- return;
- }
- // 开始相机会话
- photoSession.beginConfig();
- photoSession.addInput(cameraInput);
- photoSession.addOutput(previewOutput);
- photoSession.addOutput(photoOutPut);
- photoSession.setColorSpace(colorSpaceManager.ColorSpace.DISPLAY_P3);
- await photoSession.commitConfig();
- await photoSession.start();
- } catch (error) {
- hilog.error(DOMAIN, TAG, `The cameraShooting call failed. error: ${JSON.stringify(error)}`);
- }
- }
-
- // 拍照方法
- export async function capture(isFront: boolean) {
- try {
- let settings: camera.PhotoCaptureSetting = {
- quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
- rotation: camera.ImageRotation.ROTATION_0,
- mirror: isFront
- };
- photoOutPut.capture(settings);
- } catch (error) {
- hilog.error(DOMAIN, TAG, `The capture call failed. error: ${error.code}`);
- }
- }
-
- // 释放相机相关资源
- export async function releaseCamera(): Promise<void> {
- try {
- if (photoSession) {
- photoSession.stop();
- }
- if (cameraInput) {
- cameraInput.close();
- }
- if (previewOutput) {
- previewOutput.release();
- }
- if (photoSession) {
- photoSession.release();
- }
- if (photoOutPut) {
- photoOutPut.off('photoAssetAvailable');
- photoOutPut.off('captureReady');
- photoOutPut.release();
- }
- } catch (error) {
- hilog.error(DOMAIN, TAG, `The releaseCamera call failed. error: ${error.code}`);
- }
- }
-
- // 拍照后将图片保存至媒体库
- export function setPhotoOutputCb(photoOutput: camera.PhotoOutput): void {
- photoOutput.on('photoAssetAvailable',
- async (_err: BusinessError, photoAsset: photoAccessHelper.PhotoAsset): Promise<void> => {
- let accessHelper: photoAccessHelper.PhotoAccessHelper =
- photoAccessHelper.getPhotoAccessHelper(currentContext);
- let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
- new photoAccessHelper.MediaAssetChangeRequest(photoAsset);
- try {
- assetChangeRequest.saveCameraPhoto();
- await accessHelper.applyChanges(assetChangeRequest);
- AppStorage.setOrCreate('photoUri', await photoAsset.getThumbnail());
- } catch (error) {
- hilog.error(DOMAIN, TAG, `The setPhotoOutputCb call failed. error: ${error.code}`);
- }
- });
- }
- import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
- import { display } from '@kit.ArkUI';
- import { hilog } from '@kit.PerformanceAnalysisKit';
- import {
- cameraShooting, capture,
- } from '../utils/CameraShooter';
- import { SoundPoolUtil } from '../utils/SoundPoolUtil';
-
- const DOMAIN: number = 0x0000;
- const TAG: string = '[XComponentPage]';
-
- let cameraPosition = 0;
- let surfaceId = '';
- let storage = new LocalStorage();
-
- @Component
- @Entry(storage)
- export struct CameraPage {
- mXComponentController: XComponentController = new XComponentController;
- permissions: Array<Permissions> = [
- 'ohos.permission.CAMERA',
- ];
- private isFront: boolean = false;
- // 全局context
- private context: Context = this.getUIContext().getHostContext()!;
- private displayWidth = display.getDefaultDisplaySync().width;
- private soundPoolUtil = new SoundPoolUtil(this.context);
-
- async aboutToAppear() {
- try {
- // 在aboutToAppear页面申请相机权限
- abilityAccessCtrl.createAtManager().requestPermissionsFromUser(this.context, this.permissions).then(() => {
- setTimeout(() => {
- cameraShooting(cameraPosition, surfaceId, this.context);
- }, 200);
- });
- } catch (error) {
- hilog.error(DOMAIN, TAG, `The cameraShooting failed. error: ${JSON.stringify(error)}`);
- }
- }
-
- build() {
- RelativeContainer() {
- // XComponent主视图
- XComponent({
- type: XComponentType.SURFACE,
- controller: this.mXComponentController
- })
- .onLoad(async () => {
- this.mXComponentController.setXComponentSurfaceRect({
- surfaceWidth: this.displayWidth,
- surfaceHeight: this.displayWidth * 4 / 3
- });
- surfaceId = this.mXComponentController.getXComponentSurfaceId();
- })
-
- Row() {
- Stack() {
- // 拍照按钮
- Image($r('app.media.capture'))
- .height(70)
- .onClick(() => {
- capture(this.isFront);
- // 播放自定义快门声音
- this.soundPoolUtil?.PlaySoundPool();
- })
- }
- }
- .id('controlPanel')
- .width('100%')
- .justifyContent(FlexAlign.SpaceAround)
- .alignRules({
- bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
- })
- .margin({ bottom: '40vp' })
- }
- .height('100%')
- .backgroundColor(Color.Black)
- }
- }
-
- export async function fromBack(context: Context): Promise<void> {
- cameraShooting(cameraPosition, surfaceId, context);
- }
智能客服
你问我答,随时在线为你解决问题
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功