在这里插入图片描述

1 -> 概述

鸿蒙6.0(HarmonyOS 6.0)在 AVSession Kit(音视频播控服务)中新增了一项重要能力:跨设备私有数据发送。这一能力通过在三个核心类——AVSessionAVSessionControllerAVCastController 中统一新增 sendCustomData 方法实现,支持在媒体应用(会话提供方)、播控中心(会话控制方)以及投播控制器之间发送自定义私有数据到远端设备。

这一特性的引入,标志着鸿蒙分布式媒体播控体系从“单向控制”向“双向数据互通”的演进。在此之前,AVSession 主要承载的是标准化的媒体信息(元数据)和播放控制命令(播放、暂停、下一首等)。但实际业务场景中,仅靠标准化数据远远不够——例如:

  • 直播场景需要传输弹幕消息、礼物特效指令
  • 投播场景需要同步播放列表、当前播放进度(精确到毫秒)
  • 音乐播放器需要同步歌词同步时间戳、音效设置
  • 视频应用需要传输字幕语言偏好、画质选择

新增的 sendCustomData 接口,为这些私有数据提供了一个直达远端设备的传输通道。

在鸿蒙的媒体会话体系中,主要涉及三类角色:

  1. 媒体会话提供方AVSession):音视频应用的会话实例,负责设置媒体元数据、播放状态等,并响应控制命令。媒体会话提供方通过 AVSession 对象调用 sendCustomData,可以向所有已连接的媒体会话控制方(如播控中心)发送私有数据。
  2. 媒体会话控制方AVSessionController):播控中心等系统应用的控制器实例,负责监听会话状态、发送控制命令。媒体会话控制方通过 AVSessionController 对象调用 sendCustomData,可以向指定的媒体会话提供方发送私有数据。
  3. 投播控制器AVCastController):投播场景中用于控制远端播放的接口。投播控制器通过 AVCastController 对象调用 sendCustomData,可以在投播主控端与远端设备之间传输私有数据。

2 -> 功能解析

2.1 -> AVSession 会话提供方发送私有数据

媒体应用(会话提供方)通过 AVSession 实例的 sendCustomData 方法,可以向所有媒体会话控制方发送私有数据。

接口签名:

sendCustomData(customData: { [key: string]: Object }): Promise<void>

参数说明:

参数名 类型 说明
customData { [key: string]: Object } 私有数据对象,以键值对形式传输,支持任意类型的数据

返回值: Promise<void>,异步操作结果。

系统能力: SystemCapability.Multimedia.AVSession.Core

使用示例:

import { avSession } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 假设已有 AVSession 实例 currentAVSession
async function sendCustomDataFromSession() {
    try {
        const customData = {
            type: 'lyric_sync',
            timestamp: Date.now(),
            lyricLine: '越过山丘 虽然已白了头',
            position: 125000  // 播放位置,毫秒
        };
        await currentAVSession.sendCustomData(customData);
        console.info('sendCustomData success');
    } catch (err) {
        let error = err as BusinessError;
        console.error(`sendCustomData failed: code=${error.code}, message=${error.message}`);
    }
}

应用场景: 音视频应用需要将自定义数据(如歌词同步信息、弹幕消息、播放列表变化)同步到播控中心或其他控制方时,使用此方法。

2.2 -> AVSessionController 会话控制方发送私有数据

播控中心等媒体会话控制方通过 AVSessionController 实例的 sendCustomData 方法,可以向指定的媒体会话提供方发送私有数据。

接口签名:

sendCustomData(customData: { [key: string]: Object }): Promise<void>

参数说明:AVSession.sendCustomData

错误码说明:

错误码ID 错误信息
6600101 Session service exception(会话服务异常)
6600102 The session does not exist(会话不存在)
6600103 The session controller does not exist(会话控制器不存在)

使用示例:

import { avSession } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 假设已有 AVSessionController 实例
async function sendCommandToSession() {
    try {
        const customData = {
            action: 'volume_up',
            step: 5,
            requestId: Date.now().toString()
        };
        await avSessionController.sendCustomData(customData);
        console.info('Control command sent');
    } catch (err) {
        let error = err as BusinessError;
        console.error(`sendCustomData failed: ${error.message}`);
    }
}

应用场景: 播控中心需要向音视频应用下发私有控制指令(如自定义音量调节、特效触发、画中画切换等),使用此方法。

2.3 -> AVCastController 投播控制器发送私有数据

投播场景中,应用通过 AVCastController 实例的 sendCustomData 方法,可以在投播主控端与远端设备之间传输私有数据。

