浏览代码

更新版本到 1.5.7

ChangeLog
1. 新增 removeStream 方法,用于删除通过 createStream 创建且未发布的流
2. 修复 createStream 创建的屏幕共享预览流,无 screenshare-stopped 事件通知的问题
3. 修复 resume 后 getAudioVolume 仍无法获取正确音量的问题
4. 修复 mute 订阅流未通知到服务器的问题
5. 修复未订阅流时,收到 mute 信令,但 sdk 未修正该流的 mute 状态的问题
6. 修复通过 createStream 创建的流未暴露 mediaStream 的问题
7. 修复部分浏览器在屏幕共享时报错而无法推流的问题
kevin.song 5 年之前
父节点
当前提交
8683e21681
共有 4 个文件被更改,包括 233 次插入191 次删除
  1. 30 3
      README.md
  2. 3 3
      lib/index.js
  3. 1 1
      package.json
  4. 199 184
      types/index.d.ts

+ 30 - 3
README.md

@@ -87,6 +87,7 @@ Client 类包含以下方法:
 * [stopRelay 方法 - 结束转推](#client-stoprelay)
 * [updateRelayStreams 方法 - 增加/删除转推的流](#client-updaterelaystreams)
 * [createStream 方法 - 创建一条本地(预览)流](#client-createstream)
+* [removeStream 方法 - 删除一条本地(预览)流](#client-removestream)
 
 <a name="client-constructor"></a>
 
@@ -725,14 +726,14 @@ Stream:
 {
   sid: string                     // 流ID
   uid: string                     // 对应的用户的ID
-  type: 'publish' | 'subscribe'   // 流类型,分别为 publish 和 subscribe 两种,
+  type: 'publish' | 'subscribe'   // 流类型,为 publish 和 subscribe 两种,分别对应本地流和远端流
   video: boolean                  // 是否包含音频
   audio: boolean                  // 是否包含视频
   muteAudio: boolean              // 音频轨道是否禁用
   muteVideo: boolean              // 视频轨道是否禁用
   mediaType?: 'camera' | 'screen' // 流的媒体类型,目前存在两种媒体类型 'camera' 及 'screen',同一用户可发布的各类型的流只能存在一个,以此来区分不同媒体类型的发布/订阅流
   mediaStream?: MediaStream       // 使用的媒体流,可用 HTMLMediaElement 进行播放,此属性的值可能为空,当流被正常发布或订阅流,此值有效
-  previewId?: string              // 通过 createStream 方法创建的流将包含此字段(即使该流被发布后)
+  previewId?: string              // 通过 createStream 方法创建的流将包含此字段(即使该流被发布后),且在未发布之前会与 sid 相同,当流被发布之后 sid 将被替换为服务器生成的流 ID,而 previewId 仍为用户自定义的 ID
 }
 ```
 
@@ -2101,7 +2102,10 @@ client.createStream(PreviewOptions, callback)
 }
 ```
 
-> 注: publish 方法的 [PublishOptions](#publishoptions)
+> 注:
+> 1. publish 方法的 [PublishOptions](#publishoptions)
+> 2. 当创建的本地(预览)流被发布成功后,该流将会被自动销毁,若该流已在播放(使用 play 方法播放),内部将自动调用 stop 方法停止对其播放,
+> 3. 发布成功后,将新创建本地(发布)流(可由 stream-published 的事件通知),然后可对其进行播放
 
 - callback: function 类型,选传,方法的回调函数,函数说明如下
 
@@ -2112,6 +2116,29 @@ Error 为返回值,为空时,说明已执行成功,否则执行失败,
 
 Stream 为返回值,[Stream 类型](#stream),执行失败时,此值为空,执行成功时,此值为执行结果
 
+<a name="client-removestream"></a>
+
+### 55. removeStream 方法
+
+删除一条本地(预览)流(必须为未被发布的本地流,已被发布的本地流的删除请调用 unpublish 方法),示例代码:
+
+```
+client.createStream(previewId, callback)
+```
+
+#### 参数说明
+
+- previewId: string 类型,必传,为调用 createStream 时传的 previewId
+
+- callback: function 类型,选传,方法的回调函数,函数说明如下
+
+```
+function callback(Error) {}
+```
+Error 为返回值,为空时,说明已执行成功,否则执行失败,值为执行失败的错误
+
+> 注: 当一条本地(预览)流已经被播放(通过调用 play 方法进行播放),此删除操作将自动停止该流的播放,无须额外调用 stop 方法
+
 ----
 
 <a name='getdevices'></a>

文件差异内容过多而无法显示
+ 3 - 3
lib/index.js


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "urtc-sdk",
-  "version": "1.5.6",
+  "version": "1.5.7",
   "description": "UCloud RTC javascript SDK",
   "main": "lib/index.js",
   "repository": {

+ 199 - 184
types/index.d.ts

@@ -1,16 +1,29 @@
-export declare type VideoCodec = 'vp8'|'h264';
+export declare type VideoCodec = 'vp8' | 'h264';
 export declare type AudioCodec = 'opus';
 
-export declare type RoomType = 'rtc'|'live';
-export declare type UserRole = 'pull'|'push'|'push-and-pull';
-export declare type DeviceType = 'audio'|'video';
+export declare type RoomType = 'rtc' | 'live';
+export declare type UserRole = 'pull' | 'push' | 'push-and-pull';
+export declare type DeviceType = 'audio' | 'video';
 
 // 业务方使用的事件类型
-export declare type EventType = 'user-added' | 'user-removed' |
-  'stream-added' | 'stream-removed' | 'stream-published' | 'stream-subscribed' |
-  'mute-video' | 'unmute-video' | 'mute-audio' | 'unmute-audio' | 'screenshare-stopped' |
-  'connection-state-change' | 'kick-off' | 'network-quality' | 'stream-reconnected' |
-  'record-notify' | 'relay-notify';
+export declare type EventType =
+  | 'user-added'
+  | 'user-removed'
+  | 'stream-added'
+  | 'stream-removed'
+  | 'stream-published'
+  | 'stream-subscribed'
+  | 'mute-video'
+  | 'unmute-video'
+  | 'mute-audio'
+  | 'unmute-audio'
+  | 'screenshare-stopped'
+  | 'connection-state-change'
+  | 'kick-off'
+  | 'network-quality'
+  | 'stream-reconnected'
+  | 'record-notify'
+  | 'relay-notify';
 
 export declare type ConnectionState = 'OPEN' | 'CONNECTING' | 'CLOSING' | 'RECONNECTING' | 'CLOSED';
 
@@ -21,329 +34,331 @@ export declare type MainViewType = 'desktop' | 'screen' | 'camera'; // todo - re
 export declare type NetworkQuality = '0' | '1' | '2' | '3' | '4' | '5' | '6';
 
 export interface ClientOptions {
-  type?: RoomType
-  role?: UserRole
-  codec?: VideoCodec  // 可设 vp8 或 h264,默认为 h264
+  type?: RoomType;
+  role?: UserRole;
+  codec?: VideoCodec; // 可设 vp8 或 h264,默认为 h264
 }
 
 export interface Codecs {
-  audio: Array<AudioCodec>,
-  video: Array<VideoCodec>
+  audio: Array<AudioCodec>;
+  video: Array<VideoCodec>;
 }
 
 declare type FacingMode = 'user' | 'environment' | 'left' | 'right';
 
 export interface PublishOptions {
-  audio: boolean    // 是否开启麦克风
-  video: boolean    // 是否开启摄像头
-  screen: boolean   // 是否共享屏幕
-  facingMode?: FacingMode // 指定使用的摄像头
-  microphoneId?: string // 麦克风设备ID
-  cameraId?: string     // 摄像头设备ID
-  extensionId?: string  // chrome插件ID
-  mediaStream?: MediaStream // 自定义的媒体流
-  file?: File,              // 图片流使用的图片文件
-  filePath?: string         // 图片流使用的图片的地址
-  previewId?: string // 预览流ID
+  audio: boolean; // 是否开启麦克风
+  video: boolean; // 是否开启摄像头
+  screen: boolean; // 是否共享屏幕
+  facingMode?: FacingMode; // 指定使用的摄像头
+  microphoneId?: string; // 麦克风设备ID
+  cameraId?: string; // 摄像头设备ID
+  extensionId?: string; // chrome插件ID
+  mediaStream?: MediaStream; // 自定义的媒体流
+  file?: File; // 图片流使用的图片文件
+  filePath?: string; // 图片流使用的图片的地址
+  previewId?: string; // 预览流ID
 }
 
 export interface PreviewStreamOptions extends PublishOptions {
-  previewId: string // 预览流ID
+  previewId: string; // 预览流ID
 }
 
 export interface DeviceOptions {
-  audio: boolean        // 是否开启麦克风
-  video: boolean        // 是否开启摄像头
-  facingMode?: FacingMode
-  microphoneId?: string // 麦克风设备ID
-  cameraId?: string     // 摄像头设备ID
+  audio: boolean; // 是否开启麦克风
+  video: boolean; // 是否开启摄像头
+  facingMode?: FacingMode;
+  microphoneId?: string; // 麦克风设备ID
+  cameraId?: string; // 摄像头设备ID
 }
 
 export interface DeviceDetectionOptions {
-  audio: boolean          // 必填,指定是否检测麦克风设备
-  video: boolean          // 必填,指定是否检测摄像头设备
-  microphoneId?: string   // 选填,指定需要检测的麦克风设备的ID,可通过 getMicrophones 方法查询获得该ID,不填时,将检测默认的麦克风设备
-  cameraId?: string       // 选填,指定需要检测的摄像头设备的ID,可以通过 getCameras 方法查询获得该ID,不填时,将检测默认的摄像头设备
+  audio: boolean; // 必填,指定是否检测麦克风设备
+  video: boolean; // 必填,指定是否检测摄像头设备
+  microphoneId?: string; // 选填,指定需要检测的麦克风设备的ID,可通过 getMicrophones 方法查询获得该ID,不填时,将检测默认的麦克风设备
+  cameraId?: string; // 选填,指定需要检测的摄像头设备的ID,可以通过 getCameras 方法查询获得该ID,不填时,将检测默认的摄像头设备
 }
 
 export interface DeviceDetectionResult {
-  audio: boolean
-  audioError?: string
-  video: boolean
-  videoError?: string
+  audio: boolean;
+  audioError?: string;
+  video: boolean;
+  videoError?: string;
 }
 
 export interface User {
-  uid: string     // 用户ID
+  uid: string; // 用户ID
 }
 
 export interface Stream {
-  previewId?: string              // 预览Id
-  sid: string                     // 流ID
-  uid: string                     // 对应的用户的ID
-  type: 'publish'|'subscribe'|'preview'     // 流类型
-  mediaType?: 'camera'|'screen'   // 流的媒体类型,用于对发布流的区分
-  video: boolean                  // 是否包含音频
-  audio: boolean                  // 是否包含视频
-  muteAudio: boolean              // 音频是否静音
-  muteVideo: boolean              // 视频是否静音
-  mediaStream?: MediaStream       // 业务侧自定义媒体流
+  previewId?: string; // 预览Id
+  sid: string; // 流ID
+  uid: string; // 对应的用户的ID
+  type: 'publish' | 'subscribe' | 'preview'; // 流类型
+  mediaType?: 'camera' | 'screen'; // 流的媒体类型,用于对发布流的区分
+  video: boolean; // 是否包含音频
+  audio: boolean; // 是否包含视频
+  muteAudio: boolean; // 音频是否静音
+  muteVideo: boolean; // 视频是否静音
+  mediaStream?: MediaStream; // 业务侧自定义媒体流
 }
 
 export interface LeaveRoomOptions {
-  keepRecording: boolean      // 是否保持服务端录制,默认不保持
+  keepRecording: boolean; // 是否保持服务端录制,默认不保持
 }
 
 export interface AudioVolumeOptions {
-  streamId?: string
-  element?: HTMLMediaElement
-  volume: number
+  streamId?: string;
+  element?: HTMLMediaElement;
+  volume: number;
 }
 
 export interface WaterMarkOptions {
-  position?: WaterMarkPosition
-  type?: WaterMarkType   // 水印类型
-  remarks?: string       // 水印备注
+  position?: WaterMarkPosition;
+  type?: WaterMarkType; // 水印类型
+  remarks?: string; // 水印备注
 }
 
 export interface MixStreamOptions {
-  width?: number         // 混流后视频的宽度
-  height?: number        // 混流后视频的高度
-  template?: number      // 混流模板,对应不同的录制布局
-  isAverage?: boolean    // 是否均匀,均分对应平铺,不均分对应垂直
+  width?: number; // 混流后视频的宽度
+  height?: number; // 混流后视频的高度
+  template?: number; // 混流模板,对应不同的录制布局
+  isAverage?: boolean; // 是否均匀,均分对应平铺,不均分对应垂直
 }
 
 export interface RelayOptions {
-  time?: number,         // 转推开启时间的时间戳,不填时,将默认使用当前时间的时间戳
-  fragment: number,      // 切片
+  time?: number; // 转推开启时间的时间戳,不填时,将默认使用当前时间的时间戳
+  fragment: number; // 切片
 }
 
 export interface RecordOptions {
-  bucket: string
-  region: string
-  uid?: string           // 指定某用户的流为主画面
-  mainViewType?: MainViewType    // 主画面类型
-  mixStream?: MixStreamOptions
-  waterMark?: WaterMarkOptions
-  relay?: RelayOptions
+  bucket: string;
+  region: string;
+  uid?: string; // 指定某用户的流为主画面
+  mainViewType?: MainViewType; // 主画面类型
+  mixStream?: MixStreamOptions;
+  waterMark?: WaterMarkOptions;
+  relay?: RelayOptions;
 }
 
 export interface Record {
-  FileName: string,
-  RecordId: string
+  FileName: string;
+  RecordId: string;
 }
 
 export interface EffectOptions {
-  streamId?: string
-  effectId: number
-  filePath?: string
-  loop?: boolean
-  playTime?: number
-  replace?: boolean
+  streamId?: string;
+  effectId: number;
+  filePath?: string;
+  loop?: boolean;
+  playTime?: number;
+  replace?: boolean;
 }
 
 export interface EffectVolumeOptions {
-  streamId?: string
-  effectId: number
-  volume: number
+  streamId?: string;
+  effectId: number;
+  volume: number;
 }
 
 export interface SwitchDeviceOptions {
-  streamId?: string
-  type: DeviceType
-  deviceId: string
+  streamId?: string;
+  type: DeviceType;
+  deviceId: string;
 }
 
 export interface SwitchImageOptions {
-  streamId?: string
-  file?: File,
-  filePath?: string
+  streamId?: string;
+  file?: File;
+  filePath?: string;
 }
 
 export interface SnapshotOptions {
-  streamId?: string
-  download?: string | boolean
+  streamId?: string;
+  download?: string | boolean;
 }
 
 export interface AudioStats {
-  br: number
-  lostpre: number
-  vol: number
-  mime: string
+  br: number;
+  lostpre: number;
+  vol: number;
+  mime: string;
 }
 
 export interface VideoStats {
-  br: number,
-  lostpre: number,
-  frt: number,
-  w: number,
-  h: number,
-  mime: string
+  br: number;
+  lostpre: number;
+  frt: number;
+  w: number;
+  h: number;
+  mime: string;
 }
 
 export interface NetworkStats {
-  rtt: number
+  rtt: number;
 }
 
 export interface ReplaceTrackOptions {
-  streamId?: string
-  track: MediaStreamTrack
-  retain?: boolean
+  streamId?: string;
+  track: MediaStreamTrack;
+  retain?: boolean;
 }
 
-export declare type MixType = 'relay' | 'record' | 'relay-and-record' | 'update-config'
-export declare type MixLayoutType = 'flow' | 'main' | 'custom' | 'customMain' | 'customFlow' | 'single'
-export declare type MixAudioCodec = 'aac'
-export declare type MixVideoCodec = 'h264' | 'h265'
-export declare type H264Quality = 'B' | 'CB' | 'M' | 'E' | 'H'
-export declare type MixOutputMode = 'audio-video' | 'audio'   // 默认为 audio-video
-export declare type MixStreamAddMode = 'automatic' | 'manual' // 默认为 'automatic 自动的
+export declare type MixType = 'relay' | 'record' | 'relay-and-record' | 'update-config';
+export declare type MixLayoutType = 'flow' | 'main' | 'custom' | 'customMain' | 'customFlow' | 'single';
+export declare type MixAudioCodec = 'aac';
+export declare type MixVideoCodec = 'h264' | 'h265';
+export declare type H264Quality = 'B' | 'CB' | 'M' | 'E' | 'H';
+export declare type MixOutputMode = 'audio-video' | 'audio'; // 默认为 audio-video
+export declare type MixStreamAddMode = 'automatic' | 'manual'; // 默认为 'automatic 自动的
 
 export interface MixLayoutOptions {
-  type: MixLayoutType           // layout 类型
-  standbyTypes?: MixLayoutType[]// 待切换的 layout 类型
-  custom?: Object[]             // layout 为 'custom',自定义布局填在custom里,格式参照RFC5707 Media Server Markup Language (MSML)
-  mainViewUId?: string          // 指定某用户的流为主画面
-  mainViewType?: MainViewType   // 主画面类型
+  type: MixLayoutType; // layout 类型
+  standbyTypes?: MixLayoutType[]; // 待切换的 layout 类型
+  custom?: Array<object>; // layout 为 'custom',自定义布局填在custom里,格式参照RFC5707 Media Server Markup Language (MSML)
+  mainViewUId?: string; // 指定某用户的流为主画面
+  mainViewType?: MainViewType; // 主画面类型
 }
 
 export interface MixAudioOptions {
-  codec: MixAudioCodec
+  codec: MixAudioCodec;
 }
 
 export interface MixVideoOptions {
-  codec: MixVideoCodec
-  quality?: H264Quality       // 当 codec 为 h264 时,此项起作用
-  frameRate?: number
-  bitRate?: number
+  codec: MixVideoCodec;
+  quality?: H264Quality; // 当 codec 为 h264 时,此项起作用
+  frameRate?: number;
+  bitRate?: number;
 }
 
 export interface BackgroundColorOptions {
-  r: number
-  g: number
-  b: number
+  r: number;
+  g: number;
+  b: number;
 }
 
 export interface MixOptions {
-  type?: MixType            // 默认为 record
-  bucket?: string
-  region?: string
+  type?: MixType; // 默认为 record
+  bucket?: string;
+  region?: string;
 
-  pushURL?: string[]     // type 是 转推,转推和录制时,需指定
-  layout?: MixLayoutOptions
-  audio?: MixAudioOptions
-  video?: MixVideoOptions
-  outputMode?: MixOutputMode
+  pushURL?: string[]; // type 是 转推,转推和录制时,需指定
+  layout?: MixLayoutOptions;
+  audio?: MixAudioOptions;
+  video?: MixVideoOptions;
+  outputMode?: MixOutputMode;
 
-  width?: number
-  height?: number
-  backgroundColor?: BackgroundColorOptions
+  width?: number;
+  height?: number;
+  backgroundColor?: BackgroundColorOptions;
 
-  waterMark?: WaterMarkOptions
+  waterMark?: WaterMarkOptions;
 
-  streams?: MixStream[]
-  streamAddMode?: MixStreamAddMode
+  streams?: MixStream[];
+  streamAddMode?: MixStreamAddMode;
+
+  timeoutPeriod?: number; // 超时周期,任务检测到没有(指定)流后超过此时间,将自动停止,单位是s,最长24小时
 }
 
 export interface StopMixOptions {
-  type?: MixType            // 默认为 record
-  pushURL?: string[]        // 如果 type 为 relay 或 relay-and-record,需要指定停止对哪个 url 的转推,如果留空会停止对所有 url 的转推
+  type?: MixType; // 默认为 record
+  pushURL?: string[]; // 如果 type 为 relay 或 relay-and-record,需要指定停止对哪个 url 的转推,如果留空会停止对所有 url 的转推
 }
 
 export interface MixResult {
-  MixId: string
-  FileName?: string
-  Type?: MixType
-  PushURL?: string[]
+  MixId: string;
+  FileName?: string;
+  Type?: MixType;
+  PushURL?: string[];
 }
 
 export interface MixStream {
-  uid: string,        // 用户 ID
-  mediaType: 'camera'|'screen'   // 流的媒体类型
+  uid: string; // 用户 ID
+  mediaType: 'camera' | 'screen'; // 流的媒体类型
 }
 
 export interface AddMixStreamsOptions {
-  streams: MixStream[]
+  streams: MixStream[];
 }
 
 export interface RemoveMixStreamsOptions {
-  streams: MixStream[]
+  streams: MixStream[];
 }
 
 // 录制
 export interface StartRecordOptions {
-  bucket: string
-  region: string
+  bucket: string;
+  region: string;
 
-  layout?: MixLayoutOptions
+  layout?: MixLayoutOptions;
 
-  width?: number
-  height?: number
-  backgroundColor?: BackgroundColorOptions
+  width?: number;
+  height?: number;
+  backgroundColor?: BackgroundColorOptions;
 
-  waterMark?: WaterMarkOptions
+  waterMark?: WaterMarkOptions;
 
-  streams?: MixStream[]   // 如果列表为空,会自动添加房间内所有用户的流,如果指定了用户,则只添加该用户的指定流
+  streams?: MixStream[]; // 如果列表为空,会自动添加房间内所有用户的流,如果指定了用户,则只添加该用户的指定流
 }
 
 export interface RecordResult {
-  Id: string
-  FileName?: string
+  Id: string;
+  FileName?: string;
 }
 
 declare type UpdateMixStreamsType = 'add' | 'remove';
 
 export interface UpdateMixStreamsOptions {
-  type: UpdateMixStreamsType,
-  streams: MixStream[]
+  type: UpdateMixStreamsType;
+  streams: MixStream[];
 }
 
 export interface StartRelayOptions {
-  pushURL?: string[]
-  layout?: MixLayoutOptions
-  audio?: MixAudioOptions
-  video?: MixVideoOptions
-  outputMode?: MixOutputMode
+  pushURL?: string[];
+  layout?: MixLayoutOptions;
+  audio?: MixAudioOptions;
+  video?: MixVideoOptions;
+  outputMode?: MixOutputMode;
 
-  width?: number
-  height?: number
-  backgroundColor?: BackgroundColorOptions
+  width?: number;
+  height?: number;
+  backgroundColor?: BackgroundColorOptions;
 
-  waterMark?: WaterMarkOptions
+  waterMark?: WaterMarkOptions;
 
-  streams?: MixStream[]
-  streamAddMode?: MixStreamAddMode
+  streams?: MixStream[];
+  streamAddMode?: MixStreamAddMode;
 }
 
 export interface RelayResult {
-  Id: string
-  PushURL?: string[]
+  Id: string;
+  PushURL?: string[];
 }
 
 declare type UpdateRelayPushURLType = 'add' | 'remove';
 
 export interface UpdateRelayPushURLOptions {
-  type: UpdateRelayPushURLType,
-  pushURL: string[]
+  type: UpdateRelayPushURLType;
+  pushURL: string[];
 }
 
 export interface UpdateRelayLayoutOptions {
-  layout: MixLayoutOptions
+  layout: MixLayoutOptions;
 }
 
 export interface UpdateRelayWaterMarkOptions {
-  waterMark: WaterMarkOptions
+  waterMark: WaterMarkOptions;
 }
 
-declare type VideoFitType = 'cover' | 'contain';  // cover 模式:优先保证视窗被填满。contain 模式:优先保证视频内容全部显示。
+declare type VideoFitType = 'cover' | 'contain'; // cover 模式:优先保证视窗被填满。contain 模式:优先保证视频内容全部显示。
 
 declare type PlayControlsOption = 'show' | 'hide' | 'auto'; // 默认 auto,正常播放时隐藏,未播放时显示
 
 export interface PlayOptions {
-  streamId: string,
-  container: HTMLElement | string,
-  mute?: boolean,
-  mirror?: boolean,
-  fit?: VideoFitType
-  controls?: PlayControlsOption
-}
+  streamId: string;
+  container: HTMLElement | string;
+  mute?: boolean;
+  mirror?: boolean;
+  fit?: VideoFitType;
+  controls?: PlayControlsOption;
+}