正在显示
15 个修改的文件
包含
1565 行增加
和
11 行删除
1 | +[repoFolder:AgoraRTCEngine, branch:release/1.12.0, commit:89171d96ae055f7809ad9b455256272eee0a0b43] | ||
2 | +[repoFolder:media_sdk2, branch:release/1.12.0, commit:a442f9afe9b468f3f14930db4f3c01f73de90ea3] | ||
3 | +[repoFolder:ServerSDK-Video, branch:release/1.12.0, commit:a4f0d4c22aa9d93b9cd0f71967d4f4b763e46190] |
This file is too large to display.
1 | +#pragma once | ||
2 | + | ||
3 | +namespace agora { | ||
4 | +namespace recording { | ||
5 | + | ||
6 | +typedef unsigned char uchar_t; | ||
7 | +typedef unsigned int uint_t; | ||
8 | +typedef unsigned int uid_t; | ||
9 | + | ||
10 | +enum ERROR_CODE_TYPE { | ||
11 | + ERR_OK = 0, | ||
12 | + //1~1000 | ||
13 | + ERR_FAILED = 1, | ||
14 | + ERR_INVALID_ARGUMENT = 2, | ||
15 | + ERR_INTERNAL_FAILED = 3, | ||
16 | +}; | ||
17 | + | ||
18 | +enum WARN_CODE_TYPE { | ||
19 | + WARN_NO_AVAILABLE_CHANNEL = 103, | ||
20 | + WARN_LOOKUP_CHANNEL_TIMEOUT = 104, | ||
21 | + WARN_LOOKUP_CHANNEL_REJECTED = 105, | ||
22 | + WARN_OPEN_CHANNEL_TIMEOUT = 106, | ||
23 | + WARN_OPEN_CHANNEL_REJECTED = 107, | ||
24 | +}; | ||
25 | + | ||
26 | +enum CHANNEL_PROFILE_TYPE | ||
27 | +{ | ||
28 | + CHANNEL_PROFILE_COMMUNICATION = 0, | ||
29 | + CHANNEL_PROFILE_LIVE_BROADCASTING = 1, | ||
30 | +}; | ||
31 | + | ||
32 | +enum USER_OFFLINE_REASON_TYPE | ||
33 | +{ | ||
34 | + USER_OFFLINE_QUIT = 0, | ||
35 | + USER_OFFLINE_DROPPED = 1, | ||
36 | + USER_OFFLINE_BECOME_AUDIENCE = 2, | ||
37 | +}; | ||
38 | + | ||
39 | +enum REMOTE_VIDEO_STREAM_TYPE | ||
40 | +{ | ||
41 | + REMOTE_VIDEO_STREAM_HIGH = 0, | ||
42 | + REMOTE_VIDEO_STREAM_LOW = 1, | ||
43 | +}; | ||
44 | + | ||
45 | + | ||
46 | +typedef struct VideoMixingLayout | ||
47 | +{ | ||
48 | + struct Region { | ||
49 | + uid_t uid; | ||
50 | + double x;//[0,1] | ||
51 | + double y;//[0,1] | ||
52 | + double width;//[0,1] | ||
53 | + double height;//[0,1] | ||
54 | + int zOrder; //optional, [0, 100] //0 (default): bottom most, 100: top most | ||
55 | + | ||
56 | + // Optional | ||
57 | + // [0, 1.0] where 0 denotes throughly transparent, 1.0 opaque | ||
58 | + double alpha; | ||
59 | + | ||
60 | + int renderMode;//RENDER_MODE_HIDDEN: Crop, RENDER_MODE_FIT: Zoom to fit | ||
61 | + Region() | ||
62 | + :uid(0) | ||
63 | + , x(0) | ||
64 | + , y(0) | ||
65 | + , width(0) | ||
66 | + , height(0) | ||
67 | + , zOrder(0) | ||
68 | + , alpha(1.0) | ||
69 | + , renderMode(1) | ||
70 | + {} | ||
71 | + | ||
72 | + }; | ||
73 | + int canvasWidth; | ||
74 | + int canvasHeight; | ||
75 | + const char* backgroundColor;//e.g. "#C0C0C0" in RGB | ||
76 | + int regionCount; | ||
77 | + const Region* regions; | ||
78 | + const char* appData; | ||
79 | + int appDataLength; | ||
80 | + VideoMixingLayout() | ||
81 | + :canvasWidth(0) | ||
82 | + , canvasHeight(0) | ||
83 | + , backgroundColor(NULL) | ||
84 | + , regionCount(0) | ||
85 | + , regions(NULL) | ||
86 | + , appData(NULL) | ||
87 | + , appDataLength(0) | ||
88 | + {} | ||
89 | +} VideoMixingLayout; | ||
90 | + | ||
91 | +typedef struct UserJoinInfos { | ||
92 | + const char* recordingDir; | ||
93 | + //new attached info add below | ||
94 | + | ||
95 | + UserJoinInfos(): | ||
96 | + recordingDir(NULL) | ||
97 | + {} | ||
98 | +}UserJoinInfos; | ||
99 | + | ||
100 | + | ||
101 | +class IRecordingEngineEventHandler { | ||
102 | +public: | ||
103 | + virtual ~IRecordingEngineEventHandler() {} | ||
104 | + | ||
105 | + virtual void onError(int error) = 0; | ||
106 | + virtual void onWarning(int warn) = 0; | ||
107 | + | ||
108 | + virtual void onJoinChannelSuccess(const char * channelId, uid_t uid) = 0; | ||
109 | + virtual void onLeaveChannel() = 0; | ||
110 | + | ||
111 | + virtual void onUserJoined(uid_t uid, UserJoinInfos &infos) = 0; | ||
112 | + virtual void onUserOffline(uid_t uid, USER_OFFLINE_REASON_TYPE reason) = 0; | ||
113 | +}; | ||
114 | + | ||
115 | +typedef struct RecordingConfig { | ||
116 | + CHANNEL_PROFILE_TYPE channelProfile; | ||
117 | + bool isAudioOnly; | ||
118 | + bool isMixingEnabled; | ||
119 | + char * decryptionMode; | ||
120 | + char * secret; | ||
121 | + int idleLimitSec; | ||
122 | + char * appliteDir; | ||
123 | +// char * appliteLogDir; | ||
124 | + char * recordFileRootDir; | ||
125 | + int lowUdpPort; | ||
126 | + int highUdpPort; | ||
127 | + | ||
128 | + RecordingConfig(): channelProfile(CHANNEL_PROFILE_COMMUNICATION), | ||
129 | + isAudioOnly(false), | ||
130 | + isMixingEnabled(false), | ||
131 | + decryptionMode(NULL), | ||
132 | + secret(NULL), | ||
133 | + idleLimitSec(300), | ||
134 | + appliteDir(NULL), | ||
135 | +// appliteLogDir(NULL), | ||
136 | + recordFileRootDir(NULL), | ||
137 | + lowUdpPort(0), | ||
138 | + highUdpPort(0) | ||
139 | + {} | ||
140 | +} RecordingConfig; | ||
141 | + | ||
142 | +class IRecordingEngine{ | ||
143 | +public: | ||
144 | + | ||
145 | + /** | ||
146 | + * create a new recording engine instance | ||
147 | + * | ||
148 | + * @param appId The App ID issued to the application developers by Agora.io. | ||
149 | + * @param eventHandler the callback interface | ||
150 | + * | ||
151 | + * @return a recording engine instance pointer | ||
152 | + */ | ||
153 | + static IRecordingEngine* createAgoraRecordingEngine(const char * appId, IRecordingEngineEventHandler *eventHandler); | ||
154 | + | ||
155 | + virtual ~IRecordingEngine() {} | ||
156 | + | ||
157 | + /** | ||
158 | + * This method lets the recording engine join a channel, and start recording | ||
159 | + * | ||
160 | + * @param channelKey This parameter is optional if the user uses a static key, or App ID. In this case, pass NULL as the parameter value. More details refer to http://docs-origin.agora.io/en/user_guide/Component_and_Others/Dynamic_Key_User_Guide.html | ||
161 | + * @param channelId A string providing the unique channel id for the AgoraRTC session | ||
162 | + * @param uid The uid of recording client | ||
163 | + * @param config The config of current recording | ||
164 | + * | ||
165 | + * @return 0: Method call succeeded. <0: Method call failed. | ||
166 | + */ | ||
167 | + virtual int joinChannel(const char * channelKey, const char *channelId, uid_t uid, const RecordingConfig &config) = 0; | ||
168 | + | ||
169 | + | ||
170 | + | ||
171 | + /** | ||
172 | + * set the layout of video mixing | ||
173 | + * | ||
174 | + * @param layout layout setting | ||
175 | + * | ||
176 | + * @return 0: Method call succeeded. <0: Method call failed. | ||
177 | + */ | ||
178 | + virtual int setVideoMixingLayout(const VideoMixingLayout &layout) = 0; | ||
179 | + | ||
180 | + /** | ||
181 | + * Stop recording | ||
182 | + * | ||
183 | + * @return 0: Method call succeeded. <0: Method call failed. | ||
184 | + */ | ||
185 | + virtual int leaveChannel() = 0; | ||
186 | + | ||
187 | + /** | ||
188 | + * release recording engine | ||
189 | + * | ||
190 | + * @return 0: Method call succeeded. <0: Method call failed. | ||
191 | + */ | ||
192 | + virtual int release() = 0; | ||
193 | +}; | ||
194 | + | ||
195 | +} | ||
196 | +} |
1 | +#pragma once | ||
2 | + | ||
3 | +#ifdef __GNUC__ | ||
4 | +#if __GNUC_PREREQ(4, 6) | ||
5 | +#include <atomic> | ||
6 | +typedef std::atomic<bool> atomic_bool_t; | ||
7 | + | ||
8 | +#elif __GNUC_PREREQ(4, 4) | ||
9 | +namespace agora { | ||
10 | +namespace base { | ||
11 | + | ||
12 | +template <typename T> class atomic; | ||
13 | + | ||
14 | +template <> | ||
15 | +class atomic<bool> { | ||
16 | + public: | ||
17 | + explicit atomic(bool value=false); | ||
18 | + ~atomic(); | ||
19 | + | ||
20 | + operator bool() const; | ||
21 | + atomic<bool>& operator=(bool value); | ||
22 | + bool load(); | ||
23 | + void store(bool value); | ||
24 | + private: | ||
25 | + bool value_; | ||
26 | +}; | ||
27 | + | ||
28 | +inline | ||
29 | +atomic<bool>::atomic(bool value) { | ||
30 | + value_ = value; | ||
31 | + __sync_synchronize(); | ||
32 | +} | ||
33 | + | ||
34 | +inline | ||
35 | +atomic<bool>::~atomic() { | ||
36 | +} | ||
37 | + | ||
38 | +inline | ||
39 | +atomic<bool>::operator bool() const { | ||
40 | + return value_; | ||
41 | +} | ||
42 | + | ||
43 | +inline | ||
44 | +atomic<bool>& atomic<bool>::operator=(bool value) { | ||
45 | + value_ = value; | ||
46 | + __sync_synchronize(); | ||
47 | + return *this; | ||
48 | +} | ||
49 | + | ||
50 | +inline bool atomic<bool>::load() { | ||
51 | + __sync_synchronize(); | ||
52 | + return value_; | ||
53 | +} | ||
54 | + | ||
55 | +inline void atomic<bool>::store(bool value) { | ||
56 | + value_ = value; | ||
57 | + __sync_synchronize(); | ||
58 | +} | ||
59 | + | ||
60 | +} | ||
61 | +} | ||
62 | + | ||
63 | +typedef agora::base::atomic<bool> atomic_bool_t; | ||
64 | +#else | ||
65 | +#error "version should be at least 4.4" | ||
66 | +//__sync_synchronize() doesn't produce mfence instruction | ||
67 | +//when gcc version less than 4.4 | ||
68 | +#endif | ||
69 | +#endif |
1 | +#pragma once | ||
2 | + | ||
3 | +#include <sys/types.h> | ||
4 | +#include <unistd.h> | ||
5 | + | ||
6 | +#include <cinttypes> | ||
7 | +#include <cstdint> | ||
8 | +#include <cstdlib> | ||
9 | +#include <stdarg.h> | ||
10 | +#include <cassert> | ||
11 | +#include <syslog.h> | ||
12 | + | ||
13 | +namespace agora { | ||
14 | +namespace base { | ||
15 | + | ||
16 | +enum log_levels { | ||
17 | + DEBUG_LOG = LOG_DEBUG, /* 7 debug-level messages */ | ||
18 | + INFO_LOG = LOG_INFO, /* 6 informational */ | ||
19 | + NOTICE_LOG = LOG_NOTICE, /* 5 normal but significant condition */ | ||
20 | + WARN_LOG = LOG_WARNING, /* 4 warning conditions */ | ||
21 | + ERROR_LOG = LOG_ERR, /* 3 error conditions */ | ||
22 | + FATAL_LOG = LOG_CRIT, /* 2 critical conditions */ | ||
23 | +}; | ||
24 | + | ||
25 | +struct log_config { | ||
26 | + static int enabled_level; | ||
27 | + static uint64_t dropped_count; | ||
28 | + | ||
29 | + static uint32_t drop_cancel; | ||
30 | + const static uint32_t DROP_COUNT = 1000; | ||
31 | + | ||
32 | + static inline void enable_debug(bool enabled) { | ||
33 | + if (enabled) { | ||
34 | + log_config::enabled_level = DEBUG_LOG; | ||
35 | + } else { | ||
36 | + log_config::enabled_level = INFO_LOG; | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | + static bool set_drop_cannel(uint32_t cancel) { | ||
41 | + if (cancel > DROP_COUNT) { | ||
42 | + drop_cancel = DROP_COUNT; | ||
43 | + return false; | ||
44 | + } | ||
45 | + | ||
46 | + drop_cancel = cancel; | ||
47 | + return true; | ||
48 | + } | ||
49 | + | ||
50 | + static inline bool log_enabled(log_levels level) { | ||
51 | + if (level <= enabled_level) { | ||
52 | + return true; | ||
53 | + } | ||
54 | + | ||
55 | + ++dropped_count; | ||
56 | + return (dropped_count % DROP_COUNT < drop_cancel); | ||
57 | + } | ||
58 | +}; | ||
59 | + | ||
60 | +inline void open_log() { | ||
61 | + ::openlog(NULL, LOG_PID|LOG_NDELAY, LOG_USER|LOG_DAEMON); | ||
62 | +} | ||
63 | + | ||
64 | +inline void log(log_levels level, const char* format, ...) { | ||
65 | + if (! log_config::log_enabled(level)) { | ||
66 | + return; | ||
67 | + } | ||
68 | + | ||
69 | + va_list args; | ||
70 | + va_start(args, format); | ||
71 | + ::vsyslog(level, format, args); | ||
72 | + va_end(args); | ||
73 | +} | ||
74 | + | ||
75 | +inline void close_log() { | ||
76 | + ::closelog(); | ||
77 | +} | ||
78 | + | ||
79 | +} | ||
80 | +} | ||
81 | + | ||
82 | +#define LOG(level, fmt, ...) log(agora::base::level ## _LOG, \ | ||
83 | + "(%d) %s:%d: " fmt, getpid(), __FILE__, __LINE__, ##__VA_ARGS__) | ||
84 | + | ||
85 | +#define LOG_IF(level, cond, ...) \ | ||
86 | + if (cond) { \ | ||
87 | + LOG(level, __VA_ARGS__); \ | ||
88 | + } | ||
89 | + | ||
90 | +#define LOG_EVERY_N(level, N, ...) \ | ||
91 | + { \ | ||
92 | + static unsigned int count = 0; \ | ||
93 | + if (++count % N == 0) \ | ||
94 | + LOG(level, __VA_ARGS__); \ | ||
95 | + } |
不能预览此文件类型
1 | +ifeq (${CXX},) | ||
2 | +CXX=g++ | ||
3 | +endif | ||
4 | +LINK=${CXX} | ||
5 | + | ||
6 | +TOPDIR=`pwd`/.. | ||
7 | +LIBPATH=${TOPDIR}/libs | ||
8 | +#-static-libstdc++ | ||
9 | +LDFLAGS= -static-libgcc -std=c++11 | ||
10 | +CXXFLAGS = -pipe -std=c++0x -fPIC -g -fno-omit-frame-pointer \ | ||
11 | + -DNDEBUG=1 -Wconversion -O3 -Wall -W -fvisibility=hidden | ||
12 | + | ||
13 | +LIB = -pthread -lpthread -L$(LIBPATH) -lRecordEngine -lrt | ||
14 | +INCPATH =-I. -I${TOPDIR}/include | ||
15 | + | ||
16 | +SRC =$(wildcard *.cpp) | ||
17 | +OBJ=$(addsuffix .o, $(basename $(SRC))) | ||
18 | +TARGET=Recorder_local | ||
19 | + | ||
20 | + | ||
21 | +.PHONY: all clean | ||
22 | +all: $(TARGET) | ||
23 | + | ||
24 | +$(TARGET): $(OBJ) | ||
25 | + $(LINK) $(LDFLAGS) $(INCPATH) $^ -o "$@" $(LIB) | ||
26 | + | ||
27 | +%.o: %.cpp | ||
28 | + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" | ||
29 | + | ||
30 | +clean: | ||
31 | + rm -f $(TARGET) | ||
32 | + rm -f ${OBJ} |
1 | +#pragma once | ||
2 | + | ||
3 | +#include <cstdint> | ||
4 | +#include <iostream> | ||
5 | +#include <string> | ||
6 | +#include <unordered_map> | ||
7 | + | ||
8 | +namespace agora { | ||
9 | +namespace base { | ||
10 | +struct ipv4 { | ||
11 | + union { | ||
12 | + uint32_t ip; | ||
13 | + uint8_t repr[4]; | ||
14 | + }; | ||
15 | +}; | ||
16 | + | ||
17 | +struct mac_addr { | ||
18 | + uint8_t addr_bytes[6]; | ||
19 | +}; | ||
20 | + | ||
21 | +class opt_parser { | ||
22 | + public: | ||
23 | + enum opt_type { | ||
24 | + no_argu=0, | ||
25 | + require_argu=1, | ||
26 | + opt_argu=2, | ||
27 | + }; | ||
28 | + | ||
29 | + private: | ||
30 | + enum pointer_type {kBool, kInt32, kUInt32, kInt64, kUInt64, kDouble, kString, | ||
31 | + kIPv4, kMacAddr}; | ||
32 | + | ||
33 | + struct internal_opt { | ||
34 | + pointer_type type; | ||
35 | + union { | ||
36 | + bool *bool_ptr; | ||
37 | + int32_t *int32_ptr; | ||
38 | + uint32_t *uint32_ptr; | ||
39 | + int64_t *int64_ptr; | ||
40 | + uint64_t *uint64_ptr; | ||
41 | + double *double_ptr; | ||
42 | + std::string *string_ptr; | ||
43 | + ipv4 *ipv4_ptr; | ||
44 | + mac_addr *addr_ptr; | ||
45 | + }; | ||
46 | + const char *help; | ||
47 | + opt_type optType; | ||
48 | + }; | ||
49 | + public: | ||
50 | + opt_parser() {} | ||
51 | + | ||
52 | + // bool add_short_arg(bool *store, char short_arg); | ||
53 | + // bool add_short_arg(int *store, char short_arg); | ||
54 | + // bool add_short_arg(std::string *store, char short_arg); | ||
55 | + | ||
56 | + bool add_long_opt(const char *long_opt, bool *store, const char *help, | ||
57 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
58 | + bool add_long_opt(const char *long_opt, int32_t *store, const char *help, | ||
59 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
60 | + bool add_long_opt(const char *long_opt, uint32_t *store, const char *help, | ||
61 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
62 | + bool add_long_opt(const char *long_opt, int64_t *store, const char *help, | ||
63 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
64 | + bool add_long_opt(const char *long_opt, uint64_t *store, const char *help, | ||
65 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
66 | + bool add_long_opt(const char *long_opt, double *store, const char *help, | ||
67 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
68 | + bool add_long_opt(const char *long_opt, std::string *store, const char *help, | ||
69 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
70 | + bool add_long_opt(const char *long_opt, ipv4 *store, const char *help, | ||
71 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
72 | + bool add_long_opt(const char *long_opt, mac_addr *store, const char *help, | ||
73 | + opt_parser::opt_type optParamType = opt_parser::opt_argu); | ||
74 | + | ||
75 | + // NOTE(liuyong): the FIRST argument must be supplied as a place holder | ||
76 | + bool parse_opts(int argc, char *const argv[]); | ||
77 | + | ||
78 | + void clear(); | ||
79 | + | ||
80 | + void print_usage(const char *exec_file, std::ostream &sout) const; | ||
81 | + private: | ||
82 | + // bool insert_short_arg(internal_opt arg, char short_arg); | ||
83 | + bool insert_long_opt(internal_opt &opt, const char *long_opt); | ||
84 | + | ||
85 | + static bool fill_arg(const char *opt_name, const internal_opt &opt, | ||
86 | + const char *opt_arg); | ||
87 | + | ||
88 | + static bool parse_ipv4(const char *arg, ipv4 *ip); | ||
89 | + static bool parse_mac_addr(const char *arg, mac_addr *addr); | ||
90 | + private: | ||
91 | + // std::unordered_map<char, internal_opt> short_args_; | ||
92 | + std::unordered_map<const char *, internal_opt> long_opts_; | ||
93 | +}; | ||
94 | + | ||
95 | +} | ||
96 | +} | ||
97 | + |
1 | +#include <csignal> | ||
2 | +#include <cstdint> | ||
3 | +#include <iostream> | ||
4 | +#include <sstream> | ||
5 | +#include <string> | ||
6 | +#include <vector> | ||
7 | +#include <algorithm> | ||
8 | + | ||
9 | +#include "IAgoraRecordingEngine.h" | ||
10 | + | ||
11 | +#include "base/atomic.h" | ||
12 | +#include "base/log.h" | ||
13 | +#include "base/opt_parser.h" | ||
14 | + | ||
15 | +using std::string; | ||
16 | +using std::cout; | ||
17 | +using std::cerr; | ||
18 | +using std::endl; | ||
19 | + | ||
20 | +using agora::base::opt_parser; | ||
21 | + | ||
22 | +class AgoraRecorder : public agora::recording::IRecordingEngineEventHandler { | ||
23 | + public: | ||
24 | + // appId | ||
25 | + AgoraRecorder(); | ||
26 | + ~AgoraRecorder(); | ||
27 | + | ||
28 | + bool createChannel(const string &appid, const string &channelKey, const string &name, uid_t uid, | ||
29 | + bool decodeAudio, bool decodeVideo, agora::recording::RecordingConfig &config); | ||
30 | + | ||
31 | + int setVideoMixLayout(); | ||
32 | + | ||
33 | + bool leaveChannel(); | ||
34 | + bool release(); | ||
35 | + | ||
36 | + bool stopped() const; | ||
37 | + | ||
38 | + private: | ||
39 | + virtual void onError(int error); | ||
40 | + virtual void onWarning(int warn); | ||
41 | + | ||
42 | + virtual void onJoinChannelSuccess(const char * channelId, uid_t uid); | ||
43 | + virtual void onLeaveChannel(); | ||
44 | + | ||
45 | + virtual void onUserJoined(uid_t uid, agora::recording::UserJoinInfos &infos); | ||
46 | + virtual void onUserOffline(uid_t uid, agora::recording::USER_OFFLINE_REASON_TYPE reason); | ||
47 | + | ||
48 | + private: | ||
49 | + atomic_bool_t m_stopped; | ||
50 | + agora::recording::IRecordingEngine *m_recorder; | ||
51 | + | ||
52 | + std::vector<agora::recording::uid_t> m_peers; | ||
53 | +}; | ||
54 | + | ||
55 | +AgoraRecorder::AgoraRecorder(): IRecordingEngineEventHandler() { | ||
56 | + m_recorder = NULL; | ||
57 | + m_stopped.store(false); | ||
58 | +} | ||
59 | + | ||
60 | +AgoraRecorder::~AgoraRecorder() { | ||
61 | + if (m_recorder) { | ||
62 | + m_recorder->release(); | ||
63 | + } | ||
64 | +} | ||
65 | + | ||
66 | +bool AgoraRecorder::stopped() const { | ||
67 | + return m_stopped; | ||
68 | +} | ||
69 | + | ||
70 | +bool AgoraRecorder::release() { | ||
71 | + if (m_recorder) { | ||
72 | + m_recorder->release(); | ||
73 | + m_recorder = NULL; | ||
74 | + } | ||
75 | + | ||
76 | + return true; | ||
77 | +} | ||
78 | + | ||
79 | +bool AgoraRecorder::createChannel(const string &appid, const string &channelKey, const string &name, | ||
80 | + uint32_t uid, | ||
81 | + bool decodeAudio, bool decodeVideo, | ||
82 | + agora::recording::RecordingConfig &config) | ||
83 | +{ | ||
84 | + if ((m_recorder = agora::recording::IRecordingEngine::createAgoraRecordingEngine(appid.c_str(), this)) == NULL) | ||
85 | + return false; | ||
86 | + | ||
87 | + | ||
88 | + return 0 == m_recorder->joinChannel(channelKey.c_str(), name.c_str(), uid, config); | ||
89 | +} | ||
90 | + | ||
91 | +bool AgoraRecorder::leaveChannel() { | ||
92 | + if (m_recorder) { | ||
93 | + m_recorder->leaveChannel(); | ||
94 | + m_stopped = true; | ||
95 | + } | ||
96 | + | ||
97 | + return true; | ||
98 | +} | ||
99 | + | ||
100 | +int AgoraRecorder::setVideoMixLayout() | ||
101 | +{ | ||
102 | + LOG(INFO, "setVideoMixLayout: user size: %d", m_peers.size()); | ||
103 | + | ||
104 | + agora::recording::VideoMixingLayout layout; | ||
105 | + layout.canvasWidth = 360; | ||
106 | + layout.canvasHeight = 640; | ||
107 | + layout.backgroundColor = "#23b9dc"; | ||
108 | + | ||
109 | + layout.regionCount = m_peers.size(); | ||
110 | + | ||
111 | + if (!m_peers.empty()) { | ||
112 | + LOG(INFO, "setVideoMixLayout: peers not empty"); | ||
113 | + agora::recording::VideoMixingLayout::Region * regionList = new agora::recording::VideoMixingLayout::Region[m_peers.size()]; | ||
114 | + | ||
115 | + regionList[0].uid = m_peers[0]; | ||
116 | + regionList[0].x = 0.f; | ||
117 | + regionList[0].y = 0.f; | ||
118 | + regionList[0].width = 1.f; | ||
119 | + regionList[0].height = 1.f; | ||
120 | + regionList[0].zOrder = 0; | ||
121 | + regionList[0].alpha = 1.f; | ||
122 | + regionList[0].renderMode = 0; | ||
123 | + | ||
124 | + LOG(INFO, "region 0 uid: %d, x: %f, y: %f, width: %f, height: %f, zOrder: %d, alpha: %f", regionList[0].uid, regionList[0].x, regionList[0].y, regionList[0].width, regionList[0].height, regionList[0].zOrder, regionList[0].alpha); | ||
125 | + | ||
126 | + | ||
127 | + float canvasWidth = 360.0; | ||
128 | + float canvasHeight = 640.0; | ||
129 | + | ||
130 | + float viewWidth = 0.3; | ||
131 | + float viewHEdge = 0.025; | ||
132 | + float viewHeight = viewWidth * (canvasWidth / canvasHeight); | ||
133 | + float viewVEdge = viewHEdge * (canvasWidth / canvasHeight); | ||
134 | + | ||
135 | + for (int i=1; i<m_peers.size(); i++) { | ||
136 | + if (i >= 7) | ||
137 | + break; | ||
138 | + | ||
139 | + regionList[i].uid = m_peers[i]; | ||
140 | + | ||
141 | + float xIndex = i % 3; | ||
142 | + float yIndex = i / 3; | ||
143 | + regionList[i].x = xIndex * (viewWidth + viewHEdge) + viewHEdge; | ||
144 | + regionList[i].y = 1 - (yIndex + 1) * (viewHeight + viewVEdge); | ||
145 | + regionList[i].width = viewWidth; | ||
146 | + regionList[i].height = viewHeight; | ||
147 | + regionList[i].zOrder = 0; | ||
148 | + regionList[i].alpha = i + 1; | ||
149 | + regionList[i].renderMode = 0; | ||
150 | + } | ||
151 | + | ||
152 | + layout.regions = regionList; | ||
153 | +// LOG(INFO, "region 0 uid: %d, x: %f, y: %f, width: %f, height: %f, zOrder: %d, alpha: %f", regionList[0].uid, regionList[0].x, regionList[0].y, regionList[0].width, regionList[0].height, regionList[0].zOrder, regionList[0].alpha); | ||
154 | + } | ||
155 | + else { | ||
156 | + layout.regions = NULL; | ||
157 | + } | ||
158 | + | ||
159 | + m_recorder->setVideoMixingLayout(layout); | ||
160 | +} | ||
161 | + | ||
162 | +void AgoraRecorder::onError(int error) { | ||
163 | + cerr << "Error: " << error << endl; | ||
164 | + leaveChannel(); | ||
165 | +} | ||
166 | + | ||
167 | +void AgoraRecorder::onWarning(int warn) { | ||
168 | + cerr << "warn: " << warn << endl; | ||
169 | + // leaveChannel(); | ||
170 | +} | ||
171 | + | ||
172 | +void AgoraRecorder::onJoinChannelSuccess(const char * channelId, uid_t uid) { | ||
173 | + cout << "join channel Id: " << channelId << ", with uid: " << uid << endl; | ||
174 | +} | ||
175 | + | ||
176 | +void AgoraRecorder::onLeaveChannel() { | ||
177 | + cout << "leave channel" << endl; | ||
178 | +} | ||
179 | + | ||
180 | +void AgoraRecorder::onUserJoined(unsigned uid, agora::recording::UserJoinInfos &infos) { | ||
181 | + cout << "User " << uid << " joined, RecordingDir:" << (infos.recordingDir? infos.recordingDir:"NULL") <<endl; | ||
182 | + m_peers.push_back(uid); | ||
183 | + | ||
184 | + setVideoMixLayout(); | ||
185 | +} | ||
186 | + | ||
187 | +void AgoraRecorder::onUserOffline(unsigned uid, agora::recording::USER_OFFLINE_REASON_TYPE reason) { | ||
188 | + cout << "User " << uid << " offline, reason: " << reason << endl; | ||
189 | + m_peers.erase(std::remove(m_peers.begin(), m_peers.end(), uid), m_peers.end()); | ||
190 | + | ||
191 | + setVideoMixLayout(); | ||
192 | +} | ||
193 | + | ||
194 | +atomic_bool_t g_bSignalStop; | ||
195 | + | ||
196 | +void signal_handler(int signo) { | ||
197 | + (void)signo; | ||
198 | + | ||
199 | + // cerr << "Signal " << signo << endl; | ||
200 | + g_bSignalStop = true; | ||
201 | +} | ||
202 | + | ||
203 | +int main(int argc, char * const argv[]) { | ||
204 | + uint32_t uid = 0; | ||
205 | + string appId; | ||
206 | + string channelKey; | ||
207 | + string name; | ||
208 | + bool decodeAudio = false; | ||
209 | + bool decodeVideo = false; | ||
210 | + | ||
211 | + uint32_t channelProfile; | ||
212 | + | ||
213 | + string decryptionMode; | ||
214 | + string secret; | ||
215 | + | ||
216 | + int idleLimitSec=30*60;//30min | ||
217 | + | ||
218 | + string applitePath; | ||
219 | + string appliteLogPath; | ||
220 | + string recordFileRootDir="."; | ||
221 | + | ||
222 | + int lowUdpPort = 0;//40000; | ||
223 | + int highUdpPort = 0;//40004; | ||
224 | + | ||
225 | + bool isAudioOnly=0; | ||
226 | + bool isMixingEnabled=0; | ||
227 | + | ||
228 | + | ||
229 | + g_bSignalStop = false; | ||
230 | + signal(SIGQUIT, signal_handler); | ||
231 | + signal(SIGABRT, signal_handler); | ||
232 | + signal(SIGINT, signal_handler); | ||
233 | + signal(SIGPIPE, SIG_IGN); | ||
234 | + | ||
235 | + opt_parser parser; | ||
236 | + | ||
237 | + | ||
238 | + | ||
239 | + parser.add_long_opt("appId", &appId, "App Id/must", agora::base::opt_parser::require_argu); | ||
240 | + parser.add_long_opt("uid", &uid, "User Id default is 0/must", agora::base::opt_parser::require_argu); | ||
241 | + | ||
242 | + parser.add_long_opt("channel", &name, "Channel Id/must", agora::base::opt_parser::require_argu); | ||
243 | + parser.add_long_opt("appliteDir", &applitePath, "directory of app lite 'video_recorder', Must pointer to 'Agora_Recording_SDK_for_Linux_FULL/bin/' folder/must", | ||
244 | + agora::base::opt_parser::require_argu); | ||
245 | + | ||
246 | + parser.add_long_opt("channelKey", &channelKey, "channelKey/option"); | ||
247 | + parser.add_long_opt("channelProfile", &channelProfile, "channel_profile:(0:COMMUNICATION),(1:broadcast) default is 0/option"); | ||
248 | + | ||
249 | + parser.add_long_opt("isAudioOnly", &isAudioOnly, "Default 0:ARS (0:1)/option"); | ||
250 | + parser.add_long_opt("isMixingEnabled", &isMixingEnabled, "Mixing Enable? (0:1)/option"); | ||
251 | + | ||
252 | + parser.add_long_opt("decryptionMode", &decryptionMode, "decryption Mode, default is NULL/option"); | ||
253 | + parser.add_long_opt("secret", &secret, "input secret when enable decryptionMode/option"); | ||
254 | + | ||
255 | + parser.add_long_opt("idle", &idleLimitSec, "Default 300s/option"); | ||
256 | + parser.add_long_opt("recordFileRootDir", &recordFileRootDir, "recording file root dir/option"); | ||
257 | + | ||
258 | + parser.add_long_opt("lowUdpPort", &lowUdpPort, "default is random value/option"); | ||
259 | + parser.add_long_opt("highUdpPort", &highUdpPort, "default is random value/option"); | ||
260 | + | ||
261 | + | ||
262 | + if (!parser.parse_opts(argc, argv) || appId.empty() || name.empty()) { | ||
263 | + std::string usage = "Usage: \n\ | ||
264 | + ./RECORD_APP --appId STRING --uid UINTEGER32 --channel STRING --appliteDir STRING --channelKey STRING --channelProfile UINTEGER32 --isAudioOnly 0/1 --isMixingEnabled 0/1 --decryptionMode STRING --secret STRING --idle INTEGER32 --recordFileRootDir STRING --lowUdpPort INTEGER32 --highUdpPort INTEGER32\n \ | ||
265 | + --appId (App Id/must) \n \ | ||
266 | + --uid (User Id default is 0/must) \n \ | ||
267 | + --channel (Channel Id/must) \n \ | ||
268 | + --appliteDir (directory of app lite 'video_recorder', Must pointer to 'Agora_Recording_SDK_for_Linux_FULL/bin/' folder/must) \n \ | ||
269 | + --channelKey (channelKey/option) \n \ | ||
270 | + --channelProfile (channel_profile:(0:COMMUNICATION),(1:broadcast) default is 0/option) \n \ | ||
271 | + --isAudioOnly (Default 0:ARS (0:1)/option) \n \ | ||
272 | + --isMixingEnabled (Mixing Enable? (0:1)/option) \n \ | ||
273 | + --decryptionMode (decryption Mode, default is NULL/option) \n \ | ||
274 | + --secret (input secret when enable decryptionMode/option) \n \ | ||
275 | + --idle (Default 300s/option) \n \ | ||
276 | + --recordFileRootDir (recording file root dir/option) \n \ | ||
277 | + --lowUdpPort (default is random value/option) \n \ | ||
278 | + --highUdpPort (default is random value/option)"; | ||
279 | + | ||
280 | + std::cerr << usage << std::endl; | ||
281 | + return -1; | ||
282 | + } | ||
283 | + | ||
284 | + LOG(INFO, "uid %" PRIu32 " from vendor %s is joining channel %s", | ||
285 | + uid, appId.c_str(), name.c_str()); | ||
286 | + | ||
287 | + AgoraRecorder recorder; | ||
288 | + agora::recording::RecordingConfig config; | ||
289 | + config.idleLimitSec = idleLimitSec; | ||
290 | + config.channelProfile = static_cast<agora::recording::CHANNEL_PROFILE_TYPE>(channelProfile); | ||
291 | + | ||
292 | + config.isAudioOnly = isAudioOnly; | ||
293 | + config.isMixingEnabled = isMixingEnabled; | ||
294 | + | ||
295 | + config.appliteDir = const_cast<char*>(applitePath.c_str()); | ||
296 | + config.recordFileRootDir = const_cast<char*>(recordFileRootDir.c_str()); | ||
297 | + | ||
298 | + config.secret = secret.empty()? NULL:const_cast<char*>(secret.c_str()); | ||
299 | + config.decryptionMode = decryptionMode.empty()? NULL:const_cast<char*>(decryptionMode.c_str()); | ||
300 | + | ||
301 | + config.lowUdpPort = lowUdpPort; | ||
302 | + config.highUdpPort = highUdpPort; | ||
303 | + | ||
304 | + | ||
305 | + if (!recorder.createChannel(appId, channelKey, name, uid, decodeAudio, decodeVideo, config)) { | ||
306 | + cerr << "Failed to create agora channel: " << name << endl; | ||
307 | + return -1; | ||
308 | + } | ||
309 | + | ||
310 | + while (!recorder.stopped() && !g_bSignalStop) { | ||
311 | + sleep(1); | ||
312 | + } | ||
313 | + | ||
314 | + if (g_bSignalStop) { | ||
315 | + recorder.leaveChannel(); | ||
316 | + recorder.release(); | ||
317 | + } | ||
318 | + | ||
319 | + cerr << "Stopped \n"; | ||
320 | + return 0; | ||
321 | +} | ||
322 | + |
1 | +#include <cassert> | ||
2 | +#include <cctype> | ||
3 | +#include <cstdlib> | ||
4 | +#include <cstring> | ||
5 | +#include <iostream> | ||
6 | +#include <vector> | ||
7 | +#include <cstring> | ||
8 | + | ||
9 | +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__) | ||
10 | +enum {ERROR=-1, INFO=0, WARNING, FATAL}; | ||
11 | +#define LOG(level, fmt, ...) fprintf(stderr, #level fmt "\n", __VA_ARGS__) | ||
12 | +#define strtoll _strtoi64 | ||
13 | +#define strtoull _strtoui64 | ||
14 | +#else | ||
15 | +#include <getopt.h> | ||
16 | +#include "base/log.h" | ||
17 | +#endif | ||
18 | + | ||
19 | +#include "base/opt_parser.h" | ||
20 | + | ||
21 | +using namespace std; | ||
22 | + | ||
23 | +namespace agora { | ||
24 | +namespace base { | ||
25 | +#if defined(_WIN32) && !defined(__GNUC__) | ||
26 | + | ||
27 | +enum {no_argument = 0, required_argument, optional_argument}; | ||
28 | + | ||
29 | +int optind = 0; | ||
30 | +const char *optarg = NULL; | ||
31 | + | ||
32 | +struct option { | ||
33 | + const char *name; | ||
34 | + int has_arg; | ||
35 | + int *flag; | ||
36 | + int val; | ||
37 | +}; | ||
38 | + | ||
39 | +int getopt_long_only(int argc, char *const argv[], const char *short_opts, | ||
40 | + const option *long_opts, int *index) { | ||
41 | + if (short_opts && *short_opts != '\0') { | ||
42 | + LOG(ERROR, "short options have not been implemented yet!"); | ||
43 | + return -1; | ||
44 | + } | ||
45 | + | ||
46 | + optind = optind == 0 ? 1 : optind; | ||
47 | + optarg = NULL; | ||
48 | + | ||
49 | + if (optind >= argc) | ||
50 | + return -1; | ||
51 | + | ||
52 | + const char *a = argv[optind]; | ||
53 | + if (a[0] != '-' || a[1] != '-') | ||
54 | + return -1; | ||
55 | + | ||
56 | + a += 2; | ||
57 | + | ||
58 | + int i = 0; | ||
59 | + | ||
60 | + for (; long_opts[i].name != NULL; ++i) { | ||
61 | + if (!strcmp(long_opts[i].name, a)) { | ||
62 | + ++optind; | ||
63 | + *index = i; | ||
64 | + return 0; | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + return '?'; | ||
69 | +} | ||
70 | + | ||
71 | +#endif | ||
72 | + | ||
73 | +// bool opt_parser::insert_short_arg(internal_opt arg, char short_arg) { | ||
74 | +// if (!isalpha(short_arg)) { | ||
75 | +// LOG(ERROR, "short parameters should be alphabetic!"); | ||
76 | +// return false; | ||
77 | +// } | ||
78 | +// | ||
79 | +// if (short_args_.count(short_arg) > 0) { | ||
80 | +// LOG(ERROR, "short parameter[%c] has been occupied!", short_arg); | ||
81 | +// return false; | ||
82 | +// } | ||
83 | +// | ||
84 | +// short_args_[short_arg] = arg; | ||
85 | +// return true; | ||
86 | +// } | ||
87 | + | ||
88 | +bool opt_parser::insert_long_opt(internal_opt &opt, const char *long_opt) { | ||
89 | + if (!long_opt) { | ||
90 | + LOG(ERROR, "A full parameter should be supplied!"); | ||
91 | + return false; | ||
92 | + } | ||
93 | + | ||
94 | + if (long_opts_.count(long_opt) > 0) { | ||
95 | + LOG(ERROR, "{%s} has been occupied yet!", long_opt); | ||
96 | + return false; | ||
97 | + } | ||
98 | + if(opt.help == NULL || !strlen(opt.help)) | ||
99 | + opt.help = "NA"; | ||
100 | + | ||
101 | + long_opts_[long_opt] = opt; | ||
102 | + return true; | ||
103 | +} | ||
104 | + | ||
105 | +// bool opt_parser::add_short_arg(bool *store, char short_arg) { | ||
106 | +// *store = false; | ||
107 | +// | ||
108 | +// internal_opt arg = {kBool, {store}}; | ||
109 | +// return insert_short_arg(arg, short_arg); | ||
110 | +// } | ||
111 | +// | ||
112 | +// bool opt_parser::add_short_arg(int *store, char short_arg) { | ||
113 | +// internal_opt arg; | ||
114 | +// arg.type = kInt; | ||
115 | +// arg.int_ptr = store; | ||
116 | +// | ||
117 | +// return insert_short_arg(arg, short_arg); | ||
118 | +// } | ||
119 | +// | ||
120 | +// bool opt_parser::add_short_arg(string *store, char short_arg) { | ||
121 | +// internal_opt arg; | ||
122 | +// arg.type = kString; | ||
123 | +// arg.string_ptr = store; | ||
124 | +// | ||
125 | +// return insert_short_arg(arg, short_arg); | ||
126 | +// } | ||
127 | + | ||
128 | +bool opt_parser::add_long_opt(const char *long_opt, bool *store, | ||
129 | + const char *help, opt_parser::opt_type optParamType) | ||
130 | +{ | ||
131 | + internal_opt arg; | ||
132 | + arg.type = kBool; | ||
133 | + arg.bool_ptr = store; | ||
134 | + arg.help = help; | ||
135 | + arg.optType = optParamType; | ||
136 | + | ||
137 | + return insert_long_opt(arg, long_opt); | ||
138 | +} | ||
139 | + | ||
140 | +bool opt_parser::add_long_opt(const char *long_opt, int32_t *store, | ||
141 | + const char *help, opt_parser::opt_type optParamType) | ||
142 | +{ | ||
143 | + internal_opt arg; | ||
144 | + arg.type = kInt32; | ||
145 | + arg.int32_ptr = store; | ||
146 | + arg.help = help; | ||
147 | + arg.optType = optParamType; | ||
148 | + | ||
149 | + return insert_long_opt(arg, long_opt); | ||
150 | +} | ||
151 | + | ||
152 | +bool opt_parser::add_long_opt(const char *long_opt, uint32_t *store, | ||
153 | + const char *help, opt_parser::opt_type optParamType) | ||
154 | +{ | ||
155 | + internal_opt arg; | ||
156 | + arg.type = kUInt32; | ||
157 | + arg.uint32_ptr = store; | ||
158 | + arg.help = help; | ||
159 | + arg.optType = optParamType; | ||
160 | + | ||
161 | + return insert_long_opt(arg, long_opt); | ||
162 | +} | ||
163 | + | ||
164 | +bool opt_parser::add_long_opt(const char *long_opt, int64_t *store, | ||
165 | + const char *help, opt_parser::opt_type optParamType) | ||
166 | +{ | ||
167 | + internal_opt arg; | ||
168 | + arg.type = kInt64; | ||
169 | + arg.int64_ptr = store; | ||
170 | + arg.help = help; | ||
171 | + arg.optType = optParamType; | ||
172 | + | ||
173 | + return insert_long_opt(arg, long_opt); | ||
174 | +} | ||
175 | + | ||
176 | +bool opt_parser::add_long_opt(const char *long_opt, uint64_t *store, | ||
177 | + const char *help, opt_parser::opt_type optParamType) | ||
178 | +{ | ||
179 | + internal_opt arg; | ||
180 | + arg.type = kUInt64; | ||
181 | + arg.uint64_ptr = store; | ||
182 | + arg.help = help; | ||
183 | + arg.optType = optParamType; | ||
184 | + | ||
185 | + return insert_long_opt(arg, long_opt); | ||
186 | +} | ||
187 | + | ||
188 | +bool opt_parser::add_long_opt(const char *long_opt, double *store, | ||
189 | + const char *help, opt_parser::opt_type optParamType) | ||
190 | +{ | ||
191 | + internal_opt arg; | ||
192 | + arg.type = kDouble; | ||
193 | + arg.double_ptr = store; | ||
194 | + arg.help = help; | ||
195 | + arg.optType = optParamType; | ||
196 | + | ||
197 | + return insert_long_opt(arg, long_opt); | ||
198 | +} | ||
199 | + | ||
200 | +bool opt_parser::add_long_opt(const char *long_opt, string *store, | ||
201 | + const char *help, opt_parser::opt_type optParamType) | ||
202 | +{ | ||
203 | + internal_opt arg; | ||
204 | + arg.type = kString; | ||
205 | + arg.string_ptr = store; | ||
206 | + arg.help = help; | ||
207 | + arg.optType = optParamType; | ||
208 | + | ||
209 | + return insert_long_opt(arg, long_opt); | ||
210 | +} | ||
211 | + | ||
212 | +bool opt_parser::add_long_opt(const char *long_opt, ipv4 *store, | ||
213 | + const char *help, opt_parser::opt_type optParamType) | ||
214 | +{ | ||
215 | + internal_opt arg; | ||
216 | + arg.type = kIPv4; | ||
217 | + arg.ipv4_ptr = store; | ||
218 | + arg.help = help; | ||
219 | + arg.optType = optParamType; | ||
220 | + | ||
221 | + return insert_long_opt(arg, long_opt); | ||
222 | +} | ||
223 | + | ||
224 | +bool opt_parser::add_long_opt(const char *long_opt, mac_addr *store, | ||
225 | + const char *help, opt_parser::opt_type optParamType) | ||
226 | +{ | ||
227 | + internal_opt arg; | ||
228 | + arg.type = kMacAddr; | ||
229 | + arg.addr_ptr = store; | ||
230 | + arg.help = help; | ||
231 | + arg.optType = optParamType; | ||
232 | + | ||
233 | + return insert_long_opt(arg, long_opt); | ||
234 | +} | ||
235 | + | ||
236 | +bool opt_parser::parse_ipv4(const char *arg, ipv4 *ip) { | ||
237 | + uint8_t (&a)[4] = ip->repr; | ||
238 | + if (sscanf(arg, "%hhu.%hhu.%hhu.%hhu", &a[0], &a[1], &a[2], &a[3]) != 4) { | ||
239 | + LOG(ERROR, "Illegal IP Format: %s", arg); | ||
240 | + return false; | ||
241 | + } | ||
242 | + | ||
243 | + return true; | ||
244 | +} | ||
245 | + | ||
246 | +bool opt_parser::parse_mac_addr(const char *arg, mac_addr *addr) { | ||
247 | + uint8_t (&b)[6] = addr->addr_bytes; | ||
248 | + if (sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &b[0], &b[1], | ||
249 | + &b[2], &b[3], &b[4], &b[5]) != 6) { | ||
250 | + LOG(ERROR, "Illegal ethernet physical address: %s", arg); | ||
251 | + return false; | ||
252 | + } | ||
253 | + | ||
254 | + return true; | ||
255 | +} | ||
256 | + | ||
257 | +bool opt_parser::fill_arg(const char *opt_name, const internal_opt &opt, | ||
258 | + const char *opt_arg) { | ||
259 | + | ||
260 | + if (opt_arg == NULL) { | ||
261 | + LOG(ERROR, "No argument available for %s", opt_name); | ||
262 | + return false; | ||
263 | + } | ||
264 | + | ||
265 | + char *end_ptr = NULL; | ||
266 | + | ||
267 | + switch (opt.type) { | ||
268 | + case kBool: { | ||
269 | + unsigned long n = strtoul(opt_arg, &end_ptr, 10); | ||
270 | + if (*end_ptr != '\0') { | ||
271 | + LOG(ERROR, "Invalid integer argument: %s", opt_arg); | ||
272 | + return false; | ||
273 | + } | ||
274 | + *opt.bool_ptr = n? true:false; | ||
275 | + } | ||
276 | + break; | ||
277 | + | ||
278 | + case kInt32: { | ||
279 | + long n = strtol(opt_arg, &end_ptr, 10); | ||
280 | + if (*end_ptr != '\0') { | ||
281 | + LOG(ERROR, "Invalid integer argument: %s", opt_arg); | ||
282 | + return false; | ||
283 | + } | ||
284 | + *opt.int32_ptr = int32_t(n); | ||
285 | + break; | ||
286 | + } | ||
287 | + case kUInt32: { | ||
288 | + unsigned long n = strtoul(opt_arg, &end_ptr, 10); | ||
289 | + if (*end_ptr != '\0') { | ||
290 | + LOG(ERROR, "Invalid integer argument: %s", opt_arg); | ||
291 | + return false; | ||
292 | + } | ||
293 | + *opt.uint32_ptr = uint32_t(n); | ||
294 | + break; | ||
295 | + } | ||
296 | + case kInt64: { | ||
297 | + long long n = strtoll(opt_arg, &end_ptr, 10); | ||
298 | + if (*end_ptr != '\0') { | ||
299 | + LOG(ERROR, "Invalid integer argument: %s", opt_arg); | ||
300 | + return false; | ||
301 | + } | ||
302 | + *opt.int64_ptr = int64_t(n); | ||
303 | + break; | ||
304 | + } | ||
305 | + case kUInt64: { | ||
306 | + unsigned long long n = strtoull(opt_arg, &end_ptr, 10); | ||
307 | + if (*end_ptr != '\0') { | ||
308 | + LOG(ERROR, "Invalid integer argument: %s", opt_arg); | ||
309 | + return false; | ||
310 | + } | ||
311 | + *opt.uint64_ptr = uint64_t(n); | ||
312 | + break; | ||
313 | + } | ||
314 | + case kDouble: { | ||
315 | + double n = strtod(opt_arg, &end_ptr); | ||
316 | + if (*end_ptr != '\0') { | ||
317 | + LOG(ERROR, "Invalid double argument: %s", opt_arg); | ||
318 | + return false; | ||
319 | + } | ||
320 | + *opt.double_ptr = n; | ||
321 | + break; | ||
322 | + } | ||
323 | + case kString: { | ||
324 | + *opt.string_ptr = opt_arg; | ||
325 | + break; | ||
326 | + } | ||
327 | + case kIPv4: { | ||
328 | + if (!parse_ipv4(opt_arg, opt.ipv4_ptr)) | ||
329 | + return false; | ||
330 | + break; | ||
331 | + } | ||
332 | + case kMacAddr: { | ||
333 | + if (!parse_mac_addr(opt_arg, opt.addr_ptr)) | ||
334 | + return false; | ||
335 | + break; | ||
336 | + } | ||
337 | + default: assert(false); break; | ||
338 | + } | ||
339 | + | ||
340 | + return true; | ||
341 | +} | ||
342 | + | ||
343 | +bool opt_parser::parse_opts(int argc, char* const argv[]) { | ||
344 | +// vector<char> options; | ||
345 | +// options.reserve(short_args_.size() + 1); | ||
346 | +// | ||
347 | +// unordered_map<char, internal_opt>::const_iterator it; | ||
348 | +// for (it = short_args_.begin(); it != short_args_.end(); ++it) { | ||
349 | +// options.push_back(it->first); | ||
350 | +// if (it->second.type != kBool) | ||
351 | +// options.push_back(':'); | ||
352 | +// } | ||
353 | +// | ||
354 | +// options.push_back('\0'); | ||
355 | + | ||
356 | + vector<option> long_opt; | ||
357 | + long_opt.reserve(long_opts_.size() + 1); | ||
358 | + | ||
359 | + unordered_map<const char *, internal_opt>::const_iterator f; | ||
360 | + for (f = long_opts_.begin(); f != long_opts_.end(); ++f) { | ||
361 | + option arg = {f->first, f->second.optType == opt_argu ? | ||
362 | + optional_argument : required_argument, 0, 0}; | ||
363 | + long_opt.push_back(arg); | ||
364 | + } | ||
365 | + | ||
366 | + option end_indicator = {NULL, 0, NULL, 0}; | ||
367 | + long_opt.push_back(end_indicator); | ||
368 | + int index, ret; | ||
369 | + | ||
370 | + // NOTE(liuyong): MUST initialize this variable first! | ||
371 | + optind = 1; | ||
372 | + optarg = NULL; | ||
373 | + | ||
374 | + while ((ret = getopt_long_only(argc, argv, "", &long_opt[0], | ||
375 | + &index)) == 0 || (ret > 0 && ret != '?')) { | ||
376 | + if (ret == 0) { // handle long options | ||
377 | + const option &opt = long_opt[index]; | ||
378 | + const internal_opt &a = long_opts_[opt.name]; | ||
379 | + const char *arg = optarg; | ||
380 | + if (!arg && optind < argc) { | ||
381 | + arg = argv[optind]; | ||
382 | + ++optind; | ||
383 | + } | ||
384 | + | ||
385 | + if (!fill_arg(opt.name, a, arg)) { | ||
386 | + optind = 0; | ||
387 | + return false; | ||
388 | + } | ||
389 | + }/* else if (short_args_.count(ret) > 0) { // handle short options | ||
390 | + const internal_opt &a = short_args_[ret]; | ||
391 | + if (!fill_arg(a, optarg)) | ||
392 | + return false; | ||
393 | + } */ | ||
394 | + } | ||
395 | + | ||
396 | + index = optind; | ||
397 | + optind = 0; | ||
398 | + | ||
399 | + | ||
400 | + if (index < argc) { | ||
401 | + LOG(ERROR, "Unrecognized option argument: %s", argv[index]); | ||
402 | + return false; | ||
403 | + } | ||
404 | + | ||
405 | + if (ret != -1) { | ||
406 | + LOG(ERROR, "Unregconized option argument %s", argv[index - 1]); | ||
407 | + return false; | ||
408 | + } | ||
409 | + | ||
410 | + return true; | ||
411 | +} | ||
412 | + | ||
413 | +void opt_parser::clear() { | ||
414 | +// short_args_.clear(); | ||
415 | + long_opts_.clear(); | ||
416 | +} | ||
417 | + | ||
418 | +void opt_parser::print_usage(const char *exec_file, ostream &sout) const { | ||
419 | + sout << "Usage: \n " << exec_file << " "; | ||
420 | + int fileLength = strlen(exec_file); | ||
421 | + typedef unordered_map<const char*, internal_opt>::const_iterator It; | ||
422 | + for (It f = long_opts_.begin(); f != long_opts_.end(); ++f) { | ||
423 | + sout << "--" << f->first << " "; | ||
424 | + const internal_opt &opt = f->second; | ||
425 | + const char *opt_arg = NULL; | ||
426 | + | ||
427 | + switch (opt.type) { | ||
428 | + case kBool: continue; | ||
429 | + case kInt32: | ||
430 | + opt_arg = "INTEGER32"; | ||
431 | + break; | ||
432 | + case kUInt32: | ||
433 | + opt_arg = "UINTEGER32"; | ||
434 | + break; | ||
435 | + case kInt64: | ||
436 | + opt_arg = "INTEGER64"; | ||
437 | + break; | ||
438 | + case kUInt64: | ||
439 | + opt_arg = "UINTEGER64"; | ||
440 | + break; | ||
441 | + case kDouble: | ||
442 | + opt_arg = "DOUBLE"; | ||
443 | + break; | ||
444 | + case kString: | ||
445 | + opt_arg = "STRING"; | ||
446 | + break; | ||
447 | + case kIPv4: | ||
448 | + opt_arg = "ddd.ddd.ddd.ddd"; | ||
449 | + break; | ||
450 | + case kMacAddr: | ||
451 | + opt_arg = "xx:xx:xx:xx:xx:xx"; | ||
452 | + break; | ||
453 | + default: | ||
454 | + assert(false); | ||
455 | + break; | ||
456 | + } | ||
457 | + | ||
458 | + sout << opt_arg << " "; | ||
459 | + } | ||
460 | + | ||
461 | + sout << endl; | ||
462 | + | ||
463 | + for (It f = long_opts_.begin(); f != long_opts_.end(); ++f) { | ||
464 | + sout<<" "; | ||
465 | + for(int i = 0; i < fileLength; i++) sout<<" "; | ||
466 | + sout << "--" << f->first << " ("<<f->second.help<<")"<<endl; | ||
467 | + } | ||
468 | +} | ||
469 | + | ||
470 | +} | ||
471 | +} | ||
472 | + |
不能预览此文件类型
1 | +const callfile = require('child_process'); | ||
2 | + | ||
3 | + | ||
4 | +function shell(){ | ||
5 | + | ||
6 | +} | ||
7 | + | ||
8 | +shell.prototype.Recording =async(appId,uid,channel)=>{ | ||
9 | + try { | ||
10 | + let shell =`./RECORD_APP`+ | ||
11 | + ` --appId ` +appId | ||
12 | + ` --uid ` +uid | ||
13 | + ` --channel ` + channel | ||
14 | + " --appliteDir \`pwd\`/../bin"; | ||
15 | + | ||
16 | + let backShell =callfile.exec(shell); | ||
17 | + return backShell; | ||
18 | + } catch (error) { | ||
19 | + throw error | ||
20 | + } | ||
21 | + | ||
22 | +} | ||
23 | + | ||
24 | + | ||
25 | +module.exports = new shell(); |
This file is too large to display.
1 | +#!/usr/bin/env python | ||
2 | + | ||
3 | +import os | ||
4 | +import sys | ||
5 | +import glob | ||
6 | +import subprocess | ||
7 | + | ||
8 | +HOME = os.path.dirname(os.path.realpath(__file__)) | ||
9 | +pathEnv=os.getenv('PATH') | ||
10 | +os.environ['PATH']= "%s" %(HOME) + ":" + pathEnv | ||
11 | + | ||
12 | + | ||
13 | +class AudioClip: | ||
14 | + def __init__(self): | ||
15 | + self.num = 0 | ||
16 | + self.filename = [] | ||
17 | + self.start_time = [] | ||
18 | + self.end_time = [] | ||
19 | + | ||
20 | + def put_file(self, name): | ||
21 | + if not (name in self.filename): | ||
22 | + self.filename.append(name) | ||
23 | + self.start_time.append(0.0) | ||
24 | + self.end_time.append(0.0) | ||
25 | + self.num = self.num + 1 | ||
26 | + return self.filename.index(name) | ||
27 | + | ||
28 | + def max_length(self): | ||
29 | + return max(self.end_time) | ||
30 | + | ||
31 | + def print_filename(self): | ||
32 | + str = "" | ||
33 | + for i in range(self.num): | ||
34 | + str = str + ("-i %s " % self.filename[i]) | ||
35 | + return str | ||
36 | + | ||
37 | + def print_filter(self): | ||
38 | + str = "" | ||
39 | + allch = "" | ||
40 | + for i in range(self.num): | ||
41 | + tmp = "[%d]adelay=%d[ad%d];" % ( (i), int(self.start_time[i]*1000)+1, (i)) | ||
42 | + allch = allch + ("[ad%d]" % i) | ||
43 | + str = str + tmp | ||
44 | + str = str + ("%s amix=inputs=%d:dropout_transition=0.5[audio]" % (allch, self.num)) | ||
45 | + return str | ||
46 | + | ||
47 | + def print_audio_info(self, i): | ||
48 | + print "Audio Clip %d: %s: start_time=%.3f, end_time=%.3f" % (i, self.filename[i], self.start_time[i], self.end_time[i]) | ||
49 | + | ||
50 | + def print_ffmpeg(self, output_file): | ||
51 | + if self.num > 1: | ||
52 | + str = "ffmpeg " + self.print_filename() | ||
53 | + str = str + "-filter_complex \"%s\" " % self.print_filter() | ||
54 | + str = str + "-map \"[audio]\" -to %f -y %s" % (self.max_length(), output_file) | ||
55 | + elif self.num == 1: | ||
56 | + str = "ffmpeg -i %s -c:a copy %s" % (self.filename[0], output_file) | ||
57 | + else: | ||
58 | + str = "" | ||
59 | + return str | ||
60 | + | ||
61 | +class VideoClip: | ||
62 | + def __init__(self): | ||
63 | + self.num = 0 | ||
64 | + self.filename = [] | ||
65 | + self.start_time = [] | ||
66 | + self.end_time = [] | ||
67 | + self.width = [] | ||
68 | + self.height = [] | ||
69 | + self.audio_file = "" | ||
70 | + self.audio_start_time = 0.0 | ||
71 | + self.audio_end_time = 0.0 | ||
72 | + | ||
73 | + def put_file(self, name): | ||
74 | + if not (name in self.filename): | ||
75 | + self.filename.append(name) | ||
76 | + self.start_time.append(0.0) | ||
77 | + self.end_time.append(0.0) | ||
78 | + self.width.append(0) | ||
79 | + self.height.append(0) | ||
80 | + self.num = self.num + 1 | ||
81 | + return self.filename.index(name) | ||
82 | + | ||
83 | + def max_resolution(self): | ||
84 | + self.max_width = max(self.width) | ||
85 | + self.max_height = max(self.height) | ||
86 | + return self.max_width, self.max_height | ||
87 | + | ||
88 | + def max_length(self): | ||
89 | + return max(max(self.end_time), self.audio_end_time) | ||
90 | + | ||
91 | + def audio_delay_needed(self): | ||
92 | + return self.audio_file != "" and self.audio_start_time > 0.05 | ||
93 | + | ||
94 | + def print_filter(self): | ||
95 | + if self.audio_delay_needed(): | ||
96 | + audio_delay = int(self.audio_start_time*1000) | ||
97 | + str = "[0]adelay=%d[audio];" % audio_delay | ||
98 | + else: | ||
99 | + str = "" | ||
100 | + source = "1" | ||
101 | + sink = "out2" | ||
102 | + for i in range(self.num): | ||
103 | + sink = "out%d" % (i+2) | ||
104 | + if i == self.num - 1: | ||
105 | + sink = "video" | ||
106 | + tmp = "[%d]scale=%dx%d,setpts=PTS-STARTPTS+%.3f/TB[scale%d];[%s][scale%d]overlay=eof_action=pass[%s];" % \ | ||
107 | + ( (i+2), self.max_width, self.max_height, self.start_time[i], (i+2), source, (i+2), sink ) | ||
108 | + str = str + tmp | ||
109 | + source = sink | ||
110 | + return str[:-1] | ||
111 | + | ||
112 | + def print_filename(self): | ||
113 | + str = "" | ||
114 | + for i in range(self.num): | ||
115 | + str = str + ("-i %s " % self.filename[i]) | ||
116 | + return str | ||
117 | + | ||
118 | + def print_ffmpeg(self, output_file): | ||
119 | + if self.audio_file == "": | ||
120 | + str = "ffmpeg -f lavfi -i anullsrc " | ||
121 | + else: | ||
122 | + str = "ffmpeg -i %s " % self.audio_file | ||
123 | + str = str + "-f lavfi -i \"color=black:s=%dx%d:r=15\" " % (self.max_width, self.max_height) | ||
124 | + str = str + self.print_filename() | ||
125 | + str = str + "-filter_complex \"%s\" " % self.print_filter() | ||
126 | + if self.audio_file == "": | ||
127 | + map_option = "-map \"[video]\"" | ||
128 | + else: | ||
129 | + if self.audio_delay_needed(): | ||
130 | + map_option = "-map \"[audio]\" -map \"[video]\" -c:a aac" | ||
131 | + else: | ||
132 | + map_option = "-map 0:a:0 -map \"[video]\" -c:a copy" | ||
133 | + str = str + "%s -c:v libx264 -preset veryfast -to %f -y %s" % (map_option, self.max_length(), output_file) | ||
134 | + return str | ||
135 | + | ||
136 | + def print_audio_info(self): | ||
137 | + print "Audio Clip: %s: start_time=%.3f, end_time=%.3f" % (self.audio_file, self.audio_start_time, self.audio_end_time) | ||
138 | + | ||
139 | + def print_video_info(self, i): | ||
140 | + print "Video Clip %d: %s: start_time=%.3f, end_time=%.3f, width=%d, height=%d" % \ | ||
141 | + (i, self.filename[i], self.start_time[i], self.end_time[i], self.width[i], self.height[i]) | ||
142 | + | ||
143 | + | ||
144 | +if len(sys.argv) <= 1: | ||
145 | + print "Usage: python video_convert.py path_of_folder" | ||
146 | + quit() | ||
147 | + | ||
148 | +folder_name = sys.argv[1] | ||
149 | +print "Folder name:"+folder_name | ||
150 | + | ||
151 | +if not os.path.isdir(folder_name): | ||
152 | + print "Folder "+folder_name+" does not exit" | ||
153 | + quit() | ||
154 | + | ||
155 | +os.chdir(folder_name) | ||
156 | +child_env = os.environ.copy() | ||
157 | +all_uid_file = glob.glob("uid_*.txt") | ||
158 | + | ||
159 | +for uid_file in all_uid_file: | ||
160 | + uid = os.path.splitext(uid_file)[0][4:] | ||
161 | + print "UID:"+uid | ||
162 | + | ||
163 | + clip = VideoClip() | ||
164 | + audio_clip = AudioClip() | ||
165 | + with open(uid_file) as f: | ||
166 | + for line in f: | ||
167 | + items = line.split(" ") | ||
168 | + #audio file | ||
169 | + if items[1][-3:] == "aac": | ||
170 | + index = audio_clip.put_file(items[1]) | ||
171 | + if items[2] == "create": | ||
172 | + audio_clip.start_time[index] = float(items[0]) | ||
173 | + elif items[2] == "close": | ||
174 | + audio_clip.end_time[index] = float(items[0]) | ||
175 | + #video file | ||
176 | + if items[1][-3:] == "mp4": | ||
177 | + index = clip.put_file(items[1]) | ||
178 | + if items[2] == "create": | ||
179 | + clip.start_time[index] = float(items[0]) | ||
180 | + elif items[2] == "info": | ||
181 | + clip.start_time[index] = float(items[0]) | ||
182 | + clip.width[index] = int(items[3][6:]) | ||
183 | + clip.height[index] = int(items[4][7:]) | ||
184 | + rotation = int(items[5][9:]) | ||
185 | + if rotation == 90 or rotation == 270: | ||
186 | + clip.width[index], clip.height[index] = clip.height[index], clip.width[index] | ||
187 | + elif items[2] == "close": | ||
188 | + clip.end_time[index] = float(items[0]) | ||
189 | + #video file | ||
190 | + if items[1][-4:] == "webm": | ||
191 | + index = clip.put_file(items[1]) | ||
192 | + if items[2] == "create": | ||
193 | + clip.start_time[index] = float(items[0]) | ||
194 | + elif items[2] == "info": | ||
195 | + clip.start_time[index] = float(items[0]) | ||
196 | + clip.width[index] = int(items[3][6:]) | ||
197 | + clip.height[index] = int(items[4][7:]) | ||
198 | + rotation = int(items[5][9:]) | ||
199 | + if rotation == 90 or rotation == 270: | ||
200 | + clip.width[index], clip.height[index] = clip.height[index], clip.width[index] | ||
201 | + elif items[2] == "close": | ||
202 | + clip.end_time[index] = float(items[0]) | ||
203 | + | ||
204 | + | ||
205 | + clip.print_audio_info() | ||
206 | + for i in range(audio_clip.num): | ||
207 | + audio_clip.print_audio_info(i) | ||
208 | + for i in range(clip.num): | ||
209 | + clip.print_video_info(i) | ||
210 | + | ||
211 | + if audio_clip.num > 1: | ||
212 | + print "Generate Audio File" | ||
213 | + tmp_audio = uid+"_tmp.m4a" | ||
214 | + command = audio_clip.print_ffmpeg(tmp_audio) | ||
215 | + clip.audio_file = tmp_audio | ||
216 | + clip.audio_start_time = 0.0 | ||
217 | + clip.audio_end_time = audio_clip.max_length() | ||
218 | + print command | ||
219 | + print subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, env=child_env).stdout.read() | ||
220 | + elif audio_clip.num == 1: | ||
221 | + clip.audio_file = audio_clip.filename[0] | ||
222 | + clip.audio_start_time = audio_clip.start_time[0] | ||
223 | + clip.audio_end_time = audio_clip.end_time[0] | ||
224 | + | ||
225 | + if clip.num > 0: | ||
226 | + print "Generate MP4 file:" | ||
227 | + print "Output resolution:", clip.max_resolution() | ||
228 | + output_file = uid+"_av"+".mp4" | ||
229 | + #print clip.print_filter() | ||
230 | + command = clip.print_ffmpeg(output_file) | ||
231 | + else: | ||
232 | + tmp_audio = uid+"_tmp.m4a" | ||
233 | + output_file = uid+".m4a" | ||
234 | + if audio_clip.num > 1: | ||
235 | + command = "mv %s %s" % (tmp_audio, output_file) | ||
236 | + elif audio_clip.num == 1: | ||
237 | + command = "ffmpeg -i %s -c:a copy -y %s" % (clip.audio_file, output_file) | ||
238 | + print command | ||
239 | + print subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, env=child_env).stdout.read() | ||
240 | + print "\n\n" | ||
241 | + | ||
242 | +#write a convert done file | ||
243 | +f = open("convert-done.txt", "w+") | ||
244 | +f.close() | ||
245 | + | ||
246 | +#remove tmp files | ||
247 | +os.system('rm -f *_tmp.m4a') | ||
248 | + |
@@ -20,10 +20,6 @@ var hexDecode = function(str) { | @@ -20,10 +20,6 @@ var hexDecode = function(str) { | ||
20 | return new Buffer(str, 'hex'); | 20 | return new Buffer(str, 'hex'); |
21 | }; | 21 | }; |
22 | 22 | ||
23 | - | ||
24 | - | ||
25 | - | ||
26 | - | ||
27 | var Message = function(options) { | 23 | var Message = function(options) { |
28 | options.pack = function() { | 24 | options.pack = function() { |
29 | var out = ByteBuf(); | 25 | var out = ByteBuf(); |
@@ -52,10 +48,10 @@ var IN_CHANNEL_PERMISSION = 4; | @@ -52,10 +48,10 @@ var IN_CHANNEL_PERMISSION = 4; | ||
52 | 48 | ||
53 | var inspectMediaChannelKey = function async(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs) { | 49 | var inspectMediaChannelKey = function async(appID, appCertificate, channelName, unixTs, randomInt, uid, expiredTs) { |
54 | var rawAppID = hexDecode(appID); | 50 | var rawAppID = hexDecode(appID); |
55 | - console.log('App ID:\t\t\t ' + rawAppID.toString('hex').toUpperCase()); | 51 | + // console.log('App ID:\t\t\t ' + rawAppID.toString('hex').toUpperCase()); |
56 | 52 | ||
57 | var rawAppCertificate = hexDecode(appCertificate); | 53 | var rawAppCertificate = hexDecode(appCertificate); |
58 | - console.log('App Certificate:\t ' + rawAppCertificate.toString('hex').toUpperCase()); | 54 | + // console.log('App Certificate:\t ' + rawAppCertificate.toString('hex').toUpperCase()); |
59 | 55 | ||
60 | var serviceType = MEDIA_CHANNEL_SERVICE; | 56 | var serviceType = MEDIA_CHANNEL_SERVICE; |
61 | var extra = null; | 57 | var extra = null; |
@@ -120,7 +116,6 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | @@ -120,7 +116,6 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | ||
120 | return that; | 116 | return that; |
121 | } | 117 | } |
122 | var Message = function(options) { | 118 | var Message = function(options) { |
123 | - console.log('s生成buffer') | ||
124 | 119 | ||
125 | options.pack = function() { | 120 | options.pack = function() { |
126 | var out = ByteBuf(); | 121 | var out = ByteBuf(); |
@@ -150,10 +145,10 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | @@ -150,10 +145,10 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | ||
150 | }); | 145 | }); |
151 | 146 | ||
152 | var toSign = m.pack(); | 147 | var toSign = m.pack(); |
153 | - console.log("Message to sign:\t " + toSign.toString('hex').toUpperCase()); | 148 | + // console.log("Message to sign:\t " + toSign.toString('hex').toUpperCase()); |
154 | 149 | ||
155 | var signature = encodeHMac(rawAppCertificate, toSign); | 150 | var signature = encodeHMac(rawAppCertificate, toSign); |
156 | - console.log("Signature:\t\t " + signature.toString('hex').toUpperCase()); | 151 | + // console.log("Signature:\t\t " + signature.toString('hex').toUpperCase()); |
157 | var DynamicKey5Content = function(options) { | 152 | var DynamicKey5Content = function(options) { |
158 | options.pack = function() { | 153 | options.pack = function() { |
159 | var out = ByteBuf(); | 154 | var out = ByteBuf(); |
@@ -177,10 +172,10 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | @@ -177,10 +172,10 @@ var inspectMediaChannelKey = function async(appID, appCertificate, channelName, | ||
177 | , salt: randomInt | 172 | , salt: randomInt |
178 | , expiredTs: expiredTs | 173 | , expiredTs: expiredTs |
179 | , extra: extra}).pack(); | 174 | , extra: extra}).pack(); |
180 | - console.log("Content to encode:\t " + content.toString('hex').toUpperCase()); | 175 | + // console.log("Content to encode:\t " + content.toString('hex').toUpperCase()); |
181 | 176 | ||
182 | var channelKey = version + content.toString('base64'); | 177 | var channelKey = version + content.toString('base64'); |
183 | - console.log("Channel key:\t\t " + channelKey); | 178 | + // console.log("Channel key:\t\t " + channelKey); |
184 | return channelKey; | 179 | return channelKey; |
185 | }; | 180 | }; |
186 | 181 |
-
请 注册 或 登录 后发表评论