diff --git a/packages/audioplayers/example/ohos/entry/src/main/module.json5 b/packages/audioplayers/example/ohos/entry/src/main/module.json5 index 7bbf78b18f39991b1404061c7437538c7d532bb7..83f59c9cb4fb483ee183bead88797f1298a4e9ad 100644 --- a/packages/audioplayers/example/ohos/entry/src/main/module.json5 +++ b/packages/audioplayers/example/ohos/entry/src/main/module.json5 @@ -26,6 +26,9 @@ "pages": "$profile:main_pages", "abilities": [ { + "backgroundModes": [ + "audioPlayback" + ], "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ets", "description": "$string:EntryAbility_desc", @@ -48,6 +51,7 @@ ], "requestPermissions": [ {"name" : "ohos.permission.INTERNET"}, + {"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"} ] } } \ No newline at end of file diff --git a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioContextOhos.ets b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioContextOhos.ets index 8b62a2de705afecb6167fff89b539351b76140fd..664c25dcda6e2224055e807b03314c4c60c46ea1 100644 --- a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioContextOhos.ets +++ b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioContextOhos.ets @@ -21,7 +21,8 @@ export default class AudioContextOhos { rendererFlags: number = 0; usageType: number = 1; isSpeakerphoneOn: boolean = true; - audioScene: number = 0 + audioScene: number = 0; + stayAwake: boolean = false; copy(): AudioContextOhos { let context = new AudioContextOhos() @@ -29,11 +30,11 @@ export default class AudioContextOhos { context.usageType = this.usageType; context.isSpeakerphoneOn = this.isSpeakerphoneOn; context.audioScene = this.audioScene; + context.stayAwake = this.stayAwake; return context; } setAttributesOnPlayer(mediaPlayer: media.AVPlayer) { - Log.d("zhu", `setAttributesOnPlayer usage=${this.usageType} rendererFlags=${this.rendererFlags}`); mediaPlayer.audioRendererInfo = { content: 2, usage: this.usageType, rendererFlags: this.rendererFlags diff --git a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioplayersPlugin.ets b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioplayersPlugin.ets index f04d0854361a6def06b308e1f348e53a56f0da96..8c5e694756b6628693e8f56269af74b65239e515 100644 --- a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioplayersPlugin.ets +++ b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/AudioplayersPlugin.ets @@ -20,7 +20,7 @@ import { import MethodChannel, { MethodResult, } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel'; import { EventSink, StreamHandler } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel'; import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall'; -import { BinaryMessenger, EventChannel, Log } from '@ohos/flutter_ohos'; +import { AbilityAware, AbilityPluginBinding, BinaryMessenger, EventChannel, Log } from '@ohos/flutter_ohos'; import { HashMap } from '@kit.ArkTS'; import AudioContextOhos from './AudioContextOhos'; import { SoundPoolManager } from './player/SoundPoolPlayer'; @@ -30,8 +30,14 @@ import UrlSource from './source/UrlSource'; import BytesSource from './source/BytesSource'; import { parseReleaseMode } from './ReleaseMode'; import { parsePlayerMode } from './PlayerMode'; +import { WantAgent, wantAgent } from '@kit.AbilityKit'; +import { backgroundTaskManager } from '@kit.BackgroundTasksKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { avSession as AVSessionManager } from '@kit.AVSessionKit'; -export default class AudioplayersPlugin implements FlutterPlugin, IUpdateCallback { +const TAG = "AudioplayersPlugin"; + +export default class AudioplayersPlugin implements FlutterPlugin, AbilityAware, IUpdateCallback { private methods?: MethodChannel = undefined; private globalMethods?: MethodChannel = undefined; private globalEvents?: EventHandler = undefined; @@ -40,7 +46,10 @@ export default class AudioplayersPlugin implements FlutterPlugin, IUpdateCallbac private soundPoolManager?: SoundPoolManager = undefined; private players = new HashMap(); private defaultAudioContext = new AudioContextOhos(); - private updateInterval: number | null = null + private updateInterval: number | null = null; + private abilityBinding?: AbilityPluginBinding = undefined; + private session?: AVSessionManager.AVSession = undefined; + private isStartContinuousTask = false; getUniqueClassName(): string { return "AudioplayersPlugin" @@ -193,7 +202,7 @@ export default class AudioplayersPlugin implements FlutterPlugin, IUpdateCallbac } response.success(1) } catch (e) { - response.error("AndroidAudioError", e.message, e) + response.error("OhosAudioError", e.message, e) } } @@ -305,6 +314,7 @@ export default class AudioplayersPlugin implements FlutterPlugin, IUpdateCallbac contextOhos.rendererFlags = this.getObjectValue(call, "rendererFlags", "rendererFlags is required") as number contextOhos.usageType = this.getObjectValue(call, "usageType", "usageType is required") as number contextOhos.audioScene = this.getObjectValue(call, "audioScene", "audioScene is required") as number + contextOhos.stayAwake = this.getObjectValue(call, "stayAwake", "stayAwake is required") as boolean return contextOhos; } @@ -318,6 +328,65 @@ export default class AudioplayersPlugin implements FlutterPlugin, IUpdateCallbac private error(msg: string) { throw new Error(msg); } + + onAttachedToAbility(binding: AbilityPluginBinding): void { + this.abilityBinding = binding + } + + onDetachedFromAbility(): void { + this.abilityBinding = undefined + this.stopContinuousTask() + } + + async startContinuousTask() { + Log.d(TAG, `startContinuousTask`); + if(this.isStartContinuousTask){ + return; + } + this.isStartContinuousTask = true; + + let context = this.abilityBinding!.getAbility().context; + let type: AVSessionManager.AVSessionType = 'audio'; + this.session = await AVSessionManager.createAVSession(context, 'audioplayers', type); + // 激活接口要在元数据、控制命令注册完成之后再执行 + await this.session?.activate(); + Log.d(TAG, `session create done : sessionId : ${this.session?.sessionId}`); + + let wantAgentInfo: wantAgent.WantAgentInfo = { + wants: [ + { + bundleName: context?.abilityInfo.bundleName, + abilityName: context?.abilityInfo.name + } + ], + actionType: wantAgent.OperationType.START_ABILITY, + requestCode: 0, + wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] + }; + + wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { + backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => { + Log.d(TAG, `Succeeded in operationing startBackgroundRunning.`); + }).catch((err: BusinessError) => { + Log.e(TAG, `Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); + }); + }); + } + + async stopContinuousTask() { + Log.d(TAG, `stopContinuousTask`); + if(!this.isStartContinuousTask){ + return; + } + this.isStartContinuousTask = false; + await this.session?.deactivate(); + await this.session?.destroy(); + backgroundTaskManager.stopBackgroundRunning(this.abilityBinding?.getAbility().context).then(() => { + Log.d(TAG, `Succeeded in operationing stopBackgroundRunning.`); + }).catch((err: BusinessError) => { + Log.e(TAG, `Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); + }); + } } export class EventHandler implements StreamHandler { diff --git a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/MediaPlayerPlayer.ets b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/MediaPlayerPlayer.ets index 67a813e87037fed2b6f125c5d7211ade4179b065..5b598ab33f5a724cccd9e3d085cd4819526f18f1 100644 --- a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/MediaPlayerPlayer.ets +++ b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/MediaPlayerPlayer.ets @@ -29,9 +29,11 @@ export default class MediaPlayerPlayer implements Player { private isLooping: boolean = false; private volume: number = 1; private needPrepare: boolean = false; + private stayAwake: boolean = false; - constructor(wrappedPlayer: WrappedPlayer) { + constructor(wrappedPlayer: WrappedPlayer, context: AudioContextOhos) { this.wrappedPlayer = wrappedPlayer; + this.stayAwake = context.stayAwake; } async initMediaPlayer() { @@ -76,9 +78,13 @@ export default class MediaPlayerPlayer implements Player { break; case 'playing': // play成功调用后触发该状态机上报 Log.d(TAG, 'AVPlayer state playing called.'); + if (this.stayAwake) { + this.wrappedPlayer.startContinuousTask(); + } break; case 'paused': // pause成功调用后触发该状态机上报 Log.d(TAG, 'AVPlayer state paused called.'); + this.wrappedPlayer.stopContinuousTask(); break; case 'completed': // 播放结束后触发该状态机上报 Log.d(TAG, 'AVPlayer state completed called.'); @@ -86,9 +92,11 @@ export default class MediaPlayerPlayer implements Player { break; case 'stopped': // stop接口成功调用后触发该状态机上报 Log.d(TAG, 'AVPlayer state stopped called.'); + this.wrappedPlayer.stopContinuousTask(); this.needPrepare && this.prepare(); break; case 'released': + this.wrappedPlayer.stopContinuousTask(); Log.d(TAG, 'AVPlayer state released called.'); break; default: @@ -175,6 +183,10 @@ export default class MediaPlayerPlayer implements Player { updateContext(context: AudioContextOhos) { this.mediaPlayer && this.mediaPlayer!.state == 'initialized' &&context.setAttributesOnPlayer(this.mediaPlayer); + if (context.stayAwake && context.stayAwake != this.stayAwake) { + this.stayAwake = true + this.wrappedPlayer.startContinuousTask(); + } } async setSource(source: Source) { diff --git a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/WrappedPlayer.ets b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/WrappedPlayer.ets index cb49847be12a5910c4730d9cb7d5d06936c0ceac..9f855af75b3783cb7ab55c808d0578fd562bee93 100644 --- a/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/WrappedPlayer.ets +++ b/packages/audioplayers_ohos/ohos/src/main/ets/components/plugin/player/WrappedPlayer.ets @@ -341,7 +341,7 @@ export default class WrappedPlayer { await player.init(); return player; } else { - let player = new MediaPlayerPlayer(this); + let player = new MediaPlayerPlayer(this, this.context); await player.initMediaPlayer() return player } @@ -377,4 +377,12 @@ export default class WrappedPlayer { await this.release() this.eventHandler.dispose() } + + startContinuousTask() { + this.ref.startContinuousTask() + } + + stopContinuousTask() { + this.ref.stopContinuousTask() + } } \ No newline at end of file diff --git a/packages/audioplayers_platform_interface/lib/src/api/audio_context.dart b/packages/audioplayers_platform_interface/lib/src/api/audio_context.dart index 4f21f63bc2194218897d0ee2471f9c10b46d7fd2..ba04a00cc78a2f725a8c8453fa678364a7fc5aa1 100644 --- a/packages/audioplayers_platform_interface/lib/src/api/audio_context.dart +++ b/packages/audioplayers_platform_interface/lib/src/api/audio_context.dart @@ -120,11 +120,13 @@ class AudioContextOhos { final int rendererFlags; final OhosUsageType usageType; final OhosAudioScene audioScene; + final bool stayAwake; const AudioContextOhos({ this.isSpeakerphoneOn = true, this.audioScene = OhosAudioScene.normal, this.rendererFlags = 0, + this.stayAwake = true, this.usageType = OhosUsageType.music, }); @@ -133,12 +135,14 @@ class AudioContextOhos { OhosAudioScene? audioScene, int? rendererFlags, OhosUsageType? usageType, + bool? stayAwake, }) { return AudioContextOhos( isSpeakerphoneOn: isSpeakerphoneOn ?? this.isSpeakerphoneOn, audioScene: audioScene ?? this.audioScene, rendererFlags: rendererFlags ?? this.rendererFlags, usageType: usageType ?? this.usageType, + stayAwake: stayAwake ?? this.stayAwake, ); } @@ -148,6 +152,7 @@ class AudioContextOhos { 'rendererFlags': rendererFlags, 'audioScene': audioScene.value, 'usageType': usageType.value, + 'stayAwake': stayAwake, }; } } diff --git a/packages/audioplayers_platform_interface/lib/src/api/audio_context_config.dart b/packages/audioplayers_platform_interface/lib/src/api/audio_context_config.dart index 9d4b4dc2e879b4655b09058f51456919d4e97717..0b67802901b7e7b3cda75dc994da9c0434fc4dfa 100644 --- a/packages/audioplayers_platform_interface/lib/src/api/audio_context_config.dart +++ b/packages/audioplayers_platform_interface/lib/src/api/audio_context_config.dart @@ -118,6 +118,7 @@ class AudioContextConfig { AudioContextOhos buildOhos() { return AudioContextOhos( isSpeakerphoneOn: forceSpeaker, + stayAwake: stayAwake, usageType: respectSilence ? OhosUsageType.ringtone : OhosUsageType.music