接口签名:

sendCustomData(customData: { [key: string]: Object }): Promise<void>

参数说明:AVSession.sendCustomData

使用示例:

import { avSession } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 获取 AVCastController 实例
async function sendCustomDataToRemote() {
    try {
        // 通过 AVSession 获取 AVCastController
        const castController = await currentAVSession.getAVCastController();
        
        const customData = {
            type: 'playlist_sync',
            playlistId: 'playlist_12345',
            currentIndex: 3,
            nextTrackId: 'track_67890'
        };
        await castController.sendCustomData(customData);
        console.info('Custom data sent to remote device');
    } catch (err) {
        let error = err as BusinessError;
        console.error(`sendCustomData to remote failed: ${error.message}`);
    }
}

应用场景: 投播场景中,主控端需要将播放列表、用户偏好设置、画质选择等私有数据传输到远端设备,使用此方法。

3 -> 完整实现示例

以下是一个完整的媒体应用接入示例,涵盖 AVSession 创建、激活、私有数据发送与接收等完整流程。

3.1 -> 步骤一:导入模块与权限配置

module.json5 配置:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.MEDIA_CONTROL"
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC"
      }
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "backgroundModes": ["audioPlayback", "dataTransfer"]
      }
    ]
  }
}

导入模块:

import { avSession } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

3.2 -> 步骤二:创建并激活 AVSession

@Entry
@Component
struct MediaPlayerPage {
  private tag: string = "MyMediaApp";
  private currentAVSession?: avSession.AVSession;
  private context = this.getUIContext().getHostContext();

  async aboutToAppear(): Promise<void> {
    await this.createAVSession();
  }

  async createAVSession(): Promise<void> {
    try {
      // 创建音频类型的 AVSession
      this.currentAVSession = await avSession.createAVSession(
        this.context,
        this.tag,
        "audio"
      );
      console.info(`AVSession created: ${this.currentAVSession.sessionId}`);

      // 设置媒体元数据
      const metadata: avSession.AVMetadata = {
        assetId: "song_001",
        title: "夜曲",
        artist: "周杰伦",
        album: "十一月的萧邦",
        duration: 300000  // 5分钟,毫秒
      };
      await this.currentAVSession.setAVMetadata(metadata);

      // 设置播放状态
      const playbackState: avSession.AVPlaybackState = {
        state: avSession.PlaybackState.PLAYBACK_STATE_PLAY,
        position: 0,
        speed: 1.0
      };
      await this.currentAVSession.setAVPlaybackState(playbackState);

      // 激活会话
      await this.currentAVSession.activate();
      console.info("AVSession activated");

      // 注册私有数据接收监听
      this.registerCustomDataListener();
    } catch (err) {
      let error = err as BusinessError;
      console.error(`createAVSession failed: code=${error.code}, message=${error.message}`);
    }
  }

  registerCustomDataListener(): void {
    if (!this.currentAVSession) return;

    // 监听来自控制方的私有数据
    this.currentAVSession.on('customDataReceive', (customData: { [key: string]: Object }) => {
      console.info(`Received custom data: ${JSON.stringify(customData)}`);
      this.handleReceivedCustomData(customData);
    });
  }

  handleReceivedCustomData(customData: { [key: string]: Object }): void {
    // 根据数据类型分发处理
    switch (customData.type) {
      case 'volume_control':
        // 处理音量控制
        break;
      case 'lyric_sync_request':
        // 处理歌词同步请求
        break;
      default:
        console.info(`Unknown custom data type: ${customData.type}`);
    }
  }

  async sendCustomDataToController(): Promise<void> {
    if (!this.currentAVSession) return;

    try {
      const customData = {
        type: 'playlist_update',
        playlistId: 'playlist_123',
        totalTracks: 15,
        currentTrackId: 'track_005',
        timestamp: Date.now()
      };
      await this.currentAVSession.sendCustomData(customData);
      console.info('Custom data sent to controllers');
    } catch (err) {
      let error = err as BusinessError;
      console.error(`sendCustomData failed: ${error.message}`);
    }
  }

