# TTMusic APP 播放流程详细分析 ## 1. 架构概览 TTMusic采用了分层架构设计,主要包含以下核心组件: - **UnifiedPlayerService**: 统一播放器服务,提供高级播放控制接口 - **PlayerManager**: 播放器管理器,负责ijkPlayer实例的管理和音频会话 - **PlayerStateModel**: 播放状态模型,管理播放状态并提供状态验证 - **PlaylistModel**: 播放列表模型,管理播放列表和播放导航逻辑 - **IjkMediaPlayer**: 基于ijkplayer的播放器核心实现 - **AvSessionController**: 系统媒体会话控制,实现系统级媒体控制 - **VideoItem**: 媒体数据模型,表示音频/视频文件 ## 2. 播放流程详细分析 ### 2.1 初始化流程 1. **应用启动时**: - [`UnifiedPlayerService.getInstance()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:146) 获取单例实例 - 调用 [`initialize(context)`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:152) 进行初始化 - 创建核心组件:PlayerManager、PlayerStateModel、PlaylistModel等 - 设置状态监听器和回调 2. **播放器初始化**: - [`PlayerManager.initialize()`](entry/src/main/ets/common/service/PlayerManager.ets:74) 初始化ijkplayer - [`setupIjkPlayerOptions()`](entry/src/main/ets/common/service/PlayerManager.ets:84) 配置播放器选项 - [`setupPlayerCallbacks()`](entry/src/main/ets/common/service/PlayerManager.ets:142) 设置播放器回调 3. **AVSession初始化**: - [`AvSessionController.getInstance()`](entry/src/main/ets/controller/AvSessionController.ets:40) 获取系统媒体会话控制器 - [`initAvSession()`](entry/src/main/ets/controller/AvSessionController.ets:47) 初始化系统媒体会话 - [`registerControlCommands()`](entry/src/main/ets/controller/AvSessionController.ets:232) 注册系统控制命令 ### 2.2 播放控制流程 #### 2.2.1 点击播放/恢复播放 1. **用户触发播放**: - UI调用 [`UnifiedPlayerService.startPlayOrResumePlay()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:262) 2. **服务就绪检查**: - [`isAllServicesReady()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:769) 检查所有服务是否就绪 - 如果未就绪,调用 [`waitForAllServicesReady()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:918) 等待服务初始化完成 3. **获取当前歌曲**: - [`playlistModel.getCurrentSong()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:278) 获取当前歌曲 - 如果没有歌曲,尝试从持久化存储恢复状态 4. **播放器状态检查**: - [`canResumeFromPause()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:319) 检查是否可以从暂停状态恢复 - 如果可以恢复,调用 [`resumeFromPause()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:365) 5. **设置播放器**: - [`setupPlayerForSong()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1436) 为当前歌曲配置播放器 - 调用 [`ijkPlayer.reset()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:186) 重置播放器状态 - [`ijkPlayer.setDataSource()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:110) 设置数据源 - [`ijkPlayer.setDataSourceHeader()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:118) 设置HTTP请求头 6. **准备播放**: - [`ijkPlayer.prepareAsync()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:154) 异步准备播放器 - 准备完成后触发 [`onPrepared()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2003) 回调 7. **开始播放**: - 在 [`onPrepared()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2003) 回调中 - 如果不是暂停状态,调用 [`ijkPlayer.start()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:162) 开始播放 - 触发 [`onPlaybackStarted()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2026) 回调 8. **状态更新**: - [`stateModel.updatePlayingState(true)`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2033) 更新播放状态 - [`startProgressTimer()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2036) 启动进度定时器 - [`saveCurrentState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2039) 保存当前状态 - [`updateSessionPlayState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2044) 更新系统媒体会话状态 #### 2.2.2 点击暂停 1. **用户触发暂停**: - UI调用 [`UnifiedPlayerService.pause()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:459) 2. **保存播放位置**: - [`savePlaybackPosition()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:471) 保存当前播放位置 3. **暂停播放器**: - [`playerManager.pausePlayback()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:474) 暂停播放器 - 内部调用 [`ijkPlayer.pause()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:178) 4. **更新状态**: - [`stateModel.updatePlayingState(false)`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:477) 更新播放状态为暂停 - [`stopProgressTimer()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:480) 停止进度定时器 - [`saveCurrentState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:486) 保存播放状态 - [`updateSessionPlayState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:489) 更新系统媒体会话状态 #### 2.2.3 点击下一首 1. **用户触发下一首**: - UI调用 [`UnifiedPlayerService.playNext()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:550) 2. **服务就绪检查**: - [`isAllServicesReady()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:553) 检查服务是否就绪 3. **播放列表导航**: - [`playlistModel.hasNext()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:565) 检查是否有下一首 - [`playlistModel.moveToNext()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:568) 移动到下一首 4. **更新状态模型**: - [`stateModel.updateCurrentIndex()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:574) 更新当前索引 - [`stateModel.updateCurrentSong()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:579) 更新当前歌曲 5. **停止当前播放**: - [`stopSilently()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:583) 静默停止当前播放 6. **播放新歌曲**: - [`playNewSongDirectly()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:586) 直接播放新歌曲 - 内部调用 [`setupPlayerForSong()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1436) 和 [`ijkPlayer.prepareAsync()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:154) #### 2.2.4 点击上一首 1. **用户触发上一首**: - UI调用 [`UnifiedPlayerService.playPrevious()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:601) 2. **流程与下一首类似**: - 服务就绪检查 - 播放列表导航([`playlistModel.hasPrevious()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:616) 和 [`playlistModel.moveToPrevious()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:624)) - 更新状态模型 - 停止当前播放 - 播放新歌曲 ### 2.3 播放器状态管理 #### 2.3.1 状态回调机制 1. **PlayerManager回调**: - [`onPrepared()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2003): 播放器准备完成 - [`onPlaybackStarted()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2026): 播放开始 - [`onPlaybackCompleted()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2054): 播放完成 - [`onPlaybackError()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:2068): 播放错误 2. **PlayerStateModel状态更新**: - [`updatePlayingState()`](entry/src/main/ets/common/service/PlayerStateModel.ets:128): 更新播放状态 - [`updateLoadingState()`](entry/src/main/ets/common/service/PlayerStateModel.ets:146): 更新加载状态 - [`updateProgress()`](entry/src/main/ets/common/service/PlayerStateModel.ets:157): 更新播放进度 - [`updateCurrentSong()`](entry/src/main/ets/common/service/PlayerStateModel.ets:244): 更新当前歌曲 3. **状态监听通知**: - [`notifyStateChanged()`](entry/src/main/ets/common/service/PlayerStateModel.ets:372): 通知状态变化 - [`notifyProgressChanged()`](entry/src/main/ets/common/service/PlayerStateModel.ets:386): 通知进度变化 - [`notifySongChanged()`](entry/src/main/ets/common/service/PlayerStateModel.ets:407): 通知歌曲变化 #### 2.3.2 进度更新机制 1. **进度定时器**: - [`setupProgressTimer()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1486) 设置进度定时器 - 每秒调用 [`updateProgress()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1509) 更新进度 2. **进度获取**: - [`ijkPlayer.getCurrentPosition()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:393) 获取当前播放位置 - [`ijkPlayer.getDuration()`](ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer.ets:382) 获取总时长 3. **进度保存**: - [`savePlaybackPosition()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1553) 保存播放位置 - 使用PreferencesUtil保存到本地存储 ### 2.4 系统媒体会话控制 #### 2.4.1 AVSession初始化 1. **创建会话**: - [`avSession.createAVSession()`](entry/src/main/ets/controller/AvSessionController.ets:60) 创建系统媒体会话 2. **设置元数据**: - [`setAVMetadataMusic()`](entry/src/main/ets/controller/AvSessionController.ets:138) 设置音乐元数据 - 包含标题、艺术家、专辑、封面图等信息 3. **设置播放状态**: - [`setAvSessionPlayState()`](entry/src/main/ets/controller/AvSessionController.ets:213) 设置播放状态 - 包含播放状态、位置、循环模式等信息 #### 2.4.2 系统控制命令处理 1. **命令监听**: - [`setAvSessionListener()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1131) 设置系统控制监听器 - 监听播放、暂停、停止、下一首、上一首、拖动等命令 2. **命令处理**: - 接收到系统命令后,调用对应的播放控制方法 - 例如:播放命令调用 [`startPlayOrResumePlay()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:262) ### 2.5 播放列表管理 #### 2.5.1 播放列表操作 1. **添加歌曲**: - [`addSong()`](entry/src/main/ets/common/service/PlaylistModel.ets:82) 添加单首歌曲 - [`addSongs()`](entry/src/main/ets/common/service/PlaylistModel.ets:98) 添加多首歌曲 2. **移除歌曲**: - [`removeSong()`](entry/src/main/ets/common/service/PlaylistModel.ets:120) 移除歌曲 3. **替换播放列表**: - [`replaceSongs()`](entry/src/main/ets/common/service/PlaylistModel.ets:183) 替换整个播放列表 #### 2.5.2 播放模式 1. **播放模式类型**: - [`PlayMode.SEQUENCE`](entry/src/main/ets/common/service/PlayerStateModel.ets:8): 顺序播放 - [`PlayMode.SINGLE_REPEAT`](entry/src/main/ets/common/service/PlayerStateModel.ets:9): 单曲循环 - [`PlayMode.NORMAL`](entry/src/main/ets/common/service/PlayerStateModel.ets:10): 正常播放 - [`PlayMode.RANDOM`](entry/src/main/ets/common/service/PlayerStateModel.ets:11): 随机播放 2. **播放模式切换**: - [`setPlayMode()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:960) 设置播放模式 - [`getPlayMode()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:966) 获取当前播放模式 ### 2.6 数据持久化 #### 2.6.1 状态保存 1. **播放状态保存**: - [`saveCurrentState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1717) 保存当前播放状态 - 使用DataPersistenceService保存到持久化存储 2. **播放位置保存**: - [`savePlaybackPosition()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1553) 保存播放位置 - 使用PreferencesUtil保存到本地存储 #### 2.6.2 状态恢复 1. **从内存恢复**: - [`fastRestoreFromMemory()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1604) 从AppStorage快速恢复 2. **从持久化存储恢复**: - [`restorePersistedState()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1647) 从持久化存储恢复状态 3. **播放位置恢复**: - [`restorePlaybackPosition()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1571) 恢复播放位置 ## 3. 错误处理机制 ### 3.1 错误类型 - [`PlayerErrorType.INITIALIZATION_ERROR`](entry/src/main/ets/common/service/PlayerStateModel.ets:49): 初始化错误 - [`PlayerErrorType.PLAYBACK_ERROR`](entry/src/main/ets/common/service/PlayerStateModel.ets:50): 播放错误 - [`PlayerErrorType.NETWORK_ERROR`](entry/src/main/ets/common/service/PlayerStateModel.ets:51): 网络错误 - [`PlayerErrorType.FILE_NOT_FOUND`](entry/src/main/ets/common/service/PlayerStateModel.ets:52): 文件未找到 - [`PlayerErrorType.AUDIO_FOCUS_ERROR`](entry/src/main/ets/common/service/PlayerStateModel.ets:53): 音频焦点错误 ### 3.2 错误恢复策略 1. **错误处理**: - [`handlePlaybackError()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1231) 处理播放错误 - [`executeRecoveryAction()`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1263) 执行恢复动作 2. **恢复动作**: - [`ErrorRecoveryAction.RETRY`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1265): 重试 - [`ErrorRecoveryAction.SKIP_TO_NEXT`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1269): 跳到下一首 - [`ErrorRecoveryAction.STOP_PLAYBACK`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1273): 停止播放 - [`ErrorRecoveryAction.WAIT_AND_RETRY`](entry/src/main/ets/common/service/UnifiedPlayerService.ets:1277): 等待后重试 ## 4. 总结 TTMusic的播放流程采用了分层架构设计,通过UnifiedPlayerService提供统一的播放控制接口,底层使用ijkplayer进行实际的音频解码和播放。整个播放流程包括初始化、播放控制、状态管理、系统媒体会话控制、播放列表管理、数据持久化和错误处理等环节,形成了一个完整的音乐播放器系统。 系统通过状态模型、播放列表模型和播放器管理器的协同工作,实现了复杂的播放控制逻辑,同时通过AVSessionController与系统媒体控制进行集成,提供了系统级的媒体控制体验。