深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
console.log(应用自身切换循环模式 ${mode}
);
// 设置播放状态
currentSession.setAVPlaybackState({loopMode: mode}).then(() => {
console.info(‘setAVPlaybackState successfully’);
}).catch((err) => {
console.info(setAVPlaybackState : ERROR : ${err.message}
);
});
});
// 注册设置歌曲收藏命令监听
currentSession.on(‘toggleFavorite’, (assetId) => {
console.log(应用保存当前assetId为喜爱 ${assetId}
);
// 根据上一次的状态进行切换
let favorite = mediaFavorite == false ? true : false;
currentSession.setAVPlaybackState({isFavorite: favorite}).then(() => {
console.info(‘setAVPlaybackState successfully’);
}).catch((err) => {
console.info(setAVPlaybackState : ERROR : ${err.message}
);
});
mediaFavorite = favorite;
});
// 注册媒体按键命令监听
currentSession.on(‘handleKeyEvent’, (event) => {
console.log(用户按键 ${event.keyCode}
);
});
// 注册播放设备变化命令监听
currentSession.on(‘outputDeviceChange’, (device) => {
console.log(输出设备变更,更新显示 ${device.deviceName}
);
});
5.释放资源
// 取消注册回调
currentSession.off(‘play’);
currentSession.off(‘pause’);
currentSession.off(‘stop’);
currentSession.off(‘playNext’);
currentSession.off(‘playPrevious’);
currentSession.off(‘fastForward’);
currentSession.off(‘rewind’);
currentSession.off(‘seek’);
currentSession.off(‘setSpeed’);
currentSession.off(‘setLoopMode’);
currentSession.off(‘toggleFavorite’);
currentSession.off(‘handleKeyEvent’);
currentSession.off(‘outputDeviceChange’);
// 去激活session并销毁对象
currentSession.deactivate().then(() => {
currentSession.destroy();
});
调测验证
在媒体应用上点击播放、暂停、下一首等按键,媒体播放状态出现相应变化。
常见问题
1.会话服务端异常 - 现象描述:
会话服务端异常,应用端无法获取服务端的消息响应。如会话服务未运行或者会话服务通信失败。返回错误信息: Session service exception。
- 可能原因:
会话重启过程中服务被杀。
- 解决办法
(1)定时重试,超过3s仍失败时,停止对该会话或者控制器进行操作。
(2)销毁当前会话或者会话控制器,并重新创建,如果重新创建失败,则停止会话相关操作。
2.会话不存在 - 现象描述:
会话对象不存在时,向该会话设置参数或者发送命令。返回错误信息: The session does not exist。
- 可能原因:
会话已被销毁,服务端无会话记录。
- 解决办法
(1)如果在会话被控端产生该错误,请重新创建会话;如果是会话控制端,请停止向该会话发送查询或者控制命令。
(2)如果在会话管理端产生该错误,请重新查询系统当前会话记录,在创建控制器时传入正确的会话ID。
3.会话未激活 - 现象描述:
会话没有激活时,向会话发送控制命令或者事件。。返回错误信息: The session not active。
- 可能原因:
会话处于未激活状态。
- 解决办法
停止发送该命令或事件,监听会话的激活状态,会话激活后恢复发送该命令或事件。
相关实例
提供音乐Demo的代码实例
会话控制端开发指导(播控中心)
基本概念
- 远端投播:将本地媒体投播到远端设备,通过本地控制器发送命令,可控制远端播放行为。
- 发送按键命令:控制器通过发送按键事件的方式控制媒体。
- 发送控制命令:控制器通过发送控制命令的方式控制媒体。
- 发送系统按键命令:应用拥有调用该接口的系统权限,通过发送按键事件的方式控制媒体,仅系统应用可用。
- 发送系统控制命令:应用拥有调用该接口的系统权限,通过发送控制命令的方式控制媒体,仅系统应用可用。
接口说明
会话控制端涉及的常用接口如下表所示。接口返回值有两种返回形式:callback和promise,下表中为callback形式接口,promise和callback只是返回值方式不一样,功能相同。更多API说明请参见API文档。
表2:会话控制端常用接口
接口名 | 描述 |
---|---|
getAllSessionDescriptors(callback: AsyncCallback<Array>): void | 获取所有会话的描述符 |
createController(sessionId: string, callback: AsyncCallback): void | 创建控制器 |
sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback): void | 发送按键命令 |
getLaunchAbility(callback: AsyncCallback): void | 拉起应用 |
sendControlCommand(command: AVControlCommand, callback: AsyncCallback): void | 发送控制命令 |
sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback): void | 发送系统按键命令 |
sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback): void | 发送系统控制命令 |
castAudio(session: SessionToken | ‘all’, audioDevices: Array<audio.AudioDeviceDescriptor>, callback: AsyncCallback): void |
开发步骤
1.导入模块接口
import avSession from ‘@ohos.multimedia.avsession’;
import {Action, KeyEvent} from ‘@ohos.multimodalInput.KeyEvent’;
import wantAgent from ‘@ohos.app.ability.wantAgent’;
import audio from ‘@ohos.multimedia.audio’;
2.获取会话描述符,创建控制器
// 全局变量定义
let g_controller = new Array<avSession.AVSessionController>();
let g_centerSupportCmd:Set<avSession.AVControlCommandType> = new Set([‘play’, ‘pause’, ‘playNext’, ‘playPrevious’, ‘fastForward’, ‘rewind’, ‘seek’,‘setSpeed’, ‘setLoopMode’, ‘toggleFavorite’]);
let g_validCmd:Set<avSession.AVControlCommandType>;
// 获取会话描述符,创建控制器
avSession.getAllSessionDescriptors().then((descriptors) => {
descriptors.forEach((descriptor) => {
avSession.createController(descriptor.sessionId).then((controller) => {
g_controller.push(controller);
}).catch((err) => {
console.error(‘createController error’);
});
});
}).catch((err) => {
console.error(‘getAllSessionDescriptors error’);
});
// 注册会话创建监听,创建控制器
avSession.on(‘sessionCreate’, (session) => {
// 新增会话,需要创建控制器
avSession.createController(session.sessionId).then((controller) => {
g_controller.push(controller);
}).catch((err) => {
console.info(createController : ERROR : ${err.message}
);
});
});
3.监听AVSession会话状态以及AVSession服务变化
// 注册会话激活状态变更监听
controller.on(‘activeStateChange’, (isActive) => {
if (isActive) {
console.log(“控制器卡片按键高亮”);
} else {
console.log(“控制器卡片按键变更为无效”);
}
});
// 注册会话销毁监听
controller.on(‘sessionDestroy’, () => {
console.info('on sessionDestroy : SUCCESS ');
controller.destroy().then(() => {
console.info('destroy : SUCCESS ');
}).catch((err) => {
console.info(destroy : ERROR :${err.message}
);
});
});
// 注册系统会话销毁监听
avSession.on(‘sessionDestroy’, (session) => {
let index = g_controller.findIndex((controller) => {
return controller.sessionId == session.sessionId;
});
if (index != 0) {
g_controller[index].destroy();
g_controller.splice(index, 1);
}
});
// 注册系统最高优先级会话变更监听
avSession.on(‘topSessionChange’, (session) => {
let index = g_controller.findIndex((controller) => {
return controller.sessionId == session.sessionId;
});
// 将该会话显示排到第一个
if (index != 0) {
g_controller.sort((a, b) => {
return a.sessionId == session.sessionId ? -1 : 0;
});
}
});
// 注册服务异常监听
avSession.on(‘sessionServiceDie’, () => {
// 服务端异常,应用清理资源
console.log(“服务端异常”);
})
4.监听AVSession会话信息变化
// 注册元数据更新监听
let metaFilter = [‘assetId’, ‘title’, ‘description’];
controller.on(‘metadataChange’, metaFilter, (metadata) => {
console.info(on metadataChange assetId : ${metadata.assetId}
);
});
// 注册播放状态更新监听
let playbackFilter = [‘state’, ‘speed’, ‘loopMode’];
controller.on(‘playbackStateChange’, playbackFilter, (playbackState) => {
console.info(on playbackStateChange state : ${playbackState.state}
);
});
// 注册会话支持的命令变更监听
controller.on(‘validCommandChange’, (cmds) => {
console.info(validCommandChange : SUCCESS : size : ${cmds.size}
);
console.info(validCommandChange : SUCCESS : cmds : ${cmds.values()}
);
g_validCmd.clear();
for (let c of g_centerSupportCmd) {
if (cmds.has©) {
g_validCmd.add©;
}
}
});
// 注册输出设备变更监听
controller.on(‘outputDeviceChange’, (device) => {
console.info(on outputDeviceChange device isRemote : ${device.isRemote}
);
});
5.控制AVSession会话行为
// 用户点击播放按键:发送控制命令–播放
if (g_validCmd.has(‘play’)) {
controller.sendControlCommand({command:‘play’}).then(() => {
console.info(‘sendControlCommand successfully’);
}).catch((err) => {
console.info(sendControlCommand : ERROR : ${err.message}
);
});
}
// 用户点击循环模式:发送控制命令–单曲循环
if (g_validCmd.has(‘setLoopMode’)) {
controller.sendControlCommand({command: ‘setLoopMode’, parameter: avSession.LoopMode.LOOP_MODE_SINGLE}).then(() => {
console.info(‘sendControlCommand successfully’);
}).catch((err) => {
console.info(sendControlCommand : ERROR : ${err.message}
);
});
}
// 发送按键事件
let keyItem = {code: 0x49, pressedTime: 123456789, deviceId: 0};
let event = {action: 2, key: keyItem, keys: [keyItem]};
controller.sendAVKeyEvent(event).then(() => {
console.info(‘sendAVKeyEvent Successfully’);
}).catch((err) => {
console.info(sendAVKeyEvent : ERROR : ${err.message}
);
});
// 用户点击卡片空白位置拉起应用
controller.getLaunchAbility().then((want) => {
console.log(“前台拉起应用”);
}).catch((err) => {
console.info(getLaunchAbility : ERROR : ${err.message}
);
});
// 发送系统媒体按键事件
let keyItem = {code: 0x49, pressedTime: 123456789, deviceId: 0};
let event = {action: 2, key: keyItem, keys: [keyItem]};
avSession.sendSystemAVKeyEvent(event).then(() => {
console.info(‘sendSystemAVKeyEvent Successfully’);
}).catch((err) => {
console.info(sendSystemAVKeyEvent : ERROR : ${err.message}
);
});
// 发送系统控制命令,系统会把控制命令发送到Top会话中
let avcommand = {command: ‘toggleFavorite’, parameter: “false”};
avSession.sendSystemControlCommand(avcommand).then(() => {
console.info(‘sendSystemControlCommand successfully’);
}).catch((err) => {
console.info(sendSystemControlCommand : ERROR : ${err.message}
);
});
// 投播到其他设备
let audioManager = audio.getAudioManager();
let audioDevices;
await audioManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG).then((data) => {
audioDevices = data;
console.info(‘Promise returned to indicate that the device list is obtained.’);
}).catch((err) => {
console.info(getDevices : ERROR : ${err.message}
);
});
avSession.castAudio(‘all’, audioDevices).then(() => {
console.info(‘createController : SUCCESS’);
}).catch((err) => {
console.info(createController : ERROR : ${err.message}
);
});
6.释放资源
// 取消注册回调
controller.off(‘metadataChange’);
controller.off(‘playbackStateChange’);
controller.off(‘sessionDestroy’);
controller.off(‘activeStateChange’);
controller.off(‘validCommandChange’);
controller.off(‘outputDeviceChange’);
// 销毁controller对象
controller.destroy().then(() => {
console.info('destroy : SUCCESS ');
}).catch((err) => {
console.info(destroy : ERROR : ${err.message}
);
});
调测验证
在播控中心点击播放、暂停、下一首等按键,应用播放状态随即发生相应变化。
常见问题
1.控制器不存在 - 现象描述:
会话控制器不存在时,向该控制器发送控制命令或者事件。返回错误信息: The session controller does not exist。
- 可能原因:
控制器已被销毁。
- 解决办法
请重新查询系统当前会话记录,并创建对应的会话控制器。
2.远端会话连接失败 - 现象描述:
本端会话与远端会话通信失败。返回错误信息: The remote session connection failed。
- 可能原因:
设备间通信断开。
- 解决办法
停止对该会话发送控制命令,并监听输出设备变化,当输出设备发送变化后恢复发送。
3.无效会话命令 - 现象描述:
会话被控端不支持该被控命令或事件。返回错误信息: Invalid session command。
- 可能原因:
被控端不支持该命令。
- 解决办法
停止发送该命令或事件,并查询被控会话支持的命令集,发送被控端支持的命令。
4.消息过载 - 现象描述:
会话客户端在一段时间内向服务端发送了过多的消息或者命令,引起服务端消息过载。返回错误信息: Command or event overload。
- 可能原因:
服务端消息过载。
- 解决办法
检查自身命令发送是否过于频繁,控制自身查询和控制命令的发送频度。
为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
《鸿蒙 (OpenHarmony)开发学习手册》
入门必看:https://qr21.cn/FV7h05
- 应用开发导读(ArkTS)
- ……
HarmonyOS 概念:https://qr21.cn/FV7h05
- 系统定义
- 技术架构
- 技术特性
- 系统安全
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
- 系统定义
- 技术架构
- 技术特性
- 系统安全
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
[外链图片转存中…(img-2qNeeZT2-1715167244699)]
[外链图片转存中…(img-mDKeRz64-1715167244699)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新