  build() {
    Column() {
      Text('媒体播放器')
        .fontSize(20)
        .margin(10)
      Button('发送私有数据')
        .onClick(() => this.sendCustomDataToController())
        .margin(10)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

3.3 -> 步骤三:投播场景集成

// 投播功能扩展
async function setupCasting(): Promise<void> {
  if (!currentAVSession) return;

  try {
    // 获取投播控制器
    const castController = await currentAVSession.getAVCastController();
    
    // 监听设备变化
    castController.on('castDeviceChange', (state: avSession.AVCastDeviceState, device: avSession.AVCastDeviceInfo) => {
      console.info(`Device ${device.deviceId} state changed: ${state}`);
      if (state === avSession.AVCastDeviceState.DEVICE_STATE_CONNECTED) {
        // 设备已连接,同步播放状态到远端
        syncPlaybackStateToRemote(castController);
      }
    });
    
    // 监听远端私有数据
    castController.on('customDataReceive', (customData: { [key: string]: Object }) => {
      console.info(`Remote custom data: ${JSON.stringify(customData)}`);
    });
  } catch (err) {
    let error = err as BusinessError;
    console.error(`getAVCastController failed: ${error.message}`);
  }
}

async function syncPlaybackStateToRemote(castController: avSession.AVCastController): Promise<void> {
  try {
    const syncData = {
      type: 'playback_state_sync',
      position: 125000,      // 当前播放位置,毫秒
      state: 'playing',
      speed: 1.0,
      volume: 0.8
    };
    await castController.sendCustomData(syncData);
    console.info('Playback state synced to remote device');
  } catch (err) {
    let error = err as BusinessError;
    console.error(`Sync failed: ${error.message}`);
  }
}

3.4 -> 步骤四:控制方集成示例

// 播控中心侧集成示例
async function createControllerAndSendData(sessionId: string): Promise<void> {
  try {
    // 创建会话控制器
    const controller = await avSession.createController(sessionId);
    
    // 监听会话的私有数据
    controller.on('customDataReceive', (customData: { [key: string]: Object }) => {
      console.info(`Custom data from session ${sessionId}: ${JSON.stringify(customData)}`);
    });
    
    // 向会话发送私有数据
    const command = {
      type: 'set_equalizer',
      preset: 'rock',
      bands: [0, 2, 4, 2, 0]
    };
    await controller.sendCustomData(command);
    console.info('Custom data sent to session');
  } catch (err) {
    let error = err as BusinessError;
    console.error(`Controller operation failed: ${error.message}`);
  }
}

4 -> 总结

4.1 -> 核心优势

  1. 统一的数据通道sendCustomData 接口在 AVSessionAVSessionControllerAVCastController 三个核心类中保持一致的签名和使用方式,开发者无需为不同角色编写差异化的数据传输逻辑,降低了学习成本和代码维护复杂度。

  2. 全场景覆盖:从本地媒体播放到跨设备投播,从应用提供方到系统控制方,私有数据通道覆盖了鸿蒙媒体生态的各个节点,真正实现了全链路的数据互通。

  3. 灵活的数据结构:键值对形式的自定义数据设计,支持任意类型的数据传输,应用可以根据业务需求自由定义数据结构,不受标准化字段的限制。

  4. 分布式原生支持:结合鸿蒙软总线技术,私有数据在跨设备传输时具备低延迟、高可靠性的特性,设备发现延迟低于 200ms,状态同步耗时控制在 100ms 以内。

  5. 与现有能力互补sendCustomData 并非替代原有的 setAVMetadatasetAVPlaybackState 等标准化接口,而是在此基础上提供了扩展通道。标准化数据用于系统级展示和控制,私有数据用于业务级定制交互,两者相辅相成。

4.2 -> 开发注意事项

  • 三方应用可以作为媒体会话提供方(AVSession 角色),但媒体会话控制方(AVSessionController)和投播组件的完整能力仅对系统应用开放。
  • sendCustomData 发送的数据不会被持久化存储,数据传输的生命周期与会话绑定。
  • 投播场景中,AVCastController 对象在设备断开连接后失效,再次使用需要重新获取。
  • 建议在 sendCustomData 调用时添加异常处理,避免因会话状态异常导致应用崩溃。
  • 私有数据的大小建议控制在一定范围内,过大的数据包可能影响传输效率。

4.3 -> 适用版本

sendCustomData 接口从 HarmonyOS 6.0(API Version 22)开始支持。使用前请确认开发环境和目标设备满足版本要求。

鸿蒙 6.0 中 sendCustomData 的引入,为音视频开发者提供了更灵活的跨设备通信手段。无论是直播场景的实时互动数据、音乐播放器的歌词同步信息,还是投播场景的用户偏好设置,都可以通过这一统一接口轻松实现。建议音视频类应用尽快适配该接口,以充分利用鸿蒙分布式能力带来的全场景体验优势。


感谢各位大佬支持!!!

互三啦!!!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