1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef AV_PLAYER_NAPI_H
17 #define AV_PLAYER_NAPI_H
18 
19 #include <shared_mutex>
20 #include "player.h"
21 #include "media_errors.h"
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24 #include "avplayer_callback.h"
25 #include "media_data_source_callback.h"
26 #include "common_napi.h"
27 #include "audio_info.h"
28 #include "audio_effect.h"
29 #include "task_queue.h"
30 
31 namespace OHOS {
32 namespace Media {
33 namespace AVPlayerState {
34 const std::string STATE_IDLE = "idle";
35 const std::string STATE_INITIALIZED = "initialized";
36 const std::string STATE_PREPARED = "prepared";
37 const std::string STATE_PLAYING = "playing";
38 const std::string STATE_PAUSED = "paused";
39 const std::string STATE_STOPPED = "stopped";
40 const std::string STATE_RELEASED = "released";
41 const std::string STATE_ERROR = "error";
42 const std::string STATE_COMPLETED = "completed";
43 }
44 
45 namespace AVPlayerEvent {
46 const std::string EVENT_STATE_CHANGE = "stateChange";
47 const std::string EVENT_VOLUME_CHANGE = "volumeChange";
48 const std::string EVENT_END_OF_STREAM = "endOfStream";
49 const std::string EVENT_SEEK_DONE = "seekDone";
50 const std::string EVENT_SPEED_DONE = "speedDone";
51 const std::string EVENT_BITRATE_DONE = "bitrateDone";
52 const std::string EVENT_TIME_UPDATE = "timeUpdate";
53 const std::string EVENT_DURATION_UPDATE = "durationUpdate";
54 const std::string EVENT_SUBTITLE_TEXT_UPDATE = "subtitleTextUpdate";
55 const std::string EVENT_BUFFERING_UPDATE = "bufferingUpdate";
56 const std::string EVENT_START_RENDER_FRAME = "startRenderFrame";
57 const std::string EVENT_VIDEO_SIZE_CHANGE = "videoSizeChange";
58 const std::string EVENT_AUDIO_INTERRUPT = "audioInterrupt";
59 const std::string EVENT_AVAILABLE_BITRATES = "availableBitrates";
60 const std::string EVENT_TRACKCHANGE = "trackChange";
61 const std::string EVENT_TRACK_INFO_UPDATE = "trackInfoUpdate";
62 const std::string EVENT_DRM_INFO_UPDATE = "mediaKeySystemInfoUpdate";
63 const std::string EVENT_SET_DECRYPT_CONFIG_DONE = "setDecryptConfigDone";
64 const std::string EVENT_AUDIO_DEVICE_CHANGE = "audioOutputDeviceChangeWithInfo";
65 const std::string EVENT_SUBTITLE_UPDATE = "subtitleUpdate";
66 const std::string EVENT_ERROR = "error";
67 const std::string EVENT_AMPLITUDE_UPDATE = "amplitudeUpdate";
68 }
69 
70 using TaskRet = std::pair<int32_t, std::string>;
71 
72 class AVPlayerNapi : public AVPlayerNotify {
73 public:
74     __attribute__((visibility("default"))) static napi_value Init(napi_env env, napi_value exports);
75 
76 private:
77     static napi_value Constructor(napi_env env, napi_callback_info info);
78     static void Destructor(napi_env env, void *nativeObject, void *finalize);
79     /**
80      * createAVPlayer(callback: AsyncCallback<VideoPlayer>): void
81      * createAVPlayer(): Promise<VideoPlayer>
82      */
83     static napi_value JsCreateAVPlayer(napi_env env, napi_callback_info info);
84     /**
85      * prepare(callback: AsyncCallback<void>): void
86      * prepare(): Promise<void>
87      */
88     static napi_value JsPrepare(napi_env env, napi_callback_info info);
89     /**
90      * play(callback: AsyncCallback<void>): void
91      * play(): Promise<void>
92      */
93     static napi_value JsPlay(napi_env env, napi_callback_info info);
94     /**
95      * pause(callback: AsyncCallback<void>): void
96      * pause(): Promise<void>
97      */
98     static napi_value JsPause(napi_env env, napi_callback_info info);
99     /**
100      * stop(callback: AsyncCallback<void>): void
101      * stop(): Promise<void>
102      */
103     static napi_value JsStop(napi_env env, napi_callback_info info);
104     /**
105      * reset(callback: AsyncCallback<void>): void
106      * reset(): Promise<void>
107      */
108     static napi_value JsReset(napi_env env, napi_callback_info info);
109     /**
110      * release(callback: AsyncCallback<void>): void
111      * release(): Promise<void>
112      */
113     static napi_value JsRelease(napi_env env, napi_callback_info info);
114     /**
115      * seek(timeMs: number, mode?:SeekMode): void
116      */
117     static napi_value JsSeek(napi_env env, napi_callback_info info);
118     /**
119      * setPlayRange(startTimeMs: number, endTimeMs: number, mode?: SeekMode): void
120      */
121     static napi_value JsSetPlaybackRange(napi_env env, napi_callback_info info);
122     /**
123      * setSpeed(speed: number): void
124      */
125     static napi_value JsSetSpeed(napi_env env, napi_callback_info info);
126     /**
127      * setVolume(vol: number): void
128      */
129     static napi_value JsSetVolume(napi_env env, napi_callback_info info);
130     /**
131      * selectBitrate(bitRate: number): void
132      */
133     static napi_value JsSelectBitrate(napi_env env, napi_callback_info info);
134     /**
135      * addSubtitleUrl: string
136      */
137     static napi_value JsAddSubtitleUrl(napi_env env, napi_callback_info info);
138     /**
139      * addSubtitleFdSrc: AVFileDescriptor
140      */
141     static napi_value JsAddSubtitleAVFileDescriptor(napi_env env, napi_callback_info info);
142     /**
143      * url: string
144      */
145     static napi_value JsSetUrl(napi_env env, napi_callback_info info);
146     static napi_value JsGetUrl(napi_env env, napi_callback_info info);
147     /**
148      * fdSrc: AVFileDescriptor
149      */
150     static napi_value JsGetAVFileDescriptor(napi_env env, napi_callback_info info);
151     static napi_value JsSetAVFileDescriptor(napi_env env, napi_callback_info info);
152     /**
153      * dataSrc: DataSrcDescriptor
154      */
155     static napi_value JsSetDataSrc(napi_env env, napi_callback_info info);
156     static napi_value JsGetDataSrc(napi_env env, napi_callback_info info);
157     /**
158      * surfaceId?: string
159      */
160     static napi_value JsSetSurfaceID(napi_env env, napi_callback_info info);
161     static napi_value JsGetSurfaceID(napi_env env, napi_callback_info info);
162     /**
163      * loop: boolenan
164      */
165     static napi_value JsSetLoop(napi_env env, napi_callback_info info);
166     static napi_value JsGetLoop(napi_env env, napi_callback_info info);
167     /**
168      * videoScaleType?: VideoScaleType
169      */
170     static napi_value JsSetVideoScaleType(napi_env env, napi_callback_info info);
171     static napi_value JsGetVideoScaleType(napi_env env, napi_callback_info info);
172     /**
173      * audioInterruptMode?: audio.AudioInterruptMode
174      */
175     static napi_value JsGetAudioInterruptMode(napi_env env, napi_callback_info info);
176     static napi_value JsSetAudioInterruptMode(napi_env env, napi_callback_info info);
177 
178     /**
179      * audioRendererInfo?: audio.AudioRendererInfo
180      */
181     static napi_value JsGetAudioRendererInfo(napi_env env, napi_callback_info info);
182     static napi_value JsSetAudioRendererInfo(napi_env env, napi_callback_info info);
183 
184     /**
185      * audioEffectMode ?: audio.AudioEffectMode;
186      */
187     static napi_value JsGetAudioEffectMode(napi_env env, napi_callback_info info);
188     static napi_value JsSetAudioEffectMode(napi_env env, napi_callback_info info);
189     /**
190      * readonly currentTime: number
191      */
192     static napi_value JsGetCurrentTime(napi_env env, napi_callback_info info);
193     /**
194      * readonly duration: number
195      */
196     static napi_value JsGetDuration(napi_env env, napi_callback_info info);
197     /**
198      * readonly state: AVPlayState
199      */
200     static napi_value JsGetState(napi_env env, napi_callback_info info);
201     /**
202      * readonly width: number
203      */
204     static napi_value JsGetWidth(napi_env env, napi_callback_info info);
205     /**
206      * readonly height: number
207      */
208     static napi_value JsGetHeight(napi_env env, napi_callback_info info);
209     /**
210      * getTrackDescription(callback:AsyncCallback<Array<MediaDescription>>): void
211      * getTrackDescription(): Promise<Array<MediaDescription>>
212      */
213     static napi_value JsGetTrackDescription(napi_env env, napi_callback_info info);
214     /**
215      * JsGetSelectedTracks(callback:AsyncCallback<Array<number>>): void
216      * JsGetSelectedTracks(): Promise<Array<number>>
217      */
218     static napi_value JsGetSelectedTracks(napi_env env, napi_callback_info info);
219     /**
220      * selectTrack(index: number, mode?: SwitchMode): void;
221      */
222     static napi_value JsSelectTrack(napi_env env, napi_callback_info info);
223     /**
224      * deselectTrack(index: number): void;
225      */
226     static napi_value JsDeselectTrack(napi_env env, napi_callback_info info);
227     /**
228      * GetCurrentTrack(trackType: MediaType, callback: AsyncCallback<number>): void;
229      * GetCurrentTrack(trackType: MediaType): Promise<number>;
230      */
231     static napi_value JsGetCurrentTrack(napi_env env, napi_callback_info info);
232     /**
233      * setDecryptionConfig(mediaKeySession: drm.MediaKeySession, secureVideoPath: boolean): void;
234      */
235     static napi_value JsSetDecryptConfig(napi_env env, napi_callback_info info);
236 
237     static napi_value JsSetMediaSource(napi_env env, napi_callback_info info);
238     /**
239      * getMediaKeySystemInfos(): Array<MediaKeySystemInfo>;
240      */
241     static napi_value JsGetMediaKeySystemInfos(napi_env env, napi_callback_info info);
242 
243     static napi_value JsSetPlaybackStrategy(napi_env env, napi_callback_info info);
244 
245     static napi_value JsSetMediaMuted(napi_env env, napi_callback_info info);
246 
247     /**
248      * getPlaybackInfo(): playbackInfo;
249      */
250     static napi_value JsGetPlaybackInfo(napi_env env, napi_callback_info info);
251 
252     static napi_value JsIsSeekContinuousSupported(napi_env env, napi_callback_info info);
253 
254     /**
255      * on(type: 'stateChange', callback: (state: AVPlayerState, reason: StateChangeReason) => void): void;
256      * off(type: 'stateChange'): void;
257      * on(type: 'volumeChange', callback: Callback<number>): void;
258      * off(type: 'volumeChange'): void;
259      * on(type: 'endOfStream', callback: Callback<void>): void;
260      * off(type: 'endOfStream'): void;
261      * on(type: 'seekDone', callback: Callback<number>): void;
262      * off(type: 'seekDone'): void;
263      * on(type: 'speedDone', callback: Callback<number>): void;
264      * off(type: 'speedDone'): void;
265      * on(type: 'bitrateDone', callback: Callback<number>): void;
266      * off(type: 'bitrateDone'): void;
267      * on(type: 'timeUpdate', callback: Callback<number>): void;
268      * off(type: 'timeUpdate'): void;
269      * on(type: 'durationUpdate', callback: Callback<number>): void;
270      * off(type: 'durationUpdate'): void;
271      * on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void;
272      * off(type: 'bufferingUpdate'): void;
273      * on(type: 'startRenderFrame', callback: Callback<void>): void;
274      * off(type: 'startRenderFrame'): void;
275      * on(type: 'videoSizeChange', callback: (width: number, height: number) => void): void;
276      * off(type: 'videoSizeChange'): void;
277      * on(type: 'audioInterrupt', callback: (info: audio.InterruptEvent) => void): void;
278      * off(type: 'audioInterrupt'): void;
279      * on(type: 'availableBitrates', callback: (bitrates: Array<number>) => void): void;
280      * off(type: 'availableBitrates'): void;
281      * on(type: 'error', callback: ErrorCallback): void;
282      * off(type: 'error'): void;
283      * on(type: 'mediaKeySystemInfoUpdate', callback: (mediaKeySystemInfo: Array<MediaKeySystemInfo>) => void): void;
284      * off(type: 'mediaKeySystemInfoUpdate'): void;
285      */
286     static napi_value JsSetOnCallback(napi_env env, napi_callback_info info);
287     static napi_value JsClearOnCallback(napi_env env, napi_callback_info info);
288 
289     static AVPlayerNapi* GetJsInstance(napi_env env, napi_callback_info info);
290     static AVPlayerNapi* GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
291         size_t &argc, napi_value *argv);
292     static bool JsHandleParameter(napi_env env, napi_value args, AVPlayerNapi *jsPlayer);
293     static void SeekEnqueueTask(AVPlayerNapi *jsPlayer, int32_t time, int32_t mode);
294     static void SelectTrackEnqueueTask(AVPlayerNapi *jsPlayer, int32_t index, int32_t mode);
295     AVPlayerNapi();
296     ~AVPlayerNapi() override;
297     void SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref);
298     void ClearCallbackReference();
299     void ClearCallbackReference(const std::string &callbackName);
300     void StartListenCurrentResource();
301     void PauseListenCurrentResource();
302     void QueueOnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg);
303     void OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg);
304     void SetSource(std::string url);
305     void AddSubSource(std::string url);
306     void SetSurface(const std::string &surfaceStr);
307     void ResetUserParameters();
308 
309     std::shared_ptr<TaskHandler<TaskRet>> PrepareTask();
310     std::shared_ptr<TaskHandler<TaskRet>> PlayTask();
311     std::shared_ptr<TaskHandler<TaskRet>> PauseTask();
312     std::shared_ptr<TaskHandler<TaskRet>> StopTask();
313     std::shared_ptr<TaskHandler<TaskRet>> ResetTask();
314     std::shared_ptr<TaskHandler<TaskRet>> ReleaseTask();
315     std::shared_ptr<TaskHandler<TaskRet>> SetPlaybackStrategyTask(AVPlayStrategy playStrategy);
316     std::shared_ptr<TaskHandler<TaskRet>> SetMediaMutedTask(MediaType type, bool isMuted);
317     std::shared_ptr<TaskHandler<TaskRet>> EqueueSetPlayRangeTask(int32_t start, int32_t end, int32_t mode);
318 
319     std::string GetCurrentState();
320     bool IsControllable();
321     bool CanSetPlayRange();
322     bool IsLiveSource() const;
323     void EnqueueNetworkTask(const std::string url);
324     void EnqueueFdTask(const int32_t fd);
325 
326     PlayerSeekMode TransferSeekMode(int32_t mode);
327     PlayerSwitchMode TransferSwitchMode(int32_t mode);
328 
329     void NotifyDuration(int32_t duration) override;
330     void NotifyPosition(int32_t position) override;
331     void NotifyState(PlayerStates state) override;
332     void NotifyVideoSize(int32_t width, int32_t height) override;
333     void NotifyIsLiveStream() override;
334     void NotifyDrmInfoUpdated(const std::multimap<std::string, std::vector<uint8_t>> &infos) override;
335     void StopTaskQue();
336     void WaitTaskQueStop();
337     void MaxAmplitudeCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName);
338     void MaxAmplitudeCallbackOff(AVPlayerNapi *jsPlayer, std::string callbackName);
339     void DeviceChangeCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName);
340     void DeviceChangeCallbackOff(AVPlayerNapi *jsPlayer, std::string callbackName);
341 
342     std::condition_variable stopTaskQueCond_;
343     bool taskQueStoped_ = false;
344     bool calMaxAmplitude_ = false;
345     bool deviceChangeCallbackflag_ = false;
346 
347     struct AVPlayerContext : public MediaAsyncContext {
AVPlayerContextAVPlayerContext348         explicit AVPlayerContext(napi_env env) : MediaAsyncContext(env) {}
349         ~AVPlayerContext() = default;
350         void CheckTaskResult(bool isTimeLimited = false, uint32_t milliseconds = 0)
351         {
352             if (asyncTask != nullptr) {
353                 auto result = isTimeLimited ? asyncTask->GetResultWithTimeLimit(milliseconds) : asyncTask->GetResult();
354                 if (result.HasResult() && result.Value().first != MSERR_EXT_API9_OK) {
355                     SignError(result.Value().first, result.Value().second);
356                 }
357             }
358         }
359         std::shared_ptr<TaskHandler<TaskRet>> asyncTask = nullptr;
360         AVPlayerNapi *napi = nullptr;
361         std::vector<Format> trackInfoVec_;
362     };
363     std::shared_ptr<TaskHandler<TaskRet>> GetTrackDescriptionTask(const std::unique_ptr<AVPlayerContext> &promiseCtx);
364     void GetCurrentTrackTask(std::unique_ptr<AVPlayerContext> &promiseCtx, napi_env env, napi_value args);
365     static thread_local napi_ref constructor_;
366     napi_env env_ = nullptr;
367     std::shared_ptr<Player> player_ = nullptr;
368     std::shared_ptr<AVPlayerCallback> playerCb_ = nullptr;
369     std::shared_ptr<MediaDataSourceCallback> dataSrcCb_ = nullptr;
370     std::atomic<bool> isReleased_ = false;
371     std::atomic<bool> isInterrupted_ = false;
372     std::string url_ = "";
373     struct AVFileDescriptor fileDescriptor_;
374     struct AVDataSrcDescriptor dataSrcDescriptor_;
375     std::string surface_ = "";
376     bool loop_ = false;
377     int32_t videoScaleType_ = 0;
378     std::vector<Format> trackInfoVec_;
379     OHOS::AudioStandard::InterruptMode interruptMode_ = AudioStandard::InterruptMode::SHARE_MODE;
380     OHOS::AudioStandard::AudioRendererInfo audioRendererInfo_ = OHOS::AudioStandard::AudioRendererInfo {
381         OHOS::AudioStandard::ContentType::CONTENT_TYPE_MUSIC,
382         OHOS::AudioStandard::StreamUsage::STREAM_USAGE_MEDIA,
383         0
384     };
385     int32_t audioEffectMode_ = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
386     std::unique_ptr<TaskQueue> taskQue_;
387     std::mutex mutex_;
388     std::mutex taskMutex_;
389     std::map<std::string, std::shared_ptr<AutoRef>> refMap_;
390     PlayerStates state_ = PLAYER_IDLE;
391     std::condition_variable stateChangeCond_;
392     std::atomic<bool> stopWait_;
393     bool avplayerExit_ = false;
394     int32_t width_ = 0;
395     int32_t height_ = 0;
396     int32_t position_ = -1;
397     int32_t duration_ = -1;
398     bool isLiveStream_ = false;
399     std::shared_mutex drmMutex_{};
400     std::multimap<std::string, std::vector<uint8_t>> localDrmInfos_;
401     Format playbackInfo_;
402 };
403 } // namespace Media
404 } // namespace OHOS
405 #endif // AV_PLAYER_NAPI_H