diff --git a/OAT.xml b/OAT.xml
new file mode 100644
index 0000000000000000000000000000000000000000..12c0fb0c17fbf16a8caa9bab1c65207091cb2b5b
--- /dev/null
+++ b/OAT.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 770d1939fa74897469d10c04b503371986b7acca..c98e18ee4c39fafbe60ef1f9e48805468802b1f1 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,8 +1,24 @@
+//
+// Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
import 'dart:math';
import 'package:audio_session/audio_session.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
-import 'package:just_audio/just_audio.dart' as ja;
+import 'package:audioplayers/audioplayers.dart';
void main() {
runApp(MyApp());
@@ -14,12 +30,10 @@ class MyApp extends StatefulWidget {
}
class _MyAppState extends State {
- final _player = ja.AudioPlayer(
- // Handle audio_session events ourselves for the purpose of this demo.
- handleInterruptions: false,
- androidApplyAudioAttributes: false,
- handleAudioSessionActivation: false,
- );
+ final player = AudioPlayer();
+ final String url =
+ "https://luan.xyz/files/audio/ambient_c_motion.mp3";
+ PlayerState playerState = PlayerState.stopped;
@override
void initState() {
@@ -32,41 +46,41 @@ class _MyAppState extends State {
// Listen to audio interruptions and pause or duck as appropriate.
_handleInterruptions(audioSession);
// Use another plugin to load audio to play.
- await _player.setUrl(
- "https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3");
});
+ player.play(UrlSource(url));
}
void _handleInterruptions(AudioSession audioSession) {
- // just_audio can handle interruptions for us, but we have disabled that in
- // order to demonstrate manual configuration.
bool playInterrupted = false;
audioSession.becomingNoisyEventStream.listen((_) {
- print('PAUSE');
- _player.pause();
+ print('AudioSession PAUSE');
+ player.pause();
});
- _player.playingStream.listen((playing) {
+ player.onPlayerStateChanged.listen((event) {
+ print('AudioSession state changed: $event');
playInterrupted = false;
- if (playing) {
+ if (event == PlayerState.playing) {
audioSession.setActive(true);
}
+ setState(() {
+ this.playerState = event;
+ });
});
+
audioSession.interruptionEventStream.listen((event) {
- print('interruption begin: ${event.begin}');
- print('interruption type: ${event.type}');
+ print('AudioSession interruption begin: ${event.begin}');
+ print('AudioSession interruption type: ${event.type}');
if (event.begin) {
switch (event.type) {
case AudioInterruptionType.duck:
if (audioSession.androidAudioAttributes!.usage ==
- AndroidAudioUsage.game) {
- _player.setVolume(_player.volume / 2);
- }
+ AndroidAudioUsage.game) {}
playInterrupted = false;
break;
case AudioInterruptionType.pause:
case AudioInterruptionType.unknown:
- if (_player.playing) {
- _player.pause();
+ if (this.playerState == PlayerState.playing) {
+ player.pause();
playInterrupted = true;
}
break;
@@ -74,11 +88,10 @@ class _MyAppState extends State {
} else {
switch (event.type) {
case AudioInterruptionType.duck:
- _player.setVolume(min(1.0, _player.volume * 2));
playInterrupted = false;
break;
case AudioInterruptionType.pause:
- if (playInterrupted) _player.play();
+ if (playInterrupted) player.play(UrlSource(url));
playInterrupted = false;
break;
case AudioInterruptionType.unknown:
@@ -88,11 +101,16 @@ class _MyAppState extends State {
}
});
audioSession.devicesChangedEventStream.listen((event) {
- print('Devices added: ${event.devicesAdded}');
- print('Devices removed: ${event.devicesRemoved}');
+ print('AudioSession Devices added: ${event.devicesAdded}');
+ print('AudioSession Devices removed: ${event.devicesRemoved}');
});
}
+ Future play() async {
+ await player.stop();
+ await player.play(UrlSource(url));
+ }
+
@override
Widget build(BuildContext context) {
return MaterialApp(
@@ -106,29 +124,21 @@ class _MyAppState extends State {
children: [
Expanded(
child: Center(
- child: StreamBuilder(
- stream: _player.playerStateStream,
- builder: (context, snapshot) {
- final playerState = snapshot.data;
- if (playerState?.processingState !=
- ja.ProcessingState.ready) {
- return Container(
- margin: EdgeInsets.all(8.0),
- width: 64.0,
- height: 64.0,
- child: CircularProgressIndicator(),
- );
- } else if (playerState?.playing == true) {
+ child: Builder(
+ builder: (context) {
+ if (this.playerState == PlayerState.playing) {
+ print("AudioSession playing");
return IconButton(
icon: Icon(Icons.pause),
iconSize: 64.0,
- onPressed: _player.pause,
+ onPressed: player.pause,
);
} else {
+ print("AudioSession stopped");
return IconButton(
icon: Icon(Icons.play_arrow),
iconSize: 64.0,
- onPressed: _player.play,
+ onPressed: play,
);
}
},
@@ -151,14 +161,16 @@ class _MyAppState extends State {
Text("Input devices",
style: Theme.of(context).textTheme.titleLarge),
for (var device
- in devices.where((device) => device.isInput))
- Text('${device.name} (${device.type.name})'),
+ in devices.where((device) => device.isInput))
+ Text(
+ '${device.name} (${describeEnum(device.type)})'),
SizedBox(height: 16),
Text("Output devices",
style: Theme.of(context).textTheme.titleLarge),
for (var device
- in devices.where((device) => device.isOutput))
- Text('${device.name} (${device.type.name})'),
+ in devices.where((device) => device.isOutput))
+ Text(
+ '${device.name} (${describeEnum(device.type)})'),
],
);
},
diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift
index df18b278d560a36e7f3a14674d34daf8f1cc64bb..fd0047db8e72416700951aba7f354d94ffca3519 100644
--- a/example/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -6,11 +6,11 @@ import FlutterMacOS
import Foundation
import audio_session
-import just_audio
+import audioplayers_darwin
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
- JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
+ AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
}
diff --git a/example/ohos/.gitignore b/example/ohos/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f0364c33c52a9b8ce1b89ea309af9c8ea68f718d
--- /dev/null
+++ b/example/ohos/.gitignore
@@ -0,0 +1,16 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+entry/libs/arm64-v8a/libapp.so
+entry/libs/arm64-v8a/libflutter.so
+entry/libs/arm64-v8a/libvmservice_snapshot.so
+entry/src/main/resources/rawfile/flutter_assets/
+har/flutter.har
diff --git a/example/ohos/AppScope/app.json5 b/example/ohos/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..7d9e702cfa854993c2b361b2cd0e52009024279f
--- /dev/null
+++ b/example/ohos/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.ryanheise.audio_session_example",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/AppScope/resources/base/element/string.json b/example/ohos/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..c8bd0f4ba010bdf428387199e2dfe4b500007194
--- /dev/null
+++ b/example/ohos/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "audio_session_example"
+ }
+ ]
+}
diff --git a/example/ohos/AppScope/resources/base/media/app_icon.png b/example/ohos/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/example/ohos/AppScope/resources/base/media/app_icon.png differ
diff --git a/example/ohos/build-profile.json5 b/example/ohos/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..1d12140d202702d7c73d64f1b291fe5c45a660ce
--- /dev/null
+++ b/example/ohos/build-profile.json5
@@ -0,0 +1,27 @@
+{
+ "app": {
+ "signingConfigs": [],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.0(12)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/dta/icudtl.dat b/example/ohos/dta/icudtl.dat
new file mode 100644
index 0000000000000000000000000000000000000000..d1f10917ab52e3ebd251abd7f5377d7196b80d67
Binary files /dev/null and b/example/ohos/dta/icudtl.dat differ
diff --git a/example/ohos/entry/.gitignore b/example/ohos/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2795a1c5b1fe53659dd1b71d90ba0592eaf7e043
--- /dev/null
+++ b/example/ohos/entry/.gitignore
@@ -0,0 +1,7 @@
+
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/example/ohos/entry/build-profile.json5 b/example/ohos/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..633d360fbc91a3186a23b66ab71b27e5618944cb
--- /dev/null
+++ b/example/ohos/entry/build-profile.json5
@@ -0,0 +1,29 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "apiType": 'stageMode',
+ "buildOption": {
+ },
+ "targets": [
+ {
+ "name": "default",
+ "runtimeOS": "HarmonyOS"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/hvigorfile.ts b/example/ohos/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..894fc15c6b793f085e6c8506e43d719af658e8ff
--- /dev/null
+++ b/example/ohos/entry/hvigorfile.ts
@@ -0,0 +1,17 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { hapTasks } from '@ohos/hvigor-ohos-plugin';
diff --git a/example/ohos/entry/libs/arm64-v8a/libc++_shared.so b/example/ohos/entry/libs/arm64-v8a/libc++_shared.so
new file mode 100644
index 0000000000000000000000000000000000000000..831c9353702073d45889352a4dafb93103d67d20
Binary files /dev/null and b/example/ohos/entry/libs/arm64-v8a/libc++_shared.so differ
diff --git a/example/ohos/entry/oh-package.json5 b/example/ohos/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..995d00f6cd5991dc7142bbe5ea53b264223579fa
--- /dev/null
+++ b/example/ohos/entry/oh-package.json5
@@ -0,0 +1,13 @@
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "audio_session": "file:../har/audio_session.har",
+ "audioplayers_ohos": "file:../har/audioplayers_ohos.har",
+ "path_provider_ohos": "file:../har/path_provider_ohos.har"
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..a00049282e93c69f1b3dcd987538024f47e40ace
--- /dev/null
+++ b/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,25 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { FlutterAbility } from '@ohos/flutter_ohos'
+import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
+import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine';
+
+export default class EntryAbility extends FlutterAbility {
+ configureFlutterEngine(flutterEngine: FlutterEngine) {
+ super.configureFlutterEngine(flutterEngine)
+ GeneratedPluginRegistrant.registerWith(flutterEngine)
+ }
+}
diff --git a/example/ohos/entry/src/main/ets/pages/Index.ets b/example/ohos/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1125f9fdd95f4310a182c1c9e3680f37f73686c9
--- /dev/null
+++ b/example/ohos/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import common from '@ohos.app.ability.common';
+import { FlutterPage } from '@ohos/flutter_ohos'
+
+let storage = LocalStorage.getShared()
+const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'
+
+@Entry(storage)
+@Component
+struct Index {
+ private context = getContext(this) as common.UIAbilityContext
+ @LocalStorageLink('viewId') viewId: string = "";
+
+ build() {
+ Column() {
+ FlutterPage({ viewId: this.viewId })
+ }
+ }
+
+ onBackPress(): boolean {
+ this.context.eventHub.emit(EVENT_BACK_PRESS)
+ return true
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/module.json5 b/example/ohos/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..7bbf78b18f39991b1404061c7437538c7d532bb7
--- /dev/null
+++ b/example/ohos/entry/src/main/module.json5
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "requestPermissions": [
+ {"name" : "ohos.permission.INTERNET"},
+ ]
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/resources/base/element/color.json b/example/ohos/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/example/ohos/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/resources/base/element/string.json b/example/ohos/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..ef07f22b7976c9e7efdeae3e6e261311be32768f
--- /dev/null
+++ b/example/ohos/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "audio_session_example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/resources/base/media/icon.png b/example/ohos/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/example/ohos/entry/src/main/resources/base/media/icon.png differ
diff --git a/example/ohos/entry/src/main/resources/base/profile/main_pages.json b/example/ohos/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/example/ohos/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/example/ohos/entry/src/main/resources/en_US/element/string.json b/example/ohos/entry/src/main/resources/en_US/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..ef07f22b7976c9e7efdeae3e6e261311be32768f
--- /dev/null
+++ b/example/ohos/entry/src/main/resources/en_US/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "audio_session_example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/main/resources/zh_CN/element/string.json b/example/ohos/entry/src/main/resources/zh_CN/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..9ab4406e6f33d3450aa57f7e86340f8e1e5bf922
--- /dev/null
+++ b/example/ohos/entry/src/main/resources/zh_CN/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "模块描述"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "audio_session_example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets b/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..25d4c71ff3cd584f5d64f6f8c0ac864928c234c4
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', function () {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(function () {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ })
+ beforeEach(function () {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ })
+ afterEach(function () {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ })
+ afterAll(function () {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ })
+ it('assertContain',0, function () {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
+ let a = 'abc'
+ let b = 'b'
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b)
+ expect(a).assertEqual(a)
+ })
+ })
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/ets/test/List.test.ets b/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f4140030e65d20df6af30a6bf51e464dea8f8aa6
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import abilityTest from './Ability.test'
+
+export default function testsuite() {
+ abilityTest()
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets b/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..4ca645e6013cfce8e7dbb728313cb8840c4da660
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import hilog from '@ohos.hilog';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+import window from '@ohos.window';
+
+export default class TestAbility extends UIAbility {
+ onCreate(want, launchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? '');
+ var abilityDelegator: any
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var abilityDelegatorArguments: any
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
+ windowStage.loadContent('testability/pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
+ JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
+ }
+
+ onForeground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
+ }
+
+ onBackground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets b/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..cef0447cd2f137ef82d223ead2e156808878ab90
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+
+@Entry
+@Component
+struct Index {
+ aboutToAppear() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
+ }
+ @State message: string = 'Hello World'
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(50)
+ .fontWeight(FontWeight.Bold)
+ Button() {
+ Text('next page')
+ .fontSize(20)
+ .fontWeight(FontWeight.Bold)
+ }.type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .backgroundColor('#0D9FFB')
+ .width('35%')
+ .height('5%')
+ .onClick(()=>{
+ })
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+ }
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1def08f2e9dcbfa3454a07b7a3b82b173bb90d02
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import TestRunner from '@ohos.application.testRunner';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+
+var abilityDelegator = undefined
+var abilityDelegatorArguments = undefined
+
+async function onAbilityCreateCallback() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
+}
+
+async function addAbilityMonitorCallback(err: any) {
+ hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
+}
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
+ }
+
+ async onRun() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'
+ let lMonitor = {
+ abilityName: testAbilityName,
+ onAbilityCreate: onAbilityCreateCallback,
+ };
+ abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
+ var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName
+ var debug = abilityDelegatorArguments.parameters['-D']
+ if (debug == 'true')
+ {
+ cmd += ' -D'
+ }
+ hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd);
+ abilityDelegator.executeShellCommand(cmd,
+ (err: any, d: any) => {
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? '');
+ })
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/module.json5 b/example/ohos/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..fab77ce2e0c61e3ad010bab5b27ccbd15f9a8c96
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/module.json5
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "description": "$string:module_test_desc",
+ "mainElement": "TestAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:test_pages",
+ "abilities": [
+ {
+ "name": "TestAbility",
+ "srcEntry": "./ets/testability/TestAbility.ets",
+ "description": "$string:TestAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:TestAbility_label",
+ "exported": true,
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "skills": [
+ {
+ "actions": [
+ "action.system.home"
+ ],
+ "entities": [
+ "entity.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/example/ohos/entry/src/ohosTest/resources/base/element/color.json b/example/ohos/entry/src/ohosTest/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/resources/base/element/string.json b/example/ohos/entry/src/ohosTest/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/ohos/entry/src/ohosTest/resources/base/media/icon.png b/example/ohos/entry/src/ohosTest/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/example/ohos/entry/src/ohosTest/resources/base/media/icon.png differ
diff --git a/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json b/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe
--- /dev/null
+++ b/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "testability/pages/Index"
+ ]
+}
diff --git a/example/ohos/hvigor/hvigor-config.json5 b/example/ohos/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..a1e72840d839cebea4520acb6d1e9afff8c3cf01
--- /dev/null
+++ b/example/ohos/hvigor/hvigor-config.json5
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ }
+}
\ No newline at end of file
diff --git a/example/ohos/hvigorfile.ts b/example/ohos/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8f2d2aafe6d6a3a71a9944ebd0c91fbc308ac9d1
--- /dev/null
+++ b/example/ohos/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
\ No newline at end of file
diff --git a/example/ohos/oh-package.json5 b/example/ohos/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..2625d60a47c24a08492eecc63e2538342ccfd168
--- /dev/null
+++ b/example/ohos/oh-package.json5
@@ -0,0 +1,22 @@
+{
+ "modelVersion": "5.0.0",
+ "name": "apptemplate",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har"
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.6"
+ },
+ "overrides": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har",
+ "audio_session": "file:./har/audio_session.har",
+ "@ohos/flutter_module": "file:./entry",
+ "audioplayers_ohos": "file:./har/audioplayers_ohos.har",
+ "path_provider_ohos": "file:./har/path_provider_ohos.har"
+ }
+}
\ No newline at end of file
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index fbb87e4f5a8100898eb572fa4734182e7c938327..709c8bb86253009ba104b3dea31cfb2b725e1c0e 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -11,7 +11,11 @@ environment:
dependencies:
flutter:
sdk: flutter
- just_audio: ^0.9.31
+ # just_audio: ^0.9.31
+ audioplayers:
+ git:
+ url: https://gitee.com/openharmony-sig/flutter_audioplayers.git
+ path: packages/audioplayers
audio_session:
path: ../
diff --git a/lib/src/core.dart b/lib/src/core.dart
index abce49ad286157827b2c1d0cc476ff51384acd8e..4813c8c36248a303f210ae974b1a940933b43f9f 100644
--- a/lib/src/core.dart
+++ b/lib/src/core.dart
@@ -8,6 +8,7 @@ import 'package:rxdart/rxdart.dart';
import 'android.dart';
import 'darwin.dart';
+import 'ohos.dart';
/// Manages a single audio session to be used across different audio plugins in
/// your app. [AudioSession] will configure your app by describing to the operating
@@ -47,6 +48,10 @@ class AudioSession {
final _androidAudioManager =
!kIsWeb && Platform.isAndroid ? AndroidAudioManager() : null;
final _avAudioSession = !kIsWeb && Platform.isIOS ? AVAudioSession() : null;
+ final _ohosAudionManager =
+ !kIsWeb && defaultTargetPlatform == TargetPlatform.ohos
+ ? OhosAudioManager()
+ : null;
AudioSessionConfiguration? _configuration;
final _configurationSubject = BehaviorSubject();
final _interruptionEventSubject = PublishSubject();
@@ -147,6 +152,24 @@ class AudioSession {
_devicesSubject.add(await getDevices());
}
});
+ _ohosAudionManager?.setAudioDevicesAddedListener((devices) async {
+ _devicesChangedEventSubject.add(AudioDevicesChangedEvent(
+ devicesAdded: devices.map(_ohosDevice2device).toSet(),
+ devicesRemoved: {},
+ ));
+ if (_devicesSubject.hasListener) {
+ _devicesSubject.add(await getDevices());
+ }
+ });
+ _ohosAudionManager?.setAudioDevicesRemovedListener((devices) async {
+ _devicesChangedEventSubject.add(AudioDevicesChangedEvent(
+ devicesAdded: {},
+ devicesRemoved: devices.map(_ohosDevice2device).toSet(),
+ ));
+ if (_devicesSubject.hasListener) {
+ _devicesSubject.add(await getDevices());
+ }
+ });
_channel.setMethodCallHandler((MethodCall call) async {
final args = call.arguments as List?;
switch (call.method) {
@@ -228,6 +251,8 @@ class AudioSession {
bool? androidWillPauseWhenDucked,
AudioSessionConfiguration fallbackConfiguration =
const AudioSessionConfiguration.music(),
+ AudioConcurrencyMode? ohosAudioConcurrencyMode,
+ OhosAudioAttributes? ohosAudioAttributes,
}) async {
final configuration = _configuration ?? fallbackConfiguration;
if (!isConfigured) {
@@ -290,6 +315,29 @@ class AudioSession {
final success = await _androidAudioManager!.abandonAudioFocus();
return success;
}
+ } else if (!kIsWeb && defaultTargetPlatform == TargetPlatform.ohos) {
+ AudioConcurrencyMode concurrencyMode = ohosAudioConcurrencyMode ??
+ AudioConcurrencyMode.concurrencyPauseOthers;
+ await _ohosAudionManager!
+ .setActive(active, concurrencyMode: concurrencyMode);
+ final success = await _ohosAudionManager!.setInterruptionEventListener(
+ OhosInterruptListernerRequest(
+ audioAttributes:
+ ohosAudioAttributes ?? configuration.ohosAudioAttributes,
+ onAudioFocusChanged: (reason) {
+ switch (reason) {
+ case AudioSessionDeactivatedReason.deactivatedLowerPriority:
+ _interruptionEventSubject.add(AudioInterruptionEvent(
+ true, AudioInterruptionType.pause));
+ break;
+ case AudioSessionDeactivatedReason.deactivatedTimeout:
+ _interruptionEventSubject.add(AudioInterruptionEvent(
+ false, AudioInterruptionType.unknown));
+ break;
+ }
+ },
+ isOnListener: active));
+ return success;
}
return true;
}
@@ -328,6 +376,12 @@ class AudioSession {
outputPorts: currentRoute.outputs,
)));
}
+ } else if (_ohosAudionManager != null) {
+ var flags = DevicesFlags.noneDevicesFlag;
+ if (includeInputs) flags |= DevicesFlags.inputDevicesFlag;
+ if (includeOutputs) flags |= DevicesFlags.outputDevicesFlag;
+ final ohosDevices = await _ohosAudionManager!.getDevices(flags);
+ devices.addAll(ohosDevices.map(_ohosDevice2device).toSet());
}
return devices;
}
@@ -462,6 +516,41 @@ class AudioSession {
type: _androidType2type(device.type),
);
}
+
+ static AudioDeviceType _ohosType2type(DeviceType type) {
+ switch (type) {
+ case DeviceType.invalid:
+ return AudioDeviceType.unknown;
+ case DeviceType.earpiece:
+ return AudioDeviceType.builtInEarpiece;
+ case DeviceType.speaker:
+ return AudioDeviceType.builtInSpeaker;
+ case DeviceType.wiredHeadset:
+ return AudioDeviceType.wiredHeadset;
+ case DeviceType.wiredHeadphones:
+ return AudioDeviceType.wiredHeadphones;
+ case DeviceType.bluetoothSco:
+ return AudioDeviceType.bluetoothSco;
+ case DeviceType.bluetoothA2dp:
+ return AudioDeviceType.bluetoothA2dp;
+ case DeviceType.mic:
+ return AudioDeviceType.builtInMic;
+ case DeviceType.usbHeadset:
+ return AudioDeviceType.usbAudio;
+ case DeviceType.defaultDevice:
+ return AudioDeviceType.builtInSpeaker;
+ }
+ }
+
+ static AudioDevice _ohosDevice2device(OhosAudioDeviceDescriptor device) {
+ return AudioDevice(
+ id: device.id.toString(),
+ name: device.displayName,
+ isInput: device.deviceRole == DeviceRole.inputDevice,
+ isOutput: device.deviceRole == DeviceRole.outputDevice,
+ type: _ohosType2type(device.deviceType),
+ );
+ }
}
/// A configuration for [AudioSession] describing what type of audio your app
@@ -482,6 +571,7 @@ class AudioSessionConfiguration {
final AndroidAudioAttributes? androidAudioAttributes;
final AndroidAudioFocusGainType androidAudioFocusGainType;
final bool? androidWillPauseWhenDucked;
+ final OhosAudioAttributes? ohosAudioAttributes;
/// Creates an audio session configuration from scratch.
///
@@ -507,6 +597,7 @@ class AudioSessionConfiguration {
this.androidAudioAttributes,
this.androidAudioFocusGainType = AndroidAudioFocusGainType.gain,
this.androidWillPauseWhenDucked,
+ this.ohosAudioAttributes,
});
AudioSessionConfiguration.fromJson(Map data)
diff --git a/lib/src/ohos.dart b/lib/src/ohos.dart
new file mode 100644
index 0000000000000000000000000000000000000000..faa86038619dc1adcdc6914d111f1ce69e604fd2
--- /dev/null
+++ b/lib/src/ohos.dart
@@ -0,0 +1,598 @@
+//
+// Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import 'dart:async';
+
+import 'package:audio_session/src/util.dart';
+import 'package:flutter/services.dart';
+
+class OhosAudioManager {
+ static const MethodChannel _channel =
+ MethodChannel('com.ryanheise.ohos_audio_manager');
+ static OhosAudioManager? _instance;
+
+ OhosOnAudioDevicesChanged? _onAudioDevicesAdded;
+ OhosOnAudioDevicesChanged? _onAudioDevicesRemoved;
+ OhosOnAudioFocusChanged? _onAudioFocusChanged;
+
+ factory OhosAudioManager() {
+ return _instance ??= OhosAudioManager._();
+ }
+
+ void setAudioDevicesAddedListener(OhosOnAudioDevicesChanged listener) {
+ _onAudioDevicesAdded = listener;
+ }
+
+ void setAudioDevicesRemovedListener(OhosOnAudioDevicesChanged listener) {
+ _onAudioDevicesRemoved = listener;
+ }
+
+ OhosAudioManager._() {
+ _channel.setMethodCallHandler((MethodCall call) async {
+ final args = call.arguments as List;
+ switch (call.method) {
+ case 'onAudioDevicesAdded':
+ if (_onAudioDevicesAdded != null) {
+ _onAudioDevicesAdded!(_decodeAudioDevices(args[0]));
+ }
+ break;
+ case 'onAudioDevicesRemoved':
+ if (_onAudioDevicesRemoved != null) {
+ _onAudioDevicesRemoved!(_decodeAudioDevices(args[0]));
+ }
+ break;
+ case 'onScoAudioStateUpdated':
+ break;
+ case 'onAudioInterrupt':
+ if (_onAudioFocusChanged != null) {
+ _onAudioFocusChanged!(decodeEnum(
+ AudioSessionDeactivatedReason.values, args[0] as int?,
+ defaultValue:
+ AudioSessionDeactivatedReason.deactivatedLowerPriority));
+ }
+ break;
+ }
+ });
+ }
+
+ Future setInterruptionEventListener(
+ OhosInterruptListernerRequest listernerRequest) async {
+ _onAudioFocusChanged = listernerRequest.onAudioFocusChanged;
+ return (await _channel.invokeMethod(
+ 'setInterruptionEventListener', [listernerRequest.toJson()]))!;
+ }
+
+ Future setActive(bool active,
+ {AudioConcurrencyMode? concurrencyMode}) async =>
+ (await _channel
+ .invokeMethod('setActive', [active, concurrencyMode?.index]))!;
+
+ Future isVolumeUnadjustable() async {
+ return (await _channel.invokeMethod('isVolumeUnadjustable'))!;
+ }
+
+ Future getRingerMode() async {
+ return decodeEnum(AudioRingMode.values,
+ (await _channel.invokeMethod('getRingerMode')),
+ defaultValue: AudioRingMode.ringerModeNormal);
+ }
+
+ Future getMaxVolume(AudioVolumeType streamType) async {
+ return (await _channel.invokeMethod(
+ 'getMaxVolume', streamType.value))!;
+ }
+
+ Future getMinVolume(AudioVolumeType streamType) async {
+ return (await _channel.invokeMethod(
+ 'getMinVolume', streamType.value))!;
+ }
+
+ Future getVolume(AudioVolumeType streamType) async {
+ return (await _channel.invokeMethod('getVolume', streamType.value))!;
+ }
+
+ Future getSystemVolumeInDb(AudioVolumeType streamType) async {
+ return (await _channel.invokeMethod(
+ 'getSystemVolumeInDb', streamType.value))!;
+ }
+
+ Future isMute(AudioVolumeType streamType) async {
+ return (await _channel.invokeMethod('isMute', streamType.value))!;
+ }
+
+ Future> getDevices(DevicesFlags flags) async {
+ return _decodeAudioDevices(
+ (await _channel.invokeMethod('getDevices', [flags.value]))!);
+ }
+
+ Future setSpeakerphoneOn(bool enabled) async {
+ await _channel.invokeMethod('setSpeakerphoneOn', [enabled]);
+ }
+
+ Future isSpeakerphoneOn() async {
+ return (await _channel.invokeMethod('isSpeakerphoneOn'))!;
+ }
+
+ Future setMicrophoneMute(bool enabled) async {
+ await _channel.invokeMethod('setMicrophoneMute', [enabled]);
+ }
+
+ Future isMicrophoneMute() async {
+ return (await _channel.invokeMethod('isMicrophoneMute'))!;
+ }
+
+ Future getAudioScene() async {
+ return decodeEnum(
+ AudioScene.values, (await _channel.invokeMethod('getAudioScene')),
+ defaultValue: AudioScene.audioSceneDefault);
+ }
+
+ Future isMusicActive() async {
+ return (await _channel.invokeMethod('isMusicActive'))!;
+ }
+
+ Future setAudioParameter(String parameters, String value) async {
+ await _channel.invokeMethod('setAudioParameter', [parameters, value]);
+ }
+
+ Future getAudioParameter(String key) async {
+ return (await _channel.invokeMethod('getAudioParameter', [key]))!;
+ }
+
+ List _decodeAudioDevices(dynamic rawList) {
+ return (rawList as List).map(_decodeAudioDevice).toList();
+ }
+
+ OhosAudioDeviceDescriptor _decodeAudioDevice(dynamic raw) {
+ return OhosAudioDeviceDescriptor(
+ deviceRole: DeviceRoleExtension.getEnum(raw['deviceRole'] as int),
+ deviceType: DeviceTypeExtension.getEnum(raw['deviceType'] as int),
+ id: raw['id'] as int,
+ name: raw['name'] as String,
+ address: raw['address'] as String,
+ sampleRates: (raw['sampleRates'] as List).cast(),
+ channelCounts: (raw['channelCounts'] as List).cast(),
+ channelMasks: (raw['channelMasks'] as List).cast(),
+ displayName: raw['displayName'] as String);
+ }
+}
+
+typedef OhosOnAudioFocusChanged = void Function(
+ AudioSessionDeactivatedReason focus);
+typedef OhosOnAudioDevicesChanged = void Function(
+ List devices);
+
+class OhosInterruptEvent {
+ final OhosInterruptType eventType;
+ final OhosInterruptForceType forceType;
+ final OhosInterruptHint hintType;
+
+ OhosInterruptEvent({
+ required this.eventType,
+ required this.forceType,
+ required this.hintType,
+ });
+}
+
+class OhosInterruptType {
+ static const interruptTypeBegin = OhosInterruptType._(1);
+ static const interruptTypeEnd = OhosInterruptType._(2);
+ static const values = {
+ 1: interruptTypeBegin,
+ 2: interruptTypeEnd,
+ };
+ final int index;
+ const OhosInterruptType._(this.index);
+}
+
+extension OhosInterruptTypeExtension on OhosInterruptType {
+ int get value => [1, 2][index];
+}
+
+enum OhosInterruptForceType {
+ interruptForce,
+ interruptShare,
+}
+
+enum InterruptMode {
+ shareMode,
+ indepentMode,
+}
+
+enum OhosInterruptHint {
+ interruptHintNone,
+ interruptHintResume,
+ interruptHintPause,
+ interruptHintStop,
+ interruptHintDuck,
+ interruptHintUnduck,
+}
+
+enum AudioRingMode {
+ ringerModeSilent,
+ ringerModeVibrate,
+ ringerModeNormal,
+}
+
+enum AudioScene {
+ audioSceneDefault,
+ audioSceneRinging,
+ audioScenePhoneCall,
+ audioSceneVoiceChat,
+}
+
+enum AudioSessionDeactivatedReason {
+ deactivatedLowerPriority,
+ deactivatedTimeout
+}
+
+class DevicesFlags {
+ static const DevicesFlags noneDevicesFlag = DevicesFlags(0);
+ static const DevicesFlags outputDevicesFlag = DevicesFlags(1);
+ static const DevicesFlags inputDevicesFlag = DevicesFlags(2);
+ static const DevicesFlags allDevicesFlag = DevicesFlags(3);
+ static const DevicesFlags distributedOutputDevicesFlag = DevicesFlags(4);
+ static const DevicesFlags distributedInputDevicesFlag = DevicesFlags(8);
+ static const DevicesFlags addDistributedDevicesFlag = DevicesFlags(12);
+
+ final int value;
+
+ const DevicesFlags(this.value);
+
+ DevicesFlags operator |(DevicesFlags flag) =>
+ DevicesFlags(value | flag.value);
+
+ DevicesFlags operator &(DevicesFlags flag) =>
+ DevicesFlags(value & flag.value);
+
+ bool contains(DevicesFlags flags) => flags.value & value == flags.value;
+
+ @override
+ bool operator ==(Object other) =>
+ other is DevicesFlags && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+class OhosAudioDeviceDescriptor {
+ final DeviceRole deviceRole;
+ final DeviceType deviceType;
+ final int id;
+ final String name;
+ final String address;
+ final List sampleRates;
+ final List channelCounts;
+ final List channelMasks;
+ final String displayName;
+ final AudioEncodingType? encodingTypes;
+
+ OhosAudioDeviceDescriptor({
+ required this.deviceRole,
+ required this.deviceType,
+ required this.id,
+ required this.name,
+ required this.address,
+ required this.sampleRates,
+ required this.channelCounts,
+ required this.channelMasks,
+ required this.displayName,
+ this.encodingTypes,
+ });
+}
+
+class AudioEncodingType {
+ static const encodingTypeInvalid = AudioEncodingType._(-1);
+ static const encodingTypeRaw = AudioEncodingType._(0);
+ static const values = {
+ -1: encodingTypeInvalid,
+ 0: encodingTypeRaw,
+ };
+ final int value;
+ const AudioEncodingType._(this.value);
+ @override
+ bool operator ==(Object other) =>
+ other is AudioEncodingType && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+enum DeviceRole {
+ inputDevice,
+ outputDevice,
+}
+
+extension DeviceRoleExtension on DeviceRole {
+ static DeviceRole getEnum(int value) {
+ switch (value) {
+ case 1:
+ return DeviceRole.inputDevice;
+ case 2:
+ return DeviceRole.outputDevice;
+ default:
+ return DeviceRole.inputDevice;
+ }
+ }
+}
+
+enum DeviceType {
+ invalid,
+ earpiece,
+ speaker,
+ wiredHeadset,
+ wiredHeadphones,
+ bluetoothSco,
+ bluetoothA2dp,
+ mic,
+ usbHeadset,
+ defaultDevice,
+}
+
+extension DeviceTypeExtension on DeviceType {
+ int get value => [0, 1, 2, 3, 4, 7, 8, 15, 22, 1000][index];
+ static DeviceType getEnum(int value) {
+ switch (value) {
+ case 0:
+ return DeviceType.invalid;
+ case 1:
+ return DeviceType.earpiece;
+ case 2:
+ return DeviceType.speaker;
+ case 3:
+ return DeviceType.wiredHeadset;
+ case 4:
+ return DeviceType.wiredHeadphones;
+ case 7:
+ return DeviceType.bluetoothSco;
+ case 8:
+ return DeviceType.bluetoothA2dp;
+ case 15:
+ return DeviceType.mic;
+ case 22:
+ return DeviceType.usbHeadset;
+ case 1000:
+ return DeviceType.defaultDevice;
+ default:
+ return DeviceType.defaultDevice;
+ }
+ }
+}
+
+enum AudioVolumeType {
+ voiceCall,
+ ringTone,
+ media,
+ alarm,
+ accessibility,
+ voiceAssistant,
+ ultraSonic,
+ all
+}
+
+extension AudioVolumeTypeExtension on AudioVolumeType {
+ int get value => [0, 2, 3, 4, 5, 9, 10, 100][index];
+}
+
+class OhosAudioAttributes {
+ final StreamUsage streamUsage;
+ final AudioSamplingRate samplingRate;
+ final AudioChannel channels;
+ final AudioSampleFormat sampleFormat;
+ final AudioEncodingType encodingType;
+
+ const OhosAudioAttributes({
+ this.streamUsage = StreamUsage.unknown,
+ this.samplingRate = AudioSamplingRate.sampleRate48000,
+ this.channels = AudioChannel.channel2,
+ this.sampleFormat = AudioSampleFormat.sampleFormatS16LE,
+ this.encodingType = AudioEncodingType.encodingTypeRaw,
+ });
+
+ OhosAudioAttributes.fromJson(Map data)
+ : this(
+ streamUsage: decodeMapEnum(
+ StreamUsage.values, data['streamUsage'] as int?,
+ defaultValue: StreamUsage.unknown),
+ samplingRate: decodeMapEnum(
+ AudioSamplingRate.values, data['samplingRate'] as int?,
+ defaultValue: AudioSamplingRate.sampleRate48000),
+ channels: decodeMapEnum(
+ AudioChannel.values, data['channels'] as int?,
+ defaultValue: AudioChannel.channel2),
+ sampleFormat: decodeMapEnum(
+ AudioSampleFormat.values, data['sampleFormat'] as int?,
+ defaultValue: AudioSampleFormat.sampleFormatS16LE),
+ encodingType: decodeMapEnum(
+ AudioEncodingType.values, data['encodingType'] as int?,
+ defaultValue: AudioEncodingType.encodingTypeRaw));
+
+ Map toJson() => {
+ 'streamUsage': streamUsage.value,
+ 'samplingRate': samplingRate.value,
+ 'channels': channels.value,
+ 'sampleFormat': sampleFormat.value,
+ 'encodingType': encodingType.value,
+ };
+}
+
+class StreamUsage {
+ static const unknown = StreamUsage._(0);
+ static const music = StreamUsage._(1);
+ static const voiceCommunication = StreamUsage._(2);
+ static const voiceAssistant = StreamUsage._(3);
+ static const alarm = StreamUsage._(4);
+ static const voiceMessage = StreamUsage._(5);
+ static const ringTone = StreamUsage._(6);
+ static const notification = StreamUsage._(7);
+ static const accessibility = StreamUsage._(8);
+ static const movie = StreamUsage._(10);
+ static const game = StreamUsage._(11);
+ static const audioBook = StreamUsage._(12);
+ static const navigation = StreamUsage._(13);
+ static const values = {
+ 0: unknown,
+ 1: music,
+ 2: voiceCommunication,
+ 3: voiceAssistant,
+ 4: alarm,
+ 5: voiceMessage,
+ 6: ringTone,
+ 7: notification,
+ 8: accessibility,
+ 10: movie,
+ 11: game,
+ 12: audioBook,
+ 13: navigation,
+ };
+ final int value;
+ const StreamUsage._(this.value);
+ @override
+ bool operator ==(Object other) =>
+ other is StreamUsage && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+class OhosInterruptListernerRequest {
+ final OhosAudioAttributes? audioAttributes;
+ final OhosOnAudioFocusChanged onAudioFocusChanged;
+ final bool isOnListener;
+
+ const OhosInterruptListernerRequest({
+ this.audioAttributes,
+ required this.onAudioFocusChanged,
+ required this.isOnListener,
+ });
+ Map toJson() => {
+ 'audioAttributes': audioAttributes?.toJson(),
+ 'isOnListener': isOnListener,
+ };
+}
+
+class AudioSamplingRate {
+ static const sampleRate8000 = AudioSamplingRate._(8000);
+ static const sampleRate11025 = AudioSamplingRate._(11024);
+ static const sampleRate12000 = AudioSamplingRate._(12000);
+ static const sampleRate16000 = AudioSamplingRate._(16000);
+ static const sampleRate22050 = AudioSamplingRate._(22050);
+ static const sampleRate24000 = AudioSamplingRate._(24000);
+ static const sampleRate32000 = AudioSamplingRate._(32000);
+ static const sampleRate44100 = AudioSamplingRate._(44100);
+ static const sampleRate48000 = AudioSamplingRate._(48000);
+ static const sampleRate64000 = AudioSamplingRate._(64000);
+ static const sampleRate96000 = AudioSamplingRate._(96000);
+
+ static const values = {
+ 8000: sampleRate8000,
+ 11024: sampleRate11025,
+ 12000: sampleRate12000,
+ 16000: sampleRate16000,
+ 22050: sampleRate22050,
+ 24000: sampleRate24000,
+ 32000: sampleRate32000,
+ 44100: sampleRate44100,
+ 48000: sampleRate48000,
+ 64000: sampleRate64000,
+ 96000: sampleRate96000,
+ };
+ final int value;
+ const AudioSamplingRate._(this.value);
+ @override
+ bool operator ==(Object other) =>
+ other is AudioSamplingRate && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+class AudioChannel {
+ static const channel1 = AudioChannel._(1);
+ static const channel2 = AudioChannel._(2);
+ static const channel3 = AudioChannel._(3);
+ static const channel4 = AudioChannel._(4);
+ static const channel5 = AudioChannel._(5);
+ static const channel6 = AudioChannel._(6);
+ static const channel7 = AudioChannel._(7);
+ static const channel8 = AudioChannel._(8);
+ static const channel9 = AudioChannel._(9);
+ static const channel10 = AudioChannel._(10);
+ static const channel11 = AudioChannel._(11);
+ static const channel12 = AudioChannel._(12);
+ static const channel13 = AudioChannel._(13);
+ static const channel14 = AudioChannel._(14);
+ static const channel15 = AudioChannel._(15);
+ static const channel16 = AudioChannel._(16);
+ static const values = {
+ 1: channel1,
+ 2: channel2,
+ 3: channel3,
+ 4: channel4,
+ 5: channel5,
+ 6: channel6,
+ 7: channel7,
+ 8: channel8,
+ 9: channel9,
+ 10: channel10,
+ 11: channel11,
+ 12: channel12,
+ 13: channel13,
+ 14: channel14,
+ 15: channel15,
+ 16: channel16,
+ };
+ final int value;
+ const AudioChannel._(this.value);
+
+ @override
+ bool operator ==(Object other) =>
+ other is AudioChannel && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+class AudioSampleFormat {
+ static const sampleFormatInvalid = AudioSampleFormat._(-1);
+ static const sampleFormatU8 = AudioSampleFormat._(0);
+ static const sampleFormatS16LE = AudioSampleFormat._(1);
+ static const sampleFormatS24LE = AudioSampleFormat._(2);
+ static const sampleFormatS32LE = AudioSampleFormat._(3);
+ static const sampleFormatF32LE = AudioSampleFormat._(4);
+ static const values = {
+ -1: sampleFormatInvalid,
+ 0: sampleFormatU8,
+ 1: sampleFormatS16LE,
+ 2: sampleFormatS24LE,
+ 3: sampleFormatS32LE,
+ 4: sampleFormatF32LE,
+ };
+ final int value;
+ const AudioSampleFormat._(this.value);
+ @override
+ bool operator ==(Object other) =>
+ other is AudioSampleFormat && value == other.value;
+
+ @override
+ int get hashCode => value.hashCode;
+}
+
+enum AudioConcurrencyMode {
+ concurrencyDefault,
+ concurrencyMixWithOthers,
+ concurrencyDuckOthers,
+ concurrencyPauseOthers,
+}
\ No newline at end of file
diff --git a/ohos/.gitignore b/ohos/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/ohos/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/ohos/build-profile.json5 b/ohos/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..b5cf54176f8d80660aec9b1757d42ce5b50b2267
--- /dev/null
+++ b/ohos/build-profile.json5
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "targets": [
+ {
+ "name": "default"
+ }
+ ]
+}
diff --git a/ohos/hvigorfile.ts b/ohos/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5cdfdb9dcf894f0a1c8e3e6bac99341cdb273f27
--- /dev/null
+++ b/ohos/hvigorfile.ts
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { harTasks } from '@ohos/hvigor-ohos-plugin';
\ No newline at end of file
diff --git a/ohos/index.ets b/ohos/index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..50548b8c1c2d6822d981d7ccb0332abfe781a348
--- /dev/null
+++ b/ohos/index.ets
@@ -0,0 +1,17 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import AudioSessionPlugin from './src/main/ets/components/plugin/AudioSessionPlugin';
+export default AudioSessionPlugin;
diff --git a/ohos/oh-package.json5 b/ohos/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..bf7909c59a69c4fc2b57078b9e180feea277c3c2
--- /dev/null
+++ b/ohos/oh-package.json5
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+{
+ "name": "audio_session",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "index.ets",
+ "author": "",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har"
+ }
+}
diff --git a/ohos/src/main/ets/components/plugin/AudioSessionPlugin.ets b/ohos/src/main/ets/components/plugin/AudioSessionPlugin.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0ff7dfe5da719fa3cb1033183973ac495c848679
--- /dev/null
+++ b/ohos/src/main/ets/components/plugin/AudioSessionPlugin.ets
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
+import MethodChannel, { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
+import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall';
+import OhosAudioManager from './OhosAudioManager';
+import { Log } from '@ohos/flutter_ohos';
+
+/** AudioSessionPlugin **/
+export default class AudioSessionPlugin implements FlutterPlugin, MethodCallHandler {
+ private channel: MethodChannel | null = null;
+ private ohosAudioManager: OhosAudioManager | null = null;
+ private static instances: AudioSessionPlugin[] = [];
+ private static configuration: Map;
+
+ constructor() {
+ }
+
+ getUniqueClassName(): string {
+ return "AudioSessionPlugin"
+ }
+
+ onAttachedToEngine(binding: FlutterPluginBinding): void {
+ this.channel = new MethodChannel(binding.getBinaryMessenger(), "com.ryanheise.audio_session");
+ this.channel.setMethodCallHandler(this);
+ this.ohosAudioManager = new OhosAudioManager(binding.getApplicationContext(), binding.getBinaryMessenger());
+ AudioSessionPlugin.instances.push(this);
+ }
+
+ onDetachedFromEngine(binding: FlutterPluginBinding): void {
+ if (this.channel != null) {
+ this.channel.setMethodCallHandler(null)
+ }
+ this.ohosAudioManager?.dispose();
+ this.ohosAudioManager = null;
+ let index = AudioSessionPlugin.instances.indexOf(this);
+ AudioSessionPlugin.instances.splice(index, 1);
+ }
+
+ onMethodCall(call: MethodCall, result: MethodResult): void {
+ Log.i("AudioSessionPlugin", "onMethodCall: " + call.method);
+ switch (call.method) {
+ case "setConfiguration": {
+ const args: Array = call.args as Array;
+ Log.i("AudioSessionPlugin", "setConfiguration: " + args[0]);
+ AudioSessionPlugin.configuration = args[0] as Map;
+ result.success(null);
+ this.invokeMethod("onConfigurationChanged", AudioSessionPlugin.configuration);
+ }
+ case "getConfiguration": {
+ result.success(AudioSessionPlugin.configuration);
+ break;
+ }
+ default:
+ result.notImplemented();
+ break;
+ }
+ }
+
+ private invokeMethod(method: string, ...args: Array): void {
+ for(let i = 0; i < AudioSessionPlugin.instances.length; i++) {
+ const list: ESObject[] = [...args]
+ AudioSessionPlugin.instances[i].channel?.invokeMethod(method, list);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ohos/src/main/ets/components/plugin/OhosAudioManager.ets b/ohos/src/main/ets/components/plugin/OhosAudioManager.ets
new file mode 100644
index 0000000000000000000000000000000000000000..6a74d8fc715847c90c5afaec090ea4899dfa66e3
--- /dev/null
+++ b/ohos/src/main/ets/components/plugin/OhosAudioManager.ets
@@ -0,0 +1,571 @@
+/**
+ * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { BinaryMessenger, Log, MethodCall } from '@ohos/flutter_ohos';
+import MethodChannel, { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
+import { Context } from '@kit.AbilityKit';
+import audio from '@ohos.multimedia.audio';
+import { ArrayList, List } from '@kit.ArkTS';
+import { call } from '@kit.TelephonyKit';
+import { webSocket } from '@kit.NetworkKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+
+const TAG = "OhosAudioManager";
+
+export default class OhosAudioManager implements MethodCallHandler {
+ private messenger : BinaryMessenger | null;
+ public channel : MethodChannel | null;
+ private singleton : Singleton | null = null;
+
+ constructor(applicationContext: Context, messenger: BinaryMessenger) {
+ if(this.singleton == null) {
+ this.singleton = new Singleton(applicationContext);
+ }
+ this.messenger = messenger;
+ this.channel = new MethodChannel(messenger, "com.ryanheise.ohos_audio_manager");
+ this.singleton.add(this);
+ this.channel.setMethodCallHandler(this);
+ }
+ public onMethodCall(call: MethodCall, result: MethodResult): void {
+ try {
+ const args: Array = call.args as Array;
+ Log.i(TAG, "onMethodCall: " + call.method);
+ Log.i(TAG, "onMethodCall: args: " + JSON.stringify(args));
+ switch (call.method) {
+ case "setActive": {
+ result.success(this.singleton?.setActive(args));
+ break;
+ }
+ case "dispatchMediaKeyEvent": {
+ result.success(this.singleton?.dispatchMediaKeyEvent(call.args));
+ break;
+ }
+ case "isVolumeUnadjustable": {
+ result.success(this.singleton?.isVolumeFixed());
+ break;
+ }
+ case "adjustStreamVolume": {
+ result.success(this.singleton?.adjustStreamVolume(args[0] as number,
+ args[1] as number, args[2] as number));
+ break;
+ }
+ case "adjustVolume": {
+ result.success(this.singleton?.adjustVolume(args[0] as number, args[1] as number));
+ }
+ case "adjustSuggestedStreamVolume": {
+ result.success(this.singleton?.adjustSuggestedStreamVolume(args[0] as number,
+ args[1] as number, args[2] as number));
+ break;
+ }
+ case "getRingerMode": {
+ result.success(this.singleton?.getRingerMode());
+ break;
+ }
+ case "getMaxVolume": {
+ result.success(this.singleton?.getMaxVolume(args[0] as number));
+ break;
+ }
+ case "getMinVolume": {
+ result.success(this.singleton?.getMinVolume(args[0] as number));
+ break;
+ }
+ case "getVolume": {
+ result.success(this.singleton?.getVolume(args[0] as number));
+ break;
+ }
+ case "getSystemVolumeInDb": {
+ result.success(this.singleton?.getSystemVolumeInDb(args[0] as number,
+ args[1] as number, args[2] as number));
+ break;
+ }
+ case "setRingerMode": {
+ result.success(this.singleton?.setRingerMode(args[0] as number));
+ break;
+ }
+ case "setStreamVolume": {
+ result.success(this.singleton?.setStreamVolume(args[0] as number,
+ args[1] as number, args[2] as number));
+ break;
+ }
+ case "isMute": {
+ result.success(this.singleton?.isMute(args[0] as number));
+ break;
+ }
+ case "getAvailableCommunicationDevices": {
+ result.success(this.singleton?.getAvailableCommunicationDevices());
+ break;
+ }
+ case "setCommunicationDevice": {
+ result.success(this.singleton?.setCommunicationDevice(args[0] as number));
+ break;
+ }
+ case "getCommunicationDevice": {
+ result.success(this.singleton?.getCommunicationDevice());
+ break;
+ }
+ case "clearCommunicationDevice": {
+ result.success(this.singleton?.clearCommunicationDevice());
+ break;
+ }
+ case "setSpeakerphoneOn": {
+ result.success(this.singleton?.setSpeakerphoneOn(args[0] as boolean));
+ break;
+ }
+ case "isSpeakerphoneOn": {
+ result.success(this.singleton?.isSpeakerphoneOn());
+ break;
+ }
+ case "setAllowedCapturePolicy": {
+ result.success(this.singleton?.setAllowedCapturePolicy(args[0] as number));
+ break;
+ }
+ case "getAllowedCapturePolicy": {
+ result.success(this.singleton?.getAllowedCapturePolicy());
+ break;
+ }
+ case "isBluetoothScoAvailableOffCall": {
+ result.success(this.singleton?.isBluetoothScoAvailableOffCall());
+ break;
+ }
+ case "startBluetoothSco": {
+ result.success(this.singleton?.startBluetoothSco());
+ break;
+ }
+ case "stopBluetoothSco": {
+ result.success(this.singleton?.stopBluetoothSco());
+ break;
+ }
+ case "setBluetoothScoOn": {
+ result.success(this.singleton?.setBluetoothScoOn(args[0] as boolean));
+ break;
+ }
+ case "isBluetoothScoOn": {
+ result.success(this.singleton?.isBluetoothScoOn());
+ break;
+ }
+ case "setMicrophoneMute": {
+ result.success(this.singleton?.setMicrophoneMute(args[0] as boolean));
+ break;
+ }
+ case "isMicrophoneMute": {
+ result.success(this.singleton?.isMicrophoneMute());
+ break;
+ }
+ case "setMode": {
+ result.success(this.singleton?.setMode(args[0] as number));
+ break;
+ }
+ case "getAudioScene": {
+ result.success(this.singleton?.getAudioScene());
+ break;
+ }
+ case "isMusicActive": {
+ result.success(this.singleton?.isMusicActive());
+ break;
+ }
+ case "generateAudioSessionId": {
+ result.success(this.singleton?.generateAudioSessionId());
+ break;
+ }
+ case "setAudioParameter": {
+ result.success(this.singleton?.setAudioParameter(args[0] as string, args[1] as string));
+ break;
+ }
+ case "getAudioParameter": {
+ result.success(this.singleton?.getAudioParameter(args[0] as string));
+ break;
+ }
+ case "getProperty": {
+ result.success(this.singleton?.getProperty(args[0] as string));
+ break;
+ }
+ case "getDevices": {
+ result.success(this.singleton?.getDevices(args[0] as number));
+ break;
+ }
+ case "getMicrophones": {
+ result.success(this.singleton?.getMicrophones());
+ break;
+ }
+ case "isHapticPlaybackSupported": {
+ result.success(this.singleton?.isHapticPlaybackSupported());
+ break;
+ }
+ case "setInterruptionEventListener": {
+ this.singleton?.setInterruptionEventListener(args[0] as Map, result);
+ break;
+ }
+ default: {
+ result.notImplemented();
+ break;
+ }
+ }
+ } catch (err) {
+ result.error("Error: " + err, null, null);
+ }
+ }
+
+ public dispose(): void {
+ this.channel?.setMethodCallHandler(null);
+ this.singleton?.remove(this);
+ if(this.singleton?.isEmpty()) {
+ this.singleton?.dispose();
+ this.singleton = null;
+ }
+ this.channel = null;
+ this.messenger = null;
+ }
+
+}
+
+class Singleton {
+ private instances: OhosAudioManager[];
+ private applicationContext: Context | null;
+ private audioManager: audio.AudioManager | null;
+ private audioDeviceDescriptors: audio.AudioDeviceDescriptors | undefined;
+ private audioActive: boolean = false;
+ private audioRender: audio.AudioRenderer | null = null;
+
+ constructor(applicationContext: Context) {
+ this.instances = [];
+ this.applicationContext = applicationContext;
+ this.audioManager = audio.getAudioManager();
+ this.audioDeviceDescriptors = undefined;
+ this.initAudioDeviceCallback();
+ }
+
+ private initAudioDeviceCallback(): void {
+ this.audioManager?.getRoutingManager().on("deviceChange", audio.DeviceFlag.ALL_DEVICES_FLAG,
+ (device: audio.DeviceChangeAction) => {
+ if(device.type == audio.DeviceChangeType.CONNECT) {
+ this.invokeMethod("onAudioDevicesAdded", this.encodeAudioDevices(device.deviceDescriptors));
+ } else if(device.type == audio.DeviceChangeType.DISCONNECT) {
+ this.invokeMethod("onAudioDevicesRemoved", this.encodeAudioDevices(device.deviceDescriptors));
+ }
+
+ });
+ }
+
+ private encodeAudioDevices(devices: audio.AudioDeviceDescriptors): Map[] {
+ let result: Map[] = [];
+ for(let i = 0; i < devices.length; i++) {
+ result.push(this.encodeAudioDevice(devices[i]));
+ }
+ return result;
+ }
+
+ private encodeAudioDevice(device: audio.AudioDeviceDescriptor): Map {
+ let deviceMap: Map = new Map();
+ deviceMap.set("deviceRole", device.deviceRole);
+ deviceMap.set("deviceType", device.deviceType);
+ deviceMap.set("id", device.id);
+ deviceMap.set("name", device.name);
+ deviceMap.set("address", device.address);
+ deviceMap.set("sampleRates", device.sampleRates);
+ deviceMap.set("channelMasks", device.channelMasks);
+ deviceMap.set("displayName", device.displayName);
+ deviceMap.set("channelIndexMasks", device.channelMasks);
+ deviceMap.set("channelCounts", device.channelCounts);
+ return deviceMap;
+ }
+
+ private decodeAudioRendererOptions(attributes: Map): audio.AudioRendererOptions | null {
+ if(!attributes.has("sampleRate") || !attributes.has("channels") || !attributes.has("sampleFormat")
+ || !attributes.has("encodingType") || !attributes.has("streamUsage")) {
+ return null;
+ }
+ let audioStreamInfo: audio.AudioStreamInfo = {
+ samplingRate: attributes.get("sampleRate") as audio.AudioSamplingRate,
+ channels: attributes.get("channels") as audio.AudioChannel,
+ sampleFormat: attributes.get("sampleFormat") as audio.AudioSampleFormat,
+ encodingType: attributes.get("encodingType") as audio.AudioEncodingType,
+ };
+ let audioRendererInfo: audio.AudioRendererInfo = {
+ usage: attributes.get("streamUsage") as audio.StreamUsage,
+ rendererFlags: 0,
+ };
+ let audioRendererOptions: audio.AudioRendererOptions = {
+ streamInfo: audioStreamInfo,
+ rendererInfo: audioRendererInfo,
+ };
+ return audioRendererOptions;
+ }
+
+ public add(manager: OhosAudioManager): void {
+ this.instances.push(manager);
+ }
+ public remove(manager: OhosAudioManager): void {
+ const index = this.instances.indexOf(manager);
+ if(index != -1) {
+ this.instances.splice(index, 1);
+ }
+ }
+
+ public isEmpty() {
+ return this.instances.length == 0;
+ }
+
+ public dispose(): void {
+ this.disposeAudioDeviceCallback();
+ this.applicationContext = null;
+ this.audioManager = null;
+ }
+
+ public async setInterruptionEventListener(args: Map, result: MethodResult): Promise {
+ let audioRendererOptions: audio.AudioRendererOptions | null = null;
+ audioRendererOptions = this.decodeAudioRendererOptions(args);
+ if(audioRendererOptions == null) {
+ let audioStreamInfo: audio.AudioStreamInfo = {
+ samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
+ channels: audio.AudioChannel.CHANNEL_1,
+ sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
+ encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW,
+ };
+ let audioRendererInfo: audio.AudioRendererInfo = {
+ usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
+ rendererFlags: 0,
+ };
+ audioRendererOptions = {
+ streamInfo: audioStreamInfo,
+ rendererInfo: audioRendererInfo,
+ };
+ }
+ try {
+ this.audioRender = await audio.createAudioRenderer(audioRendererOptions);
+ this.audioRender?.on("audioInterrupt",(event: audio.InterruptEvent) => {
+ this.invokeMethod("onAudioInterrupt", event.eventType);
+ })
+ } catch (err) {
+ Log.e(TAG, " set audioInterrupt err:" + JSON.stringify(err));
+ }
+ result.success(true);
+ return true;
+ }
+
+ private disposeAudioDeviceCallback(): void {
+ this.audioManager?.getRoutingManager().off("deviceChange");
+ }
+
+ private invokeMethod(method: string, ...args: Array): void {
+ for(let i = 0; i < this.instances.length; i++) {
+ const list: ESObject[] = [...args]
+ this.instances[i].channel?.invokeMethod(method, list);
+ }
+ }
+
+ public setActive(args: Array): boolean {
+ this.audioActive = args[0] as boolean;
+ return true;
+ }
+
+ public dispatchMediaKeyEvent(rawKeyEvent: ESObject): ESObject {
+ return null;
+ }
+
+ public isVolumeFixed(): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .isVolumeUnadjustable();
+ }
+
+ public adjustStreamVolume(streamType: number, direction: number, flags: number): ESObject {
+ //TODO: AudioVolumeGroupManager.adjustSystemVolumeByStep
+ return null;
+ }
+
+ public adjustVolume(direction: number, flags: number): ESObject {
+ //TODO: AudioVolumeGroupManager.setVolume
+ return null;
+ }
+
+ public adjustSuggestedStreamVolume(direction: number, suggestedStreamType: number, flags: number): ESObject {
+ //TODO: no ohos api
+ return null;
+ }
+
+ public getRingerMode(): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .getRingerModeSync();
+ }
+
+ public getMaxVolume(streamType: number): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .getMaxVolumeSync(streamType);
+ }
+
+ public getMinVolume(streamType: number): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .getMinVolumeSync(streamType);
+ }
+
+ public getVolume(streamType: number): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .getVolumeSync(streamType);
+ }
+
+ public getSystemVolumeInDb(streamType: number, index: number, deviceType: number): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .getSystemVolumeInDbSync(streamType, index, deviceType);
+ }
+
+ public setRingerMode(ringerMode: number): ESObject {
+ //TODO: setRingerMode
+ return null;
+ }
+
+ public setStreamVolume(streamType: number, index: number, flags: number): ESObject {
+ //TODO: setVolume
+ return null;
+ }
+
+ public isMute(streamType: number): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .isMuteSync(streamType);
+ }
+
+ public getAvailableCommunicationDevices():Map[] {
+ this.audioDeviceDescriptors = this.audioManager?.getRoutingManager().getDevicesSync(audio.DeviceFlag.OUTPUT_DEVICES_FLAG);
+ let result: Map[] = [];
+ if(this.audioDeviceDescriptors != undefined) {
+ for(let i = 0; i < this.audioDeviceDescriptors?.length; i++) {
+ result.push(this.encodeAudioDevice(this.audioDeviceDescriptors[i]));
+ }
+ }
+ return result
+ }
+
+ public setCommunicationDevice(deviceId: number): boolean {
+ this.audioDeviceDescriptors?.forEach(device =>{
+ if(device.id == deviceId) {
+ //TODO: setCommunicationDevice
+ }
+ })
+ return false;
+ }
+
+ public getCommunicationDevice(): Map {
+ //TODO: getCommunicationDevice
+ return new Map();
+ }
+
+ public clearCommunicationDevice(): ESObject {
+ //TODO: clearCommunicationDevice
+ return null;
+ }
+
+ public setSpeakerphoneOn(enabled: boolean): ESObject {
+ this.audioManager?.getRoutingManager().setCommunicationDevice(audio.CommunicationDeviceType.SPEAKER, enabled);
+ return null;
+ }
+
+ public isSpeakerphoneOn(): ESObject {
+ return this.audioManager?.getRoutingManager().isCommunicationDeviceActiveSync(audio.CommunicationDeviceType.SPEAKER);
+ }
+
+ public setAllowedCapturePolicy(capturePolicy: number): ESObject {
+ //TODO: setAllowedCapturePolicy
+ return null;
+ }
+
+ public getAllowedCapturePolicy(): ESObject {
+ //TODO: getAllowedCapturePolicy
+ return null;
+ }
+
+ public isBluetoothScoAvailableOffCall(): ESObject {
+ //TODO: isBluetoothScoAvailableOffCall
+ }
+
+ public startBluetoothSco(): ESObject {
+ //TODO: startBluetoothSco
+ }
+
+ public stopBluetoothSco(): ESObject {
+ //TODO: stopBluetoothSco
+ }
+
+ public setBluetoothScoOn(enabled: boolean): ESObject {
+ //TODO: setBluetoothScoOn
+ }
+
+ public isBluetoothScoOn(): ESObject {
+ //TODO: isBluetoothScoOn
+ }
+
+ public setMicrophoneMute(enabled: boolean): ESObject {
+ this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .setMicrophoneMute(enabled);
+ return null;
+ }
+
+ public isMicrophoneMute(): ESObject {
+ return this.audioManager?.getVolumeManager().getVolumeGroupManagerSync(audio.DEFAULT_VOLUME_GROUP_ID)
+ .isMicrophoneMuteSync();
+ }
+
+ public setMode(mode: number): ESObject {
+ //TODO: audioManager.setAudioScene
+ return null;
+ }
+
+ public getAudioScene(): ESObject {
+ return this.audioManager?.getAudioSceneSync();
+ }
+
+ public isMusicActive(): ESObject {
+ return this.audioManager?.getStreamManager().isActiveSync(audio.AudioVolumeType.MEDIA);
+ }
+
+ public generateAudioSessionId(): ESObject {
+ //TODO: no oh api
+ }
+
+ public setAudioParameter(key: string, value: string): ESObject {
+ this.audioManager?.setAudioParameter(key, value);
+ return null;
+ }
+
+ public getAudioParameter(key: string): ESObject {
+ this.audioManager?.getAudioParameter(key);
+ }
+
+
+ public getProperty(arg: string): ESObject {
+ return null;
+ }
+
+ public getDevices(flags: number): ESObject {
+ let result: Array