• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//@ts-nocheck
2/*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import camera from '@ohos.multimedia.camera';
18import image from '@ohos.multimedia.image';
19import media from '@ohos.multimedia.media';
20import deviceInfo from '@ohos.deviceInfo';
21
22import { CameraId } from '../setting/settingitem/CameraId';
23import { Log } from '../utils/Log';
24import ThumbnailGetter from './ThumbnailGetter';
25import SaveCameraAsset from './SaveCameraAsset';
26import { SettingManager } from '../setting/SettingManager';
27import { CameraPlatformCapability } from './CameraPlatformCapability';
28import EventLog from '../utils/EventLog';
29import { GlobalContext } from '../utils/GlobalContext';
30
31const TAG = '[CameraService]:';
32
33const DEFAULT_VIDEO_FRAME_RATE = 30;
34const FRONT_CAMERA_POSITION = 2;
35const CAMERA_CONNECT_TYPE = 2;
36
37export interface FunctionCallBack {
38  onCapturePhotoOutput(): void
39
40  onCaptureSuccess(thumbnail: any, resourceUri: any): void
41
42  onCaptureFailure(): void
43
44  onRecordSuccess(thumbnail: any): void
45
46  onRecordFailure(): void
47
48  thumbnail(thumbnail: any): void
49}
50
51export interface VideoCallBack {
52  videoUri(videoUri: any): void
53
54  onRecodeError(errorMsg: any): void
55}
56
57type Callback = (args?: any) => void
58
59class CameraInformation {
60  deviceName: string;
61  cameraId: string;
62}
63
64export class CameraService {
65  public mImageSize = {
66    imageWidth: 1920,
67    imageHeight: 1080
68  }
69  public mVideoFrameSize = {
70    frameWidth: 1920,
71    frameHeight: 1080
72  }
73  private mCameraId: string = CameraId.BACK;
74  private mFileAssetId = 0;
75  private mCameraManager!: camera.CameraManager;
76  private mCameraIdMap: Map<string, string> = new Map();
77  private mLocalCameraMap: Map<string, string> = new Map();
78  private mCameraMap: Map<string, CameraInformation> = new Map();
79  private curCameraName = '';
80  private mCameraCount = 0;
81  private mCameraInput!: camera.CameraInput;
82  private mCaptureSession!: camera.CaptureSession;
83  private mPreviewOutput!: camera.PreviewOutput;
84  private mPhotoOutPut!: camera.PhotoOutput;
85  private mImageReceiver!: image.ImageReceiver;
86  private mVideoOutput!: camera.VideoOutput;
87  private mAVRecorder!: media.AVRecorder;
88  private mThumbnail!: image.PixelMap;
89  private mIsStartRecording = false;
90  private mSaveCameraAsset = new SaveCameraAsset();
91  private mThumbnailGetter = new ThumbnailGetter();
92  private camerasCache: any = null;
93  private outputCapability: camera.CameraOutputCapability = null;
94  private mVideoConfig: any = {
95    audioSourceType: 1,
96    videoSourceType: 1,
97    profile: {
98      audioBitrate: 48000,
99      audioChannels: 2,
100      audioCodec: 'audio/mp4a-latm',
101      audioSampleRate: 48000,
102      durationTime: 1000,
103      fileFormat: 'mp4',
104      videoBitrate: 5000000,
105      videoCodec: 'video/avc',
106      videoFrameWidth: 640,
107      videoFrameHeight: 480,
108      videoFrameRate: 30
109    },
110    url: 'file:///data/media/01.mp4',
111    orientationHint: 0,
112    maxSize: 100,
113    maxDuration: 500,
114    rotation: 0
115  }
116  private mCaptureSetting: any = {
117    rotation: 0,
118    quality: 1,
119    mirror: false
120  }
121
122  private constructor() {
123  }
124
125  public static getInstance(): CameraService {
126    if (!globalThis?.sInstanceCameraService) {
127      globalThis.sInstanceCameraService = new CameraService();
128    }
129    return globalThis.sInstanceCameraService;
130  }
131
132  public async initCamera(cameraId: string): Promise<number> {
133    Log.start(`${TAG} initCamera`);
134    if (!this.mCameraManager) {
135      try {
136        this.mCameraManager = camera.getCameraManager(GlobalContext.get().getCameraAbilityContext());
137        const cameras = this.mCameraManager.getSupportedCameras();
138        this.camerasCache = cameras;
139        this.mCameraCount = cameras.length;
140        if (cameras) {
141          Log.info(`${TAG} getCameras success.`);
142          for (let i = 0; i < cameras.length; i++) {
143            Log.info(`${TAG} camera_id: ${cameras[i].cameraId}  cameraPosition: ${cameras[i].cameraPosition}
144              cameraType: ${cameras[i].cameraType} connectionType: ${cameras[i].connectionType}`);
145            if (cameras[i].cameraPosition === FRONT_CAMERA_POSITION && cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
146              this.mLocalCameraMap.set('front', 'true');
147            }
148            if (cameras[i].cameraPosition !== FRONT_CAMERA_POSITION && cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
149              this.mLocalCameraMap.set('back', 'true');
150            }
151          }
152          // TODO 根据底层信息匹配cameraId 目前默认第0个是back, 第1个是front
153          this.mCameraIdMap.set(CameraId.BACK, cameras[0].cameraId);
154          if (cameras.length > 1 && cameras[1].connectionType !== 2) {
155            this.mCameraIdMap.set(CameraId.FRONT, cameras[1].cameraId);
156          } else {
157            this.mCameraIdMap.set(CameraId.FRONT, cameras[0].cameraId);
158          }
159        }
160      } catch (error) {
161        Log.error(`${TAG} initCamera failed: ${JSON.stringify(error)}`);
162        EventLog.writeFaultLog(error);
163      }
164    }
165    this.curCameraName = cameraId;
166    await this.createCameraInput(cameraId, 'init');
167
168    Log.info(`${TAG} deviceType = ${deviceInfo.deviceType}`);
169    if (deviceInfo.deviceType == 'default') {
170      this.mVideoConfig.videoSourceType = 1;
171    } else {
172      this.mVideoConfig.videoSourceType = 0;
173    }
174    Log.end(`${TAG} initCamera`);
175    return this.mCameraCount;
176  }
177
178  public getCameraManager(): camera.CameraManager {
179    return this.mCameraManager;
180  }
181
182  public getCameraIdMap(): Map<string, string> {
183    return this.mCameraIdMap;
184  }
185
186  public getLocalCameraMap(): Map<string, string> {
187    return this.mLocalCameraMap;
188  }
189
190  public getCameraMap(): Map<string, CameraInformation> {
191    return this.mCameraMap;
192  }
193
194  public getCameraCount(): number {
195    return this.mCameraCount;
196  }
197
198  public async createCameraInput(cameraName: string, callType?: string) {
199    Log.start(`${TAG} createCameraInput`);
200    this.mCameraId = cameraName;
201    this.curCameraName = cameraName;
202    if (callType === 'modeChange' || callType === 'init') {
203      let targetCamera = this.camerasCache.filter(item => item.connectionType !== 2);
204      if (targetCamera && targetCamera.length <= 1 && cameraName === 'BACK') {
205        this.curCameraName = 'FRONT';
206        this.mCameraId = 'FRONT';
207      }
208    }
209    if (this.mCameraInput) {
210      await this.mCameraInput.release();
211    }
212    let id;
213    if (cameraName == CameraId.FRONT || cameraName == CameraId.BACK) {
214      id = this.mCameraIdMap.get(cameraName);
215    } else {
216      id = this.mCameraMap.get(cameraName).cameraId;
217    }
218    Log.info(`${TAG} createCameraInput id = ${id}`);
219    try {
220      let cameras = await this.getCameraLists();
221      let targetCamera = cameras.find(item => item.cameraId === id);
222      this.outputCapability = this.mCameraManager.getSupportedOutputCapability(targetCamera);
223      this.mCameraInput = this.mCameraManager.createCameraInput(targetCamera);
224      await this.mCameraInput.open();
225      const platformCapability = CameraPlatformCapability.getInstance();
226      await platformCapability.calcSupportedSizes(this.mCameraInput, this.outputCapability);
227      SettingManager.getInstance().setCameraPlatformCapability(platformCapability);
228    } catch (error) {
229      Log.error(`${TAG} createCameraInput failed: ${JSON.stringify(error)}`);
230      EventLog.writeFaultLog(error);
231    }
232    Log.end(`${TAG} createCameraInput`);
233  }
234
235  public async releaseCameraInput() {
236    Log.start(`${TAG} releaseCameraInput`);
237    if (this.mCameraInput) {
238      try {
239        await this.mCameraInput.release();
240      } catch (error) {
241        Log.error(`${TAG} releaseCameraInput failed: ${JSON.stringify(error)}`);
242        EventLog.writeFaultLog(error);
243      }
244      this.mCameraInput = null;
245    }
246    Log.end(`${TAG} releaseCameraInput`);
247  }
248
249  public async createPreviewOutput(surfaceId: string, mode: string) {
250    Log.start(`${TAG} createPreviewOutput`);
251    const size = SettingManager.getInstance().getPreviewSize(mode);
252    Log.info(`${TAG} createPreviewOutput size.width = ${size.width} size.height = ${size.height}`);
253    GlobalContext.get().getXComponentController().setXComponentSurfaceSize({ surfaceWidth: size.width, surfaceHeight: size.height });
254    let previewProfiles = this.outputCapability.previewProfiles;
255    let previewProfile;
256    if (deviceInfo.deviceType == 'default') {
257      previewProfile = previewProfiles[0];
258    } else {
259      Log.info(`${TAG} previewProfiles length.` + previewProfiles.length);
260      previewProfile = previewProfiles.find(item => item.size.width === size.width &&
261      item.size.height === size.height && item.format === 1003);
262    }
263    await this.releasePreviewOutput();
264    try {
265      this.mPreviewOutput = this.mCameraManager.createPreviewOutput(previewProfile, surfaceId);
266    } catch (error) {
267      Log.error(`${TAG} createPreviewOutput failed: ${JSON.stringify(error)}`);
268      EventLog.writeFaultLog(error);
269    }
270    Log.end(`${TAG} createPreviewOutput`);
271  }
272
273  public async releasePreviewOutput() {
274    Log.start(`${TAG} releasePreviewOutput`);
275    if (this.mPreviewOutput) {
276      try {
277        await this.mPreviewOutput.release();
278        this.mPreviewOutput = null;
279      } catch (error) {
280        Log.error(`${TAG} releasePreviewOutput failed: ${JSON.stringify(error)}`);
281        EventLog.writeFaultLog(error);
282      }
283    }
284    Log.end(`${TAG} releasePreviewOutput`);
285  }
286
287  public async createPhotoOutput(functionCallback: FunctionCallBack) {
288    Log.start(`${TAG} createPhotoOutput`);
289    const size = SettingManager.getInstance().getImageSize();
290    Log.info(`${TAG} createPhotoOutput size.width = ${size.width} size.height = ${size.height}`);
291    this.mImageReceiver = image.createImageReceiver(size.width, size.height, image.ImageFormat.JPEG, 8);
292    const surfaceId = await this.mImageReceiver.getReceivingSurfaceId();
293    Log.info(`${TAG} createPhotoOutput surfaceId: ${surfaceId}.`);
294    let photoProfiles = this.outputCapability.photoProfiles;
295    let photoProfile;
296    if (deviceInfo.deviceType == 'default') {
297      photoProfile = photoProfiles[0];
298    } else {
299      Log.info(`${TAG} videoProfiles length.` + photoProfiles.length);
300      photoProfile = photoProfiles.find(item => item.size.width === size.width && item.size.height === size.height);
301    }
302    try {
303      this.mPhotoOutPut = this.mCameraManager.createPhotoOutput(photoProfile, surfaceId);
304    } catch (error) {
305      Log.error(`${TAG} createPhotoOutput failed: ${JSON.stringify(error)}`);
306      EventLog.writeFaultLog(error);
307    }
308    Log.info(`${TAG} createPhotoOutput mPhotoOutPut: ${this.mPhotoOutPut}.`);
309    this.mSaveCameraAsset.saveImage(this.mImageReceiver, 40, 40, this.mThumbnailGetter, functionCallback);
310    Log.end(`${TAG} createPhotoOutput`);
311  }
312
313  public async releasePhotoOutput() {
314    Log.start(`${TAG} releasePhotoOutput`);
315    if (this.mPhotoOutPut) {
316      try {
317        await this.mPhotoOutPut.release();
318        this.mPhotoOutPut = null;
319      } catch (error) {
320        Log.error(`${TAG} releasePhotoOutput failed: ${JSON.stringify(error)}`);
321        EventLog.writeFaultLog(error);
322      }
323    }
324    if (this.mImageReceiver) {
325      await this.mImageReceiver.release();
326      this.mImageReceiver = null;
327    }
328    Log.end(`${TAG} releasePhotoOutput`);
329  }
330
331  public async createSession(surfaceId: string, isVideo: boolean) {
332    Log.start(`${TAG} createSession`);
333    GlobalContext.get().setObject('isSessionCreating', true)
334    this.mCaptureSession = this.mCameraManager.createCaptureSession();
335    GlobalContext.get().setObject('isSessionCreating', false)
336    Log.info(`${TAG} createSession captureSession: ${this.mCaptureSession}, cameraInput: ${this.mCameraInput},
337    videoOutPut: ${this.mVideoOutput}, photoOutPut: ${this.mPhotoOutPut},  mPreviewOutput: ${this.mPreviewOutput}`);
338    Log.info(`${TAG} createSession beginConfig.`);
339    Log.start(Log.STREAM_DISTRIBUTION);
340    try {
341      this.mCaptureSession?.beginConfig();
342      await new Promise((resolve) => setTimeout(resolve, 1));
343      Log.info(`${TAG} createSession addInput.`);
344      this.mCaptureSession?.addInput(this.mCameraInput);
345      if (!isVideo) {
346        Log.info(`${TAG} createSession photo addOutput.`);
347        this.mCaptureSession?.addOutput(this.mPhotoOutPut);
348      }
349      Log.info(`${TAG} createSession preview addOutput.`);
350      this.mCaptureSession?.addOutput(this.mPreviewOutput);
351    } catch (error) {
352      Log.error(`${TAG} createSession failed: ${JSON.stringify(error)}`);
353      if (error) {
354        EventLog.write(EventLog.CAMERA_ERROR);
355      }
356    }
357    Log.info(`${TAG} createSession commitConfig.`);
358    Log.start(Log.OPEN_CAMERA);
359    try {
360      await this.mCaptureSession?.commitConfig();
361      Log.end(Log.OPEN_CAMERA);
362      Log.end(Log.STREAM_DISTRIBUTION);
363      await this.mCaptureSession?.start();
364    } catch (err) {
365      if (err) {
366        EventLog.write(EventLog.OPEN_FAIL);
367      }
368    }
369    if (GlobalContext.get().getT<boolean>('cameraStartFlag') && (new Date().getTime() - GlobalContext.get().getT<number>('cameraStartTime')) > 2000) {
370      EventLog.write(EventLog.START_TIMEOUT);
371    }
372    GlobalContext.get().setObject('cameraStartFlag', false);
373    Log.end(`${TAG} createSession`);
374  }
375
376  public async releaseSession() {
377    Log.start(`${TAG} releaseSession`);
378    if (this.mCaptureSession) {
379      try {
380        await this.mCaptureSession.stop();
381        await this.mCaptureSession.release();
382        this.mCaptureSession = null;
383      } catch (error) {
384        Log.error(`${TAG} releaseSession failed: ${JSON.stringify(error)}`);
385        EventLog.writeFaultLog(error);
386      }
387    }
388    Log.end(`${TAG} releaseSession`);
389  }
390
391  public async startPreview() {
392    Log.start(`${TAG} startPreview`);
393    if (!this.mCaptureSession) {
394      return;
395    }
396    try {
397      await this.mCaptureSession.start();
398    } catch (error) {
399      Log.error(`${TAG} startPreview failed: ${JSON.stringify(error)}`);
400      EventLog.writeFaultLog(error);
401    }
402    Log.end(`${TAG} startPreview`);
403  }
404
405  public async stopPreview() {
406    Log.start(`${TAG} stopPreview`);
407    if (!this.mCaptureSession) {
408      return;
409    }
410    try {
411      await this.mCaptureSession.stop();
412    } catch (error) {
413      Log.error(`${TAG} stopPreview failed: ${JSON.stringify(error)}`);
414      EventLog.writeFaultLog(error);
415    }
416    Log.end(`${TAG} stopPreview`);
417  }
418
419  public async takePicture() {
420    Log.start(`${TAG} takePicture`);
421    EventLog.write(EventLog.CAPTURE);
422    if (!this.mCaptureSession) {
423      Log.info(`${TAG} takePicture session is release`);
424      return;
425    }
426    if (!this.mPhotoOutPut) {
427      Log.info(`${TAG} takePicture photoOutPut is release`);
428      return;
429    }
430    if (this.mCameraId === CameraId.FRONT) {
431      this.mCaptureSetting.mirror = SettingManager.getInstance().getSelfMirror();
432    }
433    const locationData = SettingManager.getInstance().getCurGeoLocation();
434    if (locationData) {
435      this.mCaptureSetting.location = {
436        latitude: locationData.latitude,
437        longitude: locationData.longitude,
438        altitude: locationData.altitude
439      }
440    }
441    Log.info(`${TAG} takePicture captureSetting ${JSON.stringify(this.mCaptureSetting)}`);
442    // todo modify the location and mirror config
443    try {
444      this.mPhotoOutPut.capture(this.mCaptureSetting);
445    } catch (err) {
446      if (err) {
447        EventLog.write(EventLog.CAPTURE_FAIL);
448      }
449    }
450    Log.end(`${TAG} takePicture`);
451    if ((new Date().getTime() - GlobalContext.get().getT<number>('startCaptureTime')) > 2000) {
452      EventLog.write(EventLog.CAPTURE_TIMEOUT);
453    }
454  }
455
456  public async createVideoOutput(functionCallBack: VideoCallBack) {
457    Log.start(`${TAG} createVideoOutput`);
458    this.mFileAssetId = await this.mSaveCameraAsset.createVideoFd(functionCallBack);
459    if (this.mFileAssetId === undefined) {
460      Log.error(`${TAG} createVideoOutput error: mFileAssetId undefined`);
461      functionCallBack.onRecodeError('createVideoOutput error: mFileAssetId undefined');
462    }
463    this.mVideoConfig.url = `fd://${this.mFileAssetId.toString()}`;
464    await media.createAVRecorder().then((recorder) => {
465      Log.info(`${TAG} createVideoOutput createAVRecorder record: ${recorder}`);
466      this.mAVRecorder = recorder;
467    });
468    const size = SettingManager.getInstance().getVideoSize();
469    if (this.mAVRecorder != null) {
470      this.mAVRecorder.on('error', (error) => {
471        if (error) {
472          Log.error(`${TAG} createVideoOutput error: ${JSON.stringify(error)}`);
473          functionCallBack.onRecodeError(`createVideoOutput error: ${JSON.stringify(error)}`);
474        }
475      });
476      Log.info(`${TAG} createVideoOutput size = ${JSON.stringify(size)}`);
477      this.mVideoConfig.profile.videoFrameWidth = size.width;
478      this.mVideoConfig.profile.videoFrameHeight = size.height;
479      const locationData = SettingManager.getInstance().getCurGeoLocation();
480      if (locationData) {
481        this.mVideoConfig.location = {
482          latitude: locationData.latitude,
483          longitude: locationData.longitude
484        };
485      }
486
487      if (deviceInfo.deviceType != 'tablet') {
488        if (this.curCameraName === 'BACK') {
489          this.mVideoConfig.rotation = 90;
490        } else {
491          this.mVideoConfig.rotation = 270;
492        }
493      }
494      Log.info(`${TAG} createVideoOutput mVideoConfig =  ${JSON.stringify(this.mVideoConfig)}.`);
495      await this.mAVRecorder.prepare(this.mVideoConfig);
496      Log.info(`${TAG} createVideoOutput AVRecorder.prepare succeed.`);
497    } else {
498      Log.error(`${TAG} createVideoOutput createAVRecorder failed.`);
499      return;
500    }
501
502    let profileVideo;
503    if (deviceInfo.deviceType == 'default') {
504      profileVideo = this.outputCapability.videoProfiles[0];
505    } else {
506      let videoProfiles = this.outputCapability.videoProfiles;
507      Log.info(`${TAG} videoProfiles length.` + videoProfiles.length);
508      profileVideo = videoProfiles.find(item =>
509      item.size.width === size.width && item.size.height === size.height
510      && item.frameRateRange.min === DEFAULT_VIDEO_FRAME_RATE && item.frameRateRange.max === DEFAULT_VIDEO_FRAME_RATE
511      );
512    }
513
514    const videoId = await this.mAVRecorder.getInputSurface();
515    Log.info(`${TAG} createVideoOutput profileVideo =  ${JSON.stringify(profileVideo)}.`);
516    try {
517      this.mVideoOutput = this.mCameraManager.createVideoOutput(profileVideo, videoId);
518    } catch (error) {
519      Log.error(`${TAG} createVideoOutput failed: ${JSON.stringify(error)}`);
520      EventLog.writeFaultLog(error);
521    }
522    Log.end(`${TAG} createVideoOutput`);
523  }
524
525  public async releaseVideoOutput() {
526    Log.start(`${TAG} releaseVideoOutput`);
527    if (this.mVideoOutput) {
528      Log.info(`${TAG} releaseVideoOutput start`);
529      try {
530        await this.mVideoOutput.release();
531      } catch (error) {
532        Log.error(`${TAG} releaseVideoOutput failed: ${JSON.stringify(error)}`);
533        EventLog.writeFaultLog(error);
534      }
535      Log.info(`${TAG} releaseVideoOutput end`);
536      this.mVideoOutput = null;
537    }
538    Log.end(`${TAG} releaseVideoOutput`);
539  }
540
541  public async StartRecording(functionCallBack: VideoCallBack) {
542    let startRecordingTime = new Date().getTime();
543    Log.start(`${TAG} StartRecording`);
544    Log.info(`${TAG} StartRecording codec ${this.mVideoConfig.profile.videoCodec}`);
545    EventLog.write(EventLog.VIDEO_RECORD);
546    try {
547      await this.mCaptureSession.stop();
548      this.mCaptureSession.beginConfig();
549      if (this.mVideoOutput) {
550        await this.mCaptureSession.removeOutput(this.mVideoOutput);
551        Log.info(`${TAG} old videoOutput has been removed.`);
552      }
553      await this.createVideoOutput(functionCallBack);
554      this.mCaptureSession.addOutput(this.mVideoOutput);
555      Log.info(`${TAG} StartRecording addOutput finished.`);
556      await this.mCaptureSession.commitConfig();
557      Log.info(`${TAG} StartRecording commitConfig finished.`);
558      await this.mCaptureSession.start();
559      Log.info(`${TAG} StartRecording Session.start finished.`);
560    } catch (err) {
561      GlobalContext.get().setObject('startRecordingFlag', false);
562      EventLog.writeFaultLog(error);
563      Log.error(`${TAG} remove videoOutput ${err}`);
564    }
565    await this.mVideoOutput.start().then(() => {
566      Log.info(`${TAG} videoOutput.start()`);
567    });
568    await this.mAVRecorder.start().then(() => {
569      Log.info(`${TAG} AVRecorder.start()`);
570    });
571    this.mIsStartRecording = true;
572    if (new Date().getTime() - startRecordingTime > 2000) {
573      EventLog.write(EventLog.START_RECORD_TIMEOUT);
574    }
575    Log.end(`${TAG} StartRecording`);
576  }
577
578  public async stopRecording(): Promise<PixelMap | undefined> {
579    Log.start(Log.STOP_RECORDING);
580    let stopRecordingTime = new Date().getTime();
581    EventLog.write(EventLog.STOP_RECORD);
582    if (!this.mVideoOutput || !this.mAVRecorder) {
583      Log.error(`${TAG} stopRecording error videoOutPut: ${this.mVideoOutput},
584              AVRecorder: ${this.mAVRecorder} .`);
585      return undefined;
586    }
587    this.mIsStartRecording = false;
588    try {
589      await this.mAVRecorder.stop();
590      await this.mAVRecorder.release();
591    } catch (err) {
592      Log.error(`${TAG} stop AVRecorder ${err}`);
593    }
594
595    try {
596      await this.mVideoOutput.stop();
597    } catch (err) {
598      Log.error(`${TAG} stop videoOutput ${err}`);
599    }
600
601    if (this.mFileAssetId != undefined) {
602      await this.mSaveCameraAsset.videoPrepareFile.close(this.mFileAssetId);
603      this.mFileAssetId = undefined;
604      Log.info(`${TAG} fileAsset.close().`);
605    }
606    Log.start(Log.UPDATE_VIDEO_THUMBNAIL);
607    const thumbnailPixelMap: PixelMap | undefined = await this.mThumbnailGetter.getThumbnailInfo(40, 40);
608    Log.end(Log.UPDATE_VIDEO_THUMBNAIL);
609    if (new Date().getTime() - stopRecordingTime > 2000) {
610      EventLog.write(EventLog.FINISH_RECORD_TIMEOUT);
611    }
612    Log.end(Log.STOP_RECORDING);
613    return thumbnailPixelMap;
614  }
615
616  public async pauseRecording() {
617    Log.start(`${TAG} pauseRecording`);
618    if (!this.mVideoOutput || !this.mAVRecorder) {
619      Log.error(`${TAG} pauseRecording error videoOutPut: ${this.mVideoOutput},
620              AVRecorder: ${this.mAVRecorder} .`);
621      return;
622    }
623    try {
624      await this.mAVRecorder.pause();
625      await this.mVideoOutput.stop();
626    } catch (error) {
627      Log.error(`${TAG} pauseRecording failed: ${JSON.stringify(error)}`);
628    }
629    Log.end(`${TAG} pauseRecording`);
630  }
631
632  public async resumeRecording() {
633    Log.start(`${TAG} resumeRecording`);
634    if (!this.mVideoOutput || !this.mAVRecorder) {
635      Log.error(`${TAG} resumeRecording error videoOutPut: ${this.mVideoOutput},
636              AVRecorder: ${this.mAVRecorder} .`);
637      return;
638    }
639    await this.mVideoOutput.start().then(() => {
640      Log.info(`${TAG} videoOutput.start()`);
641    }).catch((error) => {
642      Log.error(`${TAG} resumeRecording mVideoOutput start failed: ${JSON.stringify(error)}`);
643    });
644    await this.mAVRecorder.resume();
645    Log.end(`${TAG} resumeRecording`);
646  }
647
648  public async releaseRecording() {
649    Log.start(`${TAG} releaseRecording`);
650    if (!this.mAVRecorder) {
651      Log.info(`${TAG} AVRecorder has not been created.`);
652      return;
653    }
654    if (this.mIsStartRecording) {
655      await this.stopRecording();
656    }
657    await this.mAVRecorder.release().then(() => {
658      Log.info(`${TAG} AVRecorder.release() success.`);
659      this.mAVRecorder = undefined;
660    });
661    Log.end(`${TAG} releaseRecording`);
662  }
663
664  public async releaseCamera() {
665    Log.start(`${TAG} releaseCamera`);
666    await this.releaseRecording();
667    await this.releaseVideoOutput();
668    await this.releasePhotoOutput();
669    await this.releaseSession();
670    Log.end(`${TAG} releaseCamera`);
671  }
672
673  public async setZoomRatio(zoomRatio: number) {
674    Log.info(`${TAG} setZoomRatio invoke E ${zoomRatio}`);
675    if (!this.mCaptureSession) {
676      Log.info(`${TAG} setZoomRatio mCaptureSession is release`);
677      return;
678    }
679    try {
680      this.mCaptureSession.setZoomRatio(zoomRatio);
681    } catch (error) {
682      Log.error(`${TAG} setZoomRatio failed: ${JSON.stringify(error)}`);
683    }
684    Log.info(`${TAG} setZoomRatio invoke X.`);
685  }
686
687  public async getZoomRatio(): Promise<number> {
688    Log.info(`${TAG} getZoomRatio invoke E.`);
689    if (!this.mCaptureSession) {
690      Log.info(`${TAG} getZoomRatio mCaptureSession is release`);
691      return 1;
692    }
693    Log.info(`${TAG} getZoomRatio invoke X.`);
694    return this.mCaptureSession.getZoomRatio();
695  }
696
697  public async setVideoConfig(videoConfig: any) {
698    Log.info(`${TAG} setVideoConfig invoke E.`);
699    if (videoConfig) {
700      this.mVideoConfig = videoConfig;
701    } else {
702      Log.info(`${TAG} setVideoConfig videoConfig is null.`);
703    }
704    Log.info(`${TAG} setVideoConfig invoke X.`);
705  }
706
707  public async setCaptureSetting(captureSetting: any) {
708    Log.info(`${TAG} setCaptureSetting invoke E.`);
709    if (captureSetting) {
710      this.mCaptureSetting = captureSetting;
711    } else {
712      Log.info(`${TAG} setCaptureSetting captureSetting is null.`);
713    }
714    Log.debug(`${TAG} setCaptureSetting invoke X.`);
715  }
716
717  public getThumbnail(functionCallBack: FunctionCallBack): image.PixelMap {
718    Log.start(`${TAG} getThumbnail`);
719    this.mThumbnailGetter.getThumbnailInfo(40, 40).then((thumbnail) => {
720      functionCallBack.thumbnail(thumbnail);
721      Log.end(`${TAG} getThumbnail`);
722    });
723    return this.mThumbnail;
724  }
725
726  public getCameraName(): string {
727    return this.curCameraName;
728  }
729
730  public setCameraId(name: string): void {
731    this.curCameraName = name;
732  }
733
734  public getPhotoUri() {
735    return this.mSaveCameraAsset.getPhotoUri();
736  }
737
738  public getRecentFileUri(): string {
739    return this.mThumbnailGetter.getRecentFileUri();
740  }
741
742  private async getCameraLists() {
743    const cameras = this.mCameraManager.getSupportedCameras();
744    this.camerasCache = cameras;
745    return cameras;
746  }
747}