Skip to content

Commit 28489bf

Browse files
authored
fix: 修改openSync之后没有closeSync导致内存泄漏问题 (#31)
1 parent 854c23a commit 28489bf

File tree

2 files changed

+68
-39
lines changed

2 files changed

+68
-39
lines changed

harmony/sound/src/main/ets/AVPlayerController.ts

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ import { wantAgent, WantAgent } from '@kit.AbilityKit';
3131
import { AbilityConstant, Want } from '@kit.AbilityKit';
3232
import fs from '@ohos.file.fs';
3333
import Logger from './Logger';
34-
import { AVAudioSessionCategory, AvplayerStatus,AvplayerSessionCategory } from './ts';
34+
import { AVAudioSessionCategory, AvplayerStatus, AvplayerSessionCategory } from './ts';
35+
3536
const TAG: string = "[RNOH] Sound"
3637

3738
export interface PrepareProps {
@@ -44,7 +45,7 @@ interface E {
4445
message: string
4546
}
4647

47-
enum Speed{
48+
enum Speed {
4849
ZERO = 0,
4950
ONE = 1,
5051
TWO = 2,
@@ -56,9 +57,10 @@ export class AVPlayerController {
5657
private audioManager = audio.getAudioManager();
5758
public playerPool = new Map<Object, media.AVPlayer>();
5859
public isPlaying: boolean = false;
59-
private category:AVAudioSessionCategory = "Playback";
60-
private mixWithOthers:Boolean = true;
60+
private category: AVAudioSessionCategory = "Playback";
61+
private mixWithOthers: Boolean = true;
6162
private context = getContext(this);
63+
private previousSrc: fs.File | string | undefined = undefined
6264

6365
//创建后台长任务
6466
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
@@ -83,7 +85,7 @@ export class AVPlayerController {
8385
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
8486
try {
8587
backgroundTaskManager.startBackgroundRunning(this.context,
86-
backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj, (error: BusinessError, data: void)=>{
88+
backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj, (error: BusinessError, data: void) => {
8789

8890
})
8991
} catch (error) {
@@ -99,13 +101,13 @@ export class AVPlayerController {
99101
// 创建session
100102
async createSession() {
101103
let type: AVSessionManager.AVSessionType = 'audio';
102-
let session = await AVSessionManager.createAVSession(this.context,'SESSION_NAME', type);
104+
let session = await AVSessionManager.createAVSession(this.context, 'SESSION_NAME', type);
103105

104106
// 激活接口要在元数据、控制命令注册完成之后再执行
105107
await session.activate();
106108
}
107109

108-
setAudioRendererInfo(mediaPlayer: media.AVPlayer){
110+
setAudioRendererInfo(mediaPlayer: media.AVPlayer) {
109111
if (this.category != null) {
110112
switch (this.category) {
111113
case AvplayerSessionCategory.AMBIENT: //游戏模式
@@ -131,13 +133,13 @@ export class AVPlayerController {
131133
}
132134
}
133135

134-
mediaPrepare(mediaPlayer: media.AVPlayer, callBack: (error: E | null, props:PrepareProps | null) => void){
135-
mediaPlayer.prepare().then(()=>{
136-
const props:PrepareProps = {
137-
duration:mediaPlayer.duration,
136+
mediaPrepare(mediaPlayer: media.AVPlayer, callBack: (error: E | null, props: PrepareProps | null) => void) {
137+
mediaPlayer.prepare().then(() => {
138+
const props: PrepareProps = {
139+
duration: mediaPlayer.duration,
138140
}
139141
callBack(null, props);
140-
},(err: BusinessError)=>{
142+
}, (err: BusinessError) => {
141143
const e: E = {
142144
code: -1,
143145
message: `avPlay prepare error:${err.name} message ${err.message}}`
@@ -146,31 +148,55 @@ export class AVPlayerController {
146148
});
147149
}
148150

149-
async prepare(fileName: string, key: number, option: object, callBack: (error: E | null, props:PrepareProps | null) => void) {
151+
closeFsRawFd() {
152+
if (typeof this.previousSrc === "string") {
153+
try {
154+
this.context.resourceManager.closeRawFdSync(this.previousSrc);
155+
Logger.debug(TAG, `aboutToDisappear, closeRawFd file succeed`);
156+
} catch (error) {
157+
Logger.debug(TAG,`aboutToDisappear, closeRawFd error is${error.message} error code:${error.code}`);
158+
}
159+
} else if (typeof this.previousSrc === "object") {
160+
try{
161+
fs.closeSync(this.previousSrc)
162+
Logger.debug(TAG, `aboutToDisappear, close file succeed`);
163+
} catch (error) {
164+
Logger.debug(TAG, `aboutToDisappear, close file failed with error message:${error.message},error code:${error.code}`);
165+
}
166+
}
167+
}
168+
169+
170+
async prepare(fileName: string, key: number, option: object,
171+
callBack: (error: E | null, props: PrepareProps | null) => void) {
172+
this.closeFsRawFd()
150173
const mediaPlayer: media.AVPlayer = await media.createAVPlayer();
151174
let fileUrl: string = '';
152-
if(fileName.startsWith('asset')){ //在npm run dev起服务的时候 用require('./frog.wav') 引入的文件
175+
if (fileName.startsWith('asset')) { //在npm run dev起服务的时候 用require('./frog.wav') 引入的文件
153176
fileUrl = fileName.split('//')[1];
154177
let fileDescriptor = await this.context.resourceManager.getRawFd(`assets/${fileUrl}`);
178+
this.previousSrc = `assets/${fileUrl}`
155179
mediaPlayer.fdSrc = fileDescriptor;
156-
} else if(fileName.startsWith("http://") || fileName.startsWith("https://")){//音频资源是网络资源和npm run start起服务的时候 用require('./frog.wav') 引入的文件
180+
} else if (fileName.startsWith("http://") ||
181+
fileName.startsWith("https://")) { //音频资源是网络资源和npm run start起服务的时候 用require('./frog.wav') 引入的文件
157182
mediaPlayer.url = fileName;
158-
} else if (fileName.startsWith('/data')){
159-
let resFile = fs.openSync(fileName, fs.OpenMode.READ_ONLY)
160-
mediaPlayer.url = `fd://${resFile.fd}`;
161-
} else { //资源在resources/rawfile 下的资源 url: 'whoosh.mp3',
183+
this.previousSrc = undefined
184+
} else if (fileName.startsWith('/data') || fileName.startsWith('file:')) {
185+
this.previousSrc = fs.openSync(fileName, fs.OpenMode.READ_ONLY)
186+
mediaPlayer.url = `fd://${this.previousSrc.fd}`;
187+
} else { //资源在resources/rawfile 下的资源 url: 'whoosh.mp3',
162188
let fileDescriptor = await this.context.resourceManager.getRawFd(fileName);
189+
this.previousSrc = fileName
163190
mediaPlayer.fdSrc = fileDescriptor;
164191
}
165-
166192
mediaPlayer.on('stateChange', async (state, reason) => {
167193
switch (state) {
168194
case AvplayerStatus.IDLE:
169195
Logger.info(TAG, 'stateChange AVPlayerstate initialized called. idle');
170196
break;
171197
case AvplayerStatus.INITIALIZED: // avplayer 设置播放源后触发该状态上报
172198
this.setAudioRendererInfo(mediaPlayer);
173-
this.mediaPrepare(mediaPlayer,callBack);
199+
this.mediaPrepare(mediaPlayer, callBack);
174200
break;
175201
default:
176202
Logger.info(TAG, 'stateChange AVPlayer state unknown called.');
@@ -195,12 +221,14 @@ export class AVPlayerController {
195221

196222
//播放错误监听
197223
mediaPlayer.on('error', (err: BusinessError) => {
198-
Logger.error(TAG,`failed, code is ${err.code}, message is ${err.message}`);
224+
Logger.error(TAG, `failed, code is ${err.code}, message is ${err.message}`);
199225
mediaPlayer.reset(); // 调用reset重置资源,触发idle状态
200226
})
227+
228+
201229
}
202230

203-
play(key: number, ctx, callback?: (success: boolean ) => void): void {
231+
play(key: number, ctx, callback?: (success: boolean) => void): void {
204232
const player: media.AVPlayer | undefined = this.playerPool.get(key);
205233
if (player === null && player === undefined) {
206234
if (callback != null) {
@@ -211,10 +239,10 @@ export class AVPlayerController {
211239
player?.on('stateChange', (state, reason) => {
212240
switch (state) {
213241
case AvplayerStatus.COMPLETED: // 播放结束后触发该状态机上报
214-
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying:false, playerKey:key });
215-
setTimeout(()=>{
242+
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying: false, playerKey: key });
243+
setTimeout(() => {
216244
callback?.(true);
217-
},1000)
245+
}, 1000)
218246
this.isPlaying = false;
219247
break;
220248
case AvplayerStatus.PLAYING: // play成功调用后触发该状态机上报
@@ -228,9 +256,9 @@ export class AVPlayerController {
228256

229257
player?.play((err: BusinessError) => {
230258
if (err) {
231-
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying:false, playerKey:key })
259+
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying: false, playerKey: key })
232260
} else {
233-
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying:true, playerKey:key })
261+
ctx.rnInstance.emitDeviceEvent("onPlayChange", { isPlaying: true, playerKey: key })
234262
}
235263
})
236264

@@ -239,10 +267,10 @@ export class AVPlayerController {
239267
pause(key: number, cb?: () => void): void {
240268
const player: media.AVPlayer | undefined = this.playerPool.get(key);
241269
if (this.isPlaying) {
242-
player?.pause().then(()=>{
270+
player?.pause().then(() => {
243271
Logger.info(TAG, `sound: AVPlayer pause success`);
244272
cb?.();
245-
}, ( err: Error)=>{
273+
}, (err: Error) => {
246274
Logger.error(TAG, `sound: AVPlayer pause error${err.name}, message is ${err.message}`);
247275
});
248276
}
@@ -265,12 +293,13 @@ export class AVPlayerController {
265293
try {
266294
player?.reset();
267295
} catch (e) {
268-
Logger.info(TAG, `sound reset error: ${e}} ` );
296+
Logger.info(TAG, `sound reset error: ${e}} `);
269297
}
270298
}
271299

272300
release(key: number): void {
273301
const player: media.AVPlayer | undefined = this.playerPool.get(key);
302+
this.closeFsRawFd()
274303
player?.release();
275304
}
276305

@@ -284,7 +313,7 @@ export class AVPlayerController {
284313
player?.setVolume(volume)
285314
}
286315

287-
getCurrentTime(key: number, callback?: (currentPosition: number | undefined, isPlaying: boolean)=>void) {
316+
getCurrentTime(key: number, callback?: (currentPosition: number | undefined, isPlaying: boolean) => void) {
288317
const player: media.AVPlayer | undefined = this.playerPool.get(key);
289318
if (player === null && player === undefined) {
290319
callback?.(-1, false);
@@ -295,7 +324,7 @@ export class AVPlayerController {
295324

296325
setCurrentTime(key: number, value: number): void {
297326
const player: media.AVPlayer | undefined = this.playerPool.get(key);
298-
if(player !== null && player !== undefined){
327+
if (player !== null && player !== undefined) {
299328
if (value < 0) {
300329
value = 0
301330
} else if (value > player.duration) {
@@ -307,9 +336,9 @@ export class AVPlayerController {
307336
}
308337

309338
// value is : 0,1,2,3,4
310-
setSpeed(key:number, value: number): void {
339+
setSpeed(key: number, value: number): void {
311340
const player: media.AVPlayer | undefined = this.playerPool.get(key);
312-
if(player !== null && player !== undefined){
341+
if (player !== null && player !== undefined) {
313342
player?.setSpeed(value)
314343
}
315344
}
@@ -326,14 +355,14 @@ export class AVPlayerController {
326355

327356
}
328357

329-
setNumberOfLoops(key:number, value: boolean): void {
358+
setNumberOfLoops(key: number, value: boolean): void {
330359
const player: media.AVPlayer | undefined = this.playerPool.get(key);
331-
if(player !== null && player !== undefined){
360+
if (player !== null && player !== undefined) {
332361
player.loop = value
333362
}
334363
}
335364

336-
setCategory(category: AVAudioSessionCategory, mixWithOthers: boolean):void{
365+
setCategory(category: AVAudioSessionCategory, mixWithOthers: boolean): void {
337366
this.category = category
338367
this.mixWithOthers = mixWithOthers
339368
}

harmony/sound/src/main/ets/Logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ class Logger {
6161
}
6262
}
6363

64-
export default new Logger('RNCSlider', 0xFF00, false)
64+
export default new Logger('RNCSlider', 0xFF00, true)

0 commit comments

Comments
 (0)