vue-easy-sip 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/dist/favicon.ico +0 -0
- package/dist/types/components/IntercomButton.vue.d.ts +124 -0
- package/dist/types/components/IntercomDialog.vue.d.ts +89 -0
- package/dist/types/hooks/useRecorder.d.ts +37 -0
- package/dist/types/hooks/useSipClient.d.ts +54 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/types.d.ts +63 -0
- package/dist/vue-easy-sip.css +1 -0
- package/dist/vue-easy-sip.es.js +10715 -0
- package/dist/vue-easy-sip.umd.js +75 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Vue Easy SIP
|
|
2
|
+
|
|
3
|
+
一个简单易用的Vue 3 SIP对讲组件库,基于JsSIP,提供语音对讲功能。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 🚀 基于Vue 3和JsSIP构建
|
|
8
|
+
- 📱 支持SIP语音对讲功能
|
|
9
|
+
- 🔄 支持发起呼叫和接收来电
|
|
10
|
+
- 🎙️ 支持通话录音功能
|
|
11
|
+
- 🎨 美观的UI界面,带有过渡动画
|
|
12
|
+
- 📦 支持作为npm包使用
|
|
13
|
+
- 🔧 高度可配置
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install vue-easy-sip
|
|
19
|
+
# 或
|
|
20
|
+
yarn add vue-easy-sip
|
|
21
|
+
# 或
|
|
22
|
+
pnpm add vue-easy-sip
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 使用方法
|
|
26
|
+
|
|
27
|
+
### 全局注册
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// main.js / main.ts
|
|
31
|
+
import { createApp } from 'vue'
|
|
32
|
+
import App from './App.vue'
|
|
33
|
+
import VueEasySip from 'vue-easy-sip'
|
|
34
|
+
import 'vue-easy-sip/style.css'
|
|
35
|
+
|
|
36
|
+
const app = createApp(App)
|
|
37
|
+
|
|
38
|
+
// 注册插件
|
|
39
|
+
app.use(VueEasySip)
|
|
40
|
+
app.mount('#app')
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 在组件中使用
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<template>
|
|
47
|
+
<div>
|
|
48
|
+
<h1>SIP对讲示例</h1>
|
|
49
|
+
<IntercomButton
|
|
50
|
+
callTarget="1002"
|
|
51
|
+
wsServer="wss://xx"
|
|
52
|
+
sipUri="sip:1010@xx"
|
|
53
|
+
password="1234"
|
|
54
|
+
displayName="1010"
|
|
55
|
+
:autoAnswer="false"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup>
|
|
61
|
+
import { IntercomButton } from 'vue-easy-sip'
|
|
62
|
+
</script>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 配置选项
|
|
66
|
+
|
|
67
|
+
### IntercomButton组件属性
|
|
68
|
+
|
|
69
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
70
|
+
| ----------- | ------- | ------ | ------------------- |
|
|
71
|
+
| callTarget | string | - | 要呼叫的目标号码 |
|
|
72
|
+
| wsServer | string | - | WebSocket服务器地址 |
|
|
73
|
+
| sipUri | string | - | SIP URI |
|
|
74
|
+
| password | string | - | SIP账号密码 |
|
|
75
|
+
| displayName | string | - | 显示名称 |
|
|
76
|
+
| autoAnswer | boolean | false | 是否自动接听来电 |
|
|
77
|
+
|
|
78
|
+
### 其它
|
|
79
|
+
|
|
80
|
+
维护拓展加qq1195669615
|
|
81
|
+
|
|
82
|
+
## 许可证
|
|
83
|
+
|
|
84
|
+
MIT
|
package/dist/favicon.ico
ADDED
|
Binary file
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { SipConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
/** 要呼叫的目标SIP URI */
|
|
5
|
+
callTarget?: string;
|
|
6
|
+
/** WebSocket服务器地址,用于建立与SIP服务器的信令连接 */
|
|
7
|
+
wsServer?: string;
|
|
8
|
+
/** SIP URI,格式为sip:用户名@域名,用于SIP注册和身份标识 */
|
|
9
|
+
sipUri?: string;
|
|
10
|
+
/** SIP账号密码,用于SIP服务器认证 */
|
|
11
|
+
password?: string;
|
|
12
|
+
/** 显示名称,可选,用于在SIP通信中展示的名称 */
|
|
13
|
+
displayName?: string;
|
|
14
|
+
/** 用户代理标识,可选,用于标识SIP客户端的类型和版本 */
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
/** 是否自动注册,可选,设置为true时初始化后自动向SIP服务器注册 */
|
|
17
|
+
autoRegister?: boolean;
|
|
18
|
+
/** SIP配置,可选,会覆盖全局配置和单独的配置属性 */
|
|
19
|
+
sipConfig?: Partial<SipConfig>;
|
|
20
|
+
/** 是否自动接听来电 */
|
|
21
|
+
autoAnswer?: boolean;
|
|
22
|
+
/** 是否禁用录音功能 */
|
|
23
|
+
disableRecording?: boolean;
|
|
24
|
+
/** 是否自动保存录音 */
|
|
25
|
+
autoSaveRecording?: boolean;
|
|
26
|
+
/** 录音名前缀 */
|
|
27
|
+
fileNamePrefix?: string;
|
|
28
|
+
/** 媒体约束,可选,用于配置音频和视频选项 */
|
|
29
|
+
mediaConstraints?: MediaStreamConstraints;
|
|
30
|
+
}
|
|
31
|
+
declare function __VLS_template(): {
|
|
32
|
+
default?(_: {}): any;
|
|
33
|
+
};
|
|
34
|
+
declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
35
|
+
callTarget: string;
|
|
36
|
+
wsServer: any;
|
|
37
|
+
sipUri: any;
|
|
38
|
+
password: any;
|
|
39
|
+
displayName: any;
|
|
40
|
+
userAgent: any;
|
|
41
|
+
autoRegister: any;
|
|
42
|
+
sipConfig: () => {};
|
|
43
|
+
autoAnswer: boolean;
|
|
44
|
+
disableRecording: boolean;
|
|
45
|
+
autoSaveRecording: boolean;
|
|
46
|
+
fileNamePrefix: string;
|
|
47
|
+
mediaConstraints: any;
|
|
48
|
+
}>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
49
|
+
registered: () => void;
|
|
50
|
+
registerFailed: (error: Error) => void;
|
|
51
|
+
connectionFailed: (error: Error) => void;
|
|
52
|
+
callFailed: (error: Error) => void;
|
|
53
|
+
callStarted: () => void;
|
|
54
|
+
callEnded: () => void;
|
|
55
|
+
incomingCall: (caller: string) => void;
|
|
56
|
+
recordingStart: () => void;
|
|
57
|
+
recordingPause: () => void;
|
|
58
|
+
recordingResume: () => void;
|
|
59
|
+
recordingStop: (blob: Blob) => void;
|
|
60
|
+
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
61
|
+
callTarget: string;
|
|
62
|
+
wsServer: any;
|
|
63
|
+
sipUri: any;
|
|
64
|
+
password: any;
|
|
65
|
+
displayName: any;
|
|
66
|
+
userAgent: any;
|
|
67
|
+
autoRegister: any;
|
|
68
|
+
sipConfig: () => {};
|
|
69
|
+
autoAnswer: boolean;
|
|
70
|
+
disableRecording: boolean;
|
|
71
|
+
autoSaveRecording: boolean;
|
|
72
|
+
fileNamePrefix: string;
|
|
73
|
+
mediaConstraints: any;
|
|
74
|
+
}>>> & Readonly<{
|
|
75
|
+
onRecordingStart?: () => any;
|
|
76
|
+
onRecordingPause?: () => any;
|
|
77
|
+
onRecordingResume?: () => any;
|
|
78
|
+
onRecordingStop?: (blob: Blob) => any;
|
|
79
|
+
onRegistered?: () => any;
|
|
80
|
+
onRegisterFailed?: (error: Error) => any;
|
|
81
|
+
onConnectionFailed?: (error: Error) => any;
|
|
82
|
+
onCallFailed?: (error: Error) => any;
|
|
83
|
+
onCallStarted?: () => any;
|
|
84
|
+
onCallEnded?: () => any;
|
|
85
|
+
onIncomingCall?: (caller: string) => any;
|
|
86
|
+
}>, {
|
|
87
|
+
disableRecording: boolean;
|
|
88
|
+
autoSaveRecording: boolean;
|
|
89
|
+
fileNamePrefix: string;
|
|
90
|
+
callTarget: string;
|
|
91
|
+
wsServer: string;
|
|
92
|
+
sipUri: string;
|
|
93
|
+
password: string;
|
|
94
|
+
displayName: string;
|
|
95
|
+
userAgent: string;
|
|
96
|
+
autoRegister: boolean;
|
|
97
|
+
sipConfig: Partial<SipConfig>;
|
|
98
|
+
autoAnswer: boolean;
|
|
99
|
+
mediaConstraints: MediaStreamConstraints;
|
|
100
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
101
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
|
|
102
|
+
export default _default;
|
|
103
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
104
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
105
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
106
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
107
|
+
} : {
|
|
108
|
+
type: import('vue').PropType<T[K]>;
|
|
109
|
+
required: true;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
type __VLS_WithDefaults<P, D> = {
|
|
113
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
114
|
+
default: D[K];
|
|
115
|
+
}> : P[K];
|
|
116
|
+
};
|
|
117
|
+
type __VLS_Prettify<T> = {
|
|
118
|
+
[K in keyof T]: T[K];
|
|
119
|
+
} & {};
|
|
120
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
121
|
+
new (): {
|
|
122
|
+
$slots: S;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** 对话框是否可见 */
|
|
3
|
+
visible: boolean;
|
|
4
|
+
/** 是否在通话中 */
|
|
5
|
+
isInCall: boolean;
|
|
6
|
+
/** 通话状态:incoming(来电)、outgoing(呼出)、active(通话中)、failed(失败)、""(空闲) */
|
|
7
|
+
callStatus: string;
|
|
8
|
+
/** 远程音频流 */
|
|
9
|
+
remoteStream: MediaStream | null;
|
|
10
|
+
/** 本地音频流 */
|
|
11
|
+
localStream: MediaStream | null;
|
|
12
|
+
/** 是否禁用录音功能 */
|
|
13
|
+
disableRecording?: boolean;
|
|
14
|
+
/** 是否自动保存录音 */
|
|
15
|
+
autoSaveRecording?: boolean;
|
|
16
|
+
/** 录音名前缀 */
|
|
17
|
+
fileNamePrefix?: string;
|
|
18
|
+
}
|
|
19
|
+
declare function __VLS_template(): {
|
|
20
|
+
default?(_: {}): any;
|
|
21
|
+
};
|
|
22
|
+
declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
23
|
+
visible: boolean;
|
|
24
|
+
isInCall: boolean;
|
|
25
|
+
callStatus: string;
|
|
26
|
+
remoteStream: any;
|
|
27
|
+
localStream: any;
|
|
28
|
+
disableRecording: boolean;
|
|
29
|
+
autoSaveRecording: boolean;
|
|
30
|
+
fileNamePrefix: string;
|
|
31
|
+
}>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
32
|
+
close: () => void;
|
|
33
|
+
answer: () => void;
|
|
34
|
+
hangup: () => void;
|
|
35
|
+
recordingStart: () => void;
|
|
36
|
+
recordingPause: () => void;
|
|
37
|
+
recordingResume: () => void;
|
|
38
|
+
recordingStop: (blob: Blob) => void;
|
|
39
|
+
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
40
|
+
visible: boolean;
|
|
41
|
+
isInCall: boolean;
|
|
42
|
+
callStatus: string;
|
|
43
|
+
remoteStream: any;
|
|
44
|
+
localStream: any;
|
|
45
|
+
disableRecording: boolean;
|
|
46
|
+
autoSaveRecording: boolean;
|
|
47
|
+
fileNamePrefix: string;
|
|
48
|
+
}>>> & Readonly<{
|
|
49
|
+
onClose?: () => any;
|
|
50
|
+
onAnswer?: () => any;
|
|
51
|
+
onHangup?: () => any;
|
|
52
|
+
onRecordingStart?: () => any;
|
|
53
|
+
onRecordingPause?: () => any;
|
|
54
|
+
onRecordingResume?: () => any;
|
|
55
|
+
onRecordingStop?: (blob: Blob) => any;
|
|
56
|
+
}>, {
|
|
57
|
+
visible: boolean;
|
|
58
|
+
isInCall: boolean;
|
|
59
|
+
callStatus: string;
|
|
60
|
+
remoteStream: MediaStream | null;
|
|
61
|
+
localStream: MediaStream | null;
|
|
62
|
+
disableRecording: boolean;
|
|
63
|
+
autoSaveRecording: boolean;
|
|
64
|
+
fileNamePrefix: string;
|
|
65
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
66
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
|
|
67
|
+
export default _default;
|
|
68
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
69
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
70
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
71
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
72
|
+
} : {
|
|
73
|
+
type: import('vue').PropType<T[K]>;
|
|
74
|
+
required: true;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
type __VLS_WithDefaults<P, D> = {
|
|
78
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
79
|
+
default: D[K];
|
|
80
|
+
}> : P[K];
|
|
81
|
+
};
|
|
82
|
+
type __VLS_Prettify<T> = {
|
|
83
|
+
[K in keyof T]: T[K];
|
|
84
|
+
} & {};
|
|
85
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
86
|
+
new (): {
|
|
87
|
+
$slots: S;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { RecorderConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 使用录音功能
|
|
5
|
+
* @param config 录音配置
|
|
6
|
+
* @returns 录音相关的状态和方法
|
|
7
|
+
*/
|
|
8
|
+
export declare function useRecorder(config?: Partial<RecorderConfig>): {
|
|
9
|
+
status: any;
|
|
10
|
+
audioBlob: import('vue').Ref<{
|
|
11
|
+
readonly size: number;
|
|
12
|
+
readonly type: string;
|
|
13
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
14
|
+
bytes: () => Promise<Uint8Array>;
|
|
15
|
+
slice: (start?: number, end?: number, contentType?: string) => Blob;
|
|
16
|
+
stream: () => ReadableStream<Uint8Array>;
|
|
17
|
+
text: () => Promise<string>;
|
|
18
|
+
}, Blob | {
|
|
19
|
+
readonly size: number;
|
|
20
|
+
readonly type: string;
|
|
21
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
22
|
+
bytes: () => Promise<Uint8Array>;
|
|
23
|
+
slice: (start?: number, end?: number, contentType?: string) => Blob;
|
|
24
|
+
stream: () => ReadableStream<Uint8Array>;
|
|
25
|
+
text: () => Promise<string>;
|
|
26
|
+
}>;
|
|
27
|
+
audioUrl: import('vue').Ref<string, string>;
|
|
28
|
+
duration: import('vue').Ref<number, number>;
|
|
29
|
+
error: import('vue').Ref<Error, Error>;
|
|
30
|
+
start: (stream: MediaStream) => Promise<boolean>;
|
|
31
|
+
pause: () => boolean;
|
|
32
|
+
resume: () => boolean;
|
|
33
|
+
stop: () => boolean;
|
|
34
|
+
saveToFile: (fileName?: string) => void;
|
|
35
|
+
formattedDuration: import('vue').ComputedRef<string>;
|
|
36
|
+
destroy: () => void;
|
|
37
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { SipConfig, SipStatus, CallStatus } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SIP客户端返回接口
|
|
6
|
+
* 定义钩子函数返回的状态和方法
|
|
7
|
+
*/
|
|
8
|
+
interface SipClientReturn {
|
|
9
|
+
/** SIP客户端当前状态,响应式值 */
|
|
10
|
+
status: Ref<SipStatus>;
|
|
11
|
+
/** 是否已注册到SIP服务器,响应式布尔值 */
|
|
12
|
+
isRegistered: Ref<boolean>;
|
|
13
|
+
/** 是否正在通话中,响应式布尔值 */
|
|
14
|
+
isInCall: Ref<boolean>;
|
|
15
|
+
/** 当前通话状态,响应式值 */
|
|
16
|
+
callStatus: Ref<CallStatus>;
|
|
17
|
+
/** 远程媒体流,用于播放对方音频/视频 */
|
|
18
|
+
remoteStream: Ref<MediaStream | null>;
|
|
19
|
+
/** 本地媒体流,用于录音和显示本地视频 */
|
|
20
|
+
localStream: Ref<MediaStream | null>;
|
|
21
|
+
/** 错误信息,如果有错误发生则包含错误对象 */
|
|
22
|
+
error: Ref<Error | null>;
|
|
23
|
+
/** 初始化SIP客户端,创建WebSocket连接并配置UA */
|
|
24
|
+
init: () => Promise<boolean>;
|
|
25
|
+
/** 向SIP服务器注册SIP账号 */
|
|
26
|
+
register: () => Promise<boolean>;
|
|
27
|
+
/** 从SIP服务器注销SIP账号 */
|
|
28
|
+
unregister: () => Promise<boolean>;
|
|
29
|
+
/** 发起呼叫到指定目标SIP URI */
|
|
30
|
+
call: (target: string) => Promise<boolean>;
|
|
31
|
+
/** 接听来电 */
|
|
32
|
+
answer: () => Promise<boolean>;
|
|
33
|
+
/** 挂断当前通话 */
|
|
34
|
+
hangup: () => Promise<boolean>;
|
|
35
|
+
/** 销毁SIP客户端,释放所有资源 */
|
|
36
|
+
destroy: () => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 创建SIP客户端
|
|
40
|
+
* 工厂函数,用于创建一个新的SIP客户端实例
|
|
41
|
+
*
|
|
42
|
+
* @param config SIP配置对象
|
|
43
|
+
* @returns SIP客户端接口
|
|
44
|
+
*/
|
|
45
|
+
export declare function createSipClient(config?: Partial<SipConfig>): SipClientReturn;
|
|
46
|
+
/**
|
|
47
|
+
* SIP客户端钩子函数
|
|
48
|
+
* 提供SIP通信功能,包括注册、呼叫、接听和挂断等
|
|
49
|
+
*
|
|
50
|
+
* @param config SIP配置对象
|
|
51
|
+
* @returns SIP客户端接口
|
|
52
|
+
*/
|
|
53
|
+
export default function useSipClient(config?: Partial<SipConfig>): SipClientReturn;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { App } from 'vue';
|
|
2
|
+
import { default as IntercomButton } from './components/IntercomButton.vue';
|
|
3
|
+
import { default as IntercomDialog } from './components/IntercomDialog.vue';
|
|
4
|
+
import { SipConfig } from './types';
|
|
5
|
+
import { createSipClient } from './hooks/useSipClient';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 设置全局SIP配置
|
|
9
|
+
* @param config SIP配置对象
|
|
10
|
+
*/
|
|
11
|
+
export declare const setSipConfig: (config: Partial<SipConfig>) => void;
|
|
12
|
+
/**
|
|
13
|
+
* 获取当前全局SIP配置
|
|
14
|
+
* @returns 当前SIP配置
|
|
15
|
+
*/
|
|
16
|
+
export declare const getSipConfig: () => SipConfig;
|
|
17
|
+
declare const VueEasySip: {
|
|
18
|
+
install: (app: App, ...options: any[]) => any;
|
|
19
|
+
};
|
|
20
|
+
export default VueEasySip;
|
|
21
|
+
export { IntercomButton, IntercomDialog, createSipClient };
|
|
22
|
+
export * from './types';
|
|
23
|
+
export * from './hooks/useRecorder';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue Easy SIP 类型定义
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* SIP配置接口
|
|
6
|
+
* 定义SIP客户端所需的配置参数
|
|
7
|
+
*/
|
|
8
|
+
export interface SipConfig {
|
|
9
|
+
/** WebSocket服务器地址,用于建立与SIP服务器的信令连接 */
|
|
10
|
+
wsServer: string;
|
|
11
|
+
/** SIP URI,格式为sip:用户名@域名,用于SIP注册和身份标识 */
|
|
12
|
+
sipUri: string;
|
|
13
|
+
/** SIP账号密码,用于SIP服务器认证 */
|
|
14
|
+
password: string;
|
|
15
|
+
/** 显示名称,可选,用于在SIP通信中展示的名称 */
|
|
16
|
+
displayName?: string;
|
|
17
|
+
/** 用户代理标识,可选,用于标识SIP客户端的类型和版本 */
|
|
18
|
+
userAgent?: string;
|
|
19
|
+
/** 是否自动注册,可选,设置为true时初始化后自动向SIP服务器注册 */
|
|
20
|
+
autoRegister?: boolean;
|
|
21
|
+
/** 是否自动应答,可选,设置为true时自动接听来电 */
|
|
22
|
+
autoAnswer?: boolean;
|
|
23
|
+
/** 媒体约束,可选,用于配置音频和视频选项 */
|
|
24
|
+
mediaConstraints?: MediaStreamConstraints;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* SIP客户端状态
|
|
28
|
+
* 表示SIP客户端与服务器的连接状态
|
|
29
|
+
*/
|
|
30
|
+
export type SipStatus = 'disconnected' | 'connecting' | 'connected' | 'registering' | 'registered' | 'error';
|
|
31
|
+
/**
|
|
32
|
+
* 通话状态
|
|
33
|
+
* 表示当前通话的状态
|
|
34
|
+
*/
|
|
35
|
+
export type CallStatus = '' | 'incoming' | 'outgoing' | 'active' | 'failed';
|
|
36
|
+
/**
|
|
37
|
+
* 录音状态
|
|
38
|
+
* 表示当前录音的状态
|
|
39
|
+
*/
|
|
40
|
+
export type RecordingStatus = 'inactive' | 'recording' | 'paused' | 'stopped';
|
|
41
|
+
/**
|
|
42
|
+
* 录音配置
|
|
43
|
+
* 定义录音功能的配置参数
|
|
44
|
+
*/
|
|
45
|
+
export interface RecorderConfig {
|
|
46
|
+
/** 音频类型,默认为audio/webm */
|
|
47
|
+
mimeType?: string;
|
|
48
|
+
/** 音频比特率 */
|
|
49
|
+
audioBitsPerSecond?: number;
|
|
50
|
+
/** 是否自动保存录音,默认为false */
|
|
51
|
+
autoSave?: boolean;
|
|
52
|
+
/** 自动保存的文件名前缀,默认为'recording' */
|
|
53
|
+
fileNamePrefix?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 对讲组件配置接口
|
|
57
|
+
*/
|
|
58
|
+
export interface IntercomConfig extends SipConfig {
|
|
59
|
+
/** 是否禁用录音功能 */
|
|
60
|
+
disableRecording?: boolean;
|
|
61
|
+
/** 是否自动保存录音 */
|
|
62
|
+
autoSaveRecording?: boolean;
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:ves-font;src:url(data:font/woff2;base64,d09GMgABAAAAAAM8AAsAAAAABxwAAALwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDBgqBXIFYATYCJAMMCwgABCAFhGcHThtMBhEVlNVkfymgx07jURFKXW3uWKBxrEKLdusB9u/Zazls9oIrrGdTyFpkcH5+EA/U2utbuE1SAlJl1VQRoEdVRSTcj3Cdjq8FIoWyc5O39n688wlNcOt5PcK4KJMEvv2fro/GIVSE6ZS1wJ1m6q7kN/z50rC8O+MuAMAhpwfFi0fYPMUacDOVGeHifsZdpIHbYjC4QXY7faQJvi8oLDD3IlLjeZ//+8m/CK99ACjKBUY1Jj6w7wP6QOu0KMKd+YB8Cuq1vgYgIy4R0M4Uc8V5PwtWcAeGE4dEmW0OZPXhAO/eSuiILNN8s6CgKzMIF1TEc3HG+ejz4ac2AFGVgL3Pkl2tO9z3dRO10iuBSUDPi6iQMAGZsKnbswZOMhMk7Zo0wsqLLIizxutHsmGUPf/xIqEAu7YDGEOzka88nsDXXSGCBAqaMBcrKdcjUoTMl6TN7ZEatqDd7i1TK3MhNRYftPp+7ZbL/++xq33PV65c2Xe/dk37ZF/h6pWe65VrtOeqtlU3tratrFqoNHxn42SV/llxrDc3OvqrvJ3+ugLf8c6vZJtmxb0yf8Zt0GlfFbavGfZHBZqstvPKgTXnXu+BHkDd9GkgPYn7p39j+k3sNnfO/2hPAHxqXf8oUjfDjeZb8AT+q74BJGYjSspNsjdBQDJKueFG7bRDzQ5082a80R2uJWjWPUPUpD+SZsOozI1Dpb1pKJrNQTvjta5vr7sjsJAlYJSzBEEXDUSd3EbSxV0qc09R6eUrii7+o51Vwe7W3qgIpr3goDjD+AWeUiTXppHVM9qnH6QueUdZmcahKety/hcjyhRz1pdtVQlIUoAfeR56nyBLeuCk5aKau6qipreUUwpmLzgozjB+gacUKSBr8fvOaJ9+EJC6Z2Rlah2asgaoXy1CHXeyz/qyrSoBCckF+NHD0PsEuXnYAyctlxGp3FUOiVCtXN8IH7cL2hn7tWmDIIYE+FfiCbNw1MJzxF1eUsRiGaItnrkg9t4Y) format("woff2"),url(data:font/woff;base64,d09GRgABAAAAAASoAAsAAAAABxwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADsAAABUIIslek9TLzIAAAFEAAAARAAAAGA9oEpdY21hcAAAAYgAAABWAAABhm2T0+RnbHlmAAAB4AAAAMYAAADcEq2sC2hlYWQAAAKoAAAALgAAADYrr/gzaGhlYQAAAtgAAAAcAAAAJAfeA4RobXR4AAAC9AAAAAwAAAAMDAAAAGxvY2EAAAMAAAAACAAAAAgALgBubWF4cAAAAwgAAAAfAAAAIAETADJuYW1lAAADKAAAAUAAAAJnEKM8sHBvc3QAAARoAAAAPQAAAE7bG9ZceJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBmg4gCACY7BUgAeJxjYGFhYJzAwMrAwNTJdIaBgaEfQjO+ZjBi5ACKMrAyM2AFAWmuKQwHnnc/72Vu+N/AwMB8hwFIMjCiKGICAINNDXp4nO2QwQ2AMAwDL2npAzEIDwbixUKoc3aM4qawBZYuVpy8DCxAEofIYBfG0KnUIk+skef4KXLD291q7/C5ZLqVcNco/Npi7u/mo63JaLbVCf4AZAMRrgAAeJw9TTuKAkEUrNfNvIbpYXR2ULMRbBzBZQ1W2AGDNfQE/cBANPAgXsJLjJcw9AIaewjT/Tw32CqqiqqkwMDP1d7sKywcPDooMQDKeRHsvBdIs/xXL1xF2hgpxniKsRVRN/FbaNoafMG0qsNfhYKeZm/mDWOgmcyo+Wg+6b0/UHKHcprUOi6pHjkdnLI+bj2l3Uzuj7tk3ZT8lnNeCTsq1ud1QY5lxflll1bZSyabjWhU6S6hZDE0nvch7NnbapHo9y97AyhcAAB4nGNgZGBgAGIPP12reH6brwzcLAwg8MQjShpB/7/KwsCsDeRyMDCBRAHgjwgAAAB4nGNgZGBgbvjfwBDDwgACQJKRARUwAwBHCQJsBAAAAAQAAAAEAAAAAAAAAAAuAG54nGNgZGBgYGZQY2BjAAEmIOYCQgaG/2A+AwAM2wFGAHichZE9bsJAEIWfwZAElChKpDRpVikoEsn8lEipUKCnoAez5ke211ovSNQ5TY6QE+QI6Whzikh52EMDRbza2W/evpkdyQDusIeH8rvnLtnDJbOSK7jAo3CV+pOwT34WrqGJnnCd+qtwAy94E26yY8YOnn/FrIV3YQ+3+BCu4AafwlXqX8I++Vu4hgf8CNep/wo3MPGuhZtoeeHA6qnTczXbqVVo0sik7niO9WITT+2pPNE2X5lUdYPOURrpVNtjm3y76DkXqciaRA15q+PYqMyatQ5dsHQu67fbkehBaBIMYKExhWOcQ2GGHeMKIQxSREV0Z/mY7gU2iFlp/3VP6LbIqR9yhS4CdM5cI7rSwnk6TY4tX+tRdXQrbsuahDSUWs1JYrLiDzzcramE1AMsi6oMfbS5ohN/UMyQ/AHYk29XeJxjYGKAAC4G7ICZkYmRmZGFgb8sPzM5taAoM69ENyczL1WoICM/L1U3IzEvXbe0QDctMyeHgQEACi0NIAAAAA==) format("woff"),url(data:font/ttf;base64,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) format("truetype")}.ves-font{font-family:ves-font!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-voiceprint-line:before{content:""}.icon-phone-hang-up-fill:before{content:""}.intercom-dialog[data-v-8c41a9bf]{position:fixed;bottom:20px;right:20px;background-color:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;z-index:1000;overflow:hidden}.slide-fade-enter-active[data-v-8c41a9bf]{transition:all .3s ease-out}.slide-fade-leave-active[data-v-8c41a9bf]{transition:all .3s ease-in}.slide-fade-enter-from[data-v-8c41a9bf],.slide-fade-leave-to[data-v-8c41a9bf]{transform:translate(20px);opacity:0}.dialog-header[data-v-8c41a9bf]{display:flex;justify-content:space-between;align-items:center;padding:6px 10px;background-color:#f5f5f5;border-bottom:1px solid #eee;cursor:move}.dialog-header h3[data-v-8c41a9bf]{margin:0 6px 0 0;font-size:16px;color:#333;white-space:nowrap}.close-button[data-v-8c41a9bf]{background:none;border:none;font-size:24px;cursor:pointer;color:#666;padding:0;line-height:1}.dialog-content[data-v-8c41a9bf]{padding:6px 10px;display:flex;flex-direction:column;align-items:center;gap:20px}.call-status[data-v-8c41a9bf]{text-align:center;width:100%}.status-icon[data-v-8c41a9bf]{width:50px;height:50px;line-height:50px;border-radius:50%;margin:0 auto 10px;background-position:center;background-repeat:no-repeat;background-size:30px}.status-icon i[data-v-8c41a9bf]{font-size:32px;color:#fff}.calling-icon[data-v-8c41a9bf]{background-color:#f8d7da;animation:pulse-8c41a9bf 1.5s infinite}.incoming-icon[data-v-8c41a9bf]{background-color:#cce5ff;animation:pulse-8c41a9bf 1.5s infinite}.failed-icon[data-v-8c41a9bf]{background-color:#f8d7da}.active-icon[data-v-8c41a9bf]{background-color:#373737}.status-text[data-v-8c41a9bf]{font-size:16px;font-weight:700}.caller-info[data-v-8c41a9bf]{font-size:14px;color:#666;margin-top:5px}.status-calling .status-text[data-v-8c41a9bf]{color:#721c24}.status-incoming .status-text[data-v-8c41a9bf]{color:#004085}.status-failed .status-text[data-v-8c41a9bf]{color:#721c24}.status-active .status-text[data-v-8c41a9bf]{color:#155724}.call-controls[data-v-8c41a9bf]{width:100%;display:flex;justify-content:center;gap:10px}.recording-controls[data-v-8c41a9bf]{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}.recording-status[data-v-8c41a9bf]{display:flex;align-items:center;justify-content:center;gap:5px;margin-top:10px;font-size:14px;color:#dc3545}.recording-indicator[data-v-8c41a9bf]{width:10px;height:10px;border-radius:50%;background-color:#dc3545;animation:blink-8c41a9bf 1s infinite}.answer-button[data-v-8c41a9bf]{padding:6px 10px;background-color:#28a745;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px}.answer-button[data-v-8c41a9bf]:hover{background-color:#218838}.reject-button[data-v-8c41a9bf],.hangup-button[data-v-8c41a9bf],.record-button[data-v-8c41a9bf],.pause-button[data-v-8c41a9bf],.resume-button[data-v-8c41a9bf],.stop-button[data-v-8c41a9bf]{padding:6px 10px;background-color:#dc3545;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px}.reject-button[data-v-8c41a9bf]:hover,.hangup-button[data-v-8c41a9bf]:hover{background-color:#c82333}.answer-button i[data-v-8c41a9bf],.reject-button i[data-v-8c41a9bf],.hangup-button i[data-v-8c41a9bf]{margin-right:8px}.record-button[data-v-8c41a9bf]{background-color:#17a2b8}.record-button[data-v-8c41a9bf]:hover{background-color:#138496}.pause-button[data-v-8c41a9bf],.resume-button[data-v-8c41a9bf]{background-color:#ffc107;color:#212529}.pause-button[data-v-8c41a9bf]:hover,.resume-button[data-v-8c41a9bf]:hover{background-color:#e0a800}.stop-button[data-v-8c41a9bf]{background-color:#6c757d}.stop-button[data-v-8c41a9bf]:hover{background-color:#5a6268}@keyframes pulse-8c41a9bf{0%{transform:scale(.95);box-shadow:0 0 #dc3545b3}70%{transform:scale(1);box-shadow:0 0 0 10px #dc354500}to{transform:scale(.95);box-shadow:0 0 #dc354500}}@keyframes blink-8c41a9bf{0%{opacity:1}50%{opacity:.4}to{opacity:1}}.intercom-button-container[data-v-2eecc54d]{position:relative}.intercom-button[data-v-2eecc54d]{padding:4px 16px;background-color:#4caf50;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px}.intercom-button[data-v-2eecc54d]:hover{background-color:#45a049}
|