diff --git a/taoyao-client-android/README.md b/taoyao-client-android/README.md index f3c4ce7..f258866 100644 --- a/taoyao-client-android/README.md +++ b/taoyao-client-android/README.md @@ -3,8 +3,10 @@ ## 支持版本 * SDK 28~32 +* WebRTC m94 * Gradle 7.5 * Andoird 9~12 +* libmediasoupclient 3.4.0 ## C++终端 diff --git a/taoyao-client-android/taoyao/.gitignore b/taoyao-client-android/taoyao/.gitignore index cb21238..7fb9089 100644 --- a/taoyao-client-android/taoyao/.gitignore +++ b/taoyao-client-android/taoyao/.gitignore @@ -2,6 +2,7 @@ .idea .gradle -media/deps +media/deps/webrtc +media/deps/libmediasoupclient local.properties diff --git a/taoyao-client-android/taoyao/media/deps/README.md b/taoyao-client-android/taoyao/media/deps/README.md new file mode 100644 index 0000000..e581a49 --- /dev/null +++ b/taoyao-client-android/taoyao/media/deps/README.md @@ -0,0 +1,17 @@ +# 依赖 + +[WebRTC](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc) + +下载文件放到响应目录 + +``` +deps + ├─libmediasoupclient + └─webrtc + ├─lib + │ ├─arm64-v8a + │ ├─armeabi-v7a + │ ├─x86 + │ └─x86_64 + └─src +``` diff --git a/taoyao-client-openharmony/README.md b/taoyao-client-openharmony/README.md index 7e0e771..514d305 100644 --- a/taoyao-client-openharmony/README.md +++ b/taoyao-client-openharmony/README.md @@ -3,6 +3,8 @@ ## 支持版本 * SDK 11 +* WebRTC m114 +* libmediasoupclient m120 ## C++终端 diff --git a/taoyao-client-openharmony/taoyao/.gitignore b/taoyao-client-openharmony/taoyao/.gitignore index 72eaace..882834b 100644 --- a/taoyao-client-openharmony/taoyao/.gitignore +++ b/taoyao-client-openharmony/taoyao/.gitignore @@ -8,7 +8,9 @@ local.properties oh-package-lock.json5 -deps build oh_modules node_modules + +media/src/main/cpp/deps/webrtc +media/src/main/cpp/deps/libmediasoupclient diff --git a/taoyao-client-openharmony/taoyao/media/build-profile.json5 b/taoyao-client-openharmony/taoyao/media/build-profile.json5 index d686a77..f577185 100644 --- a/taoyao-client-openharmony/taoyao/media/build-profile.json5 +++ b/taoyao-client-openharmony/taoyao/media/build-profile.json5 @@ -5,6 +5,7 @@ "path": "./src/main/cpp/CMakeLists.txt", "cppFlags" : "", "arguments" : "", + // 不要自作多情添加一些配置🤡🤡🤡🤡 // "cppFlags" : "-D_LIBCPP_STD_VER=17", // "arguments" : "-DOHOS_STL=c++_static", // "arguments" : "-DOHOS_STL=c++_shared", diff --git a/taoyao-client-openharmony/taoyao/media/oh-package.json5 b/taoyao-client-openharmony/taoyao/media/oh-package.json5 index 217c8aa..21f0af2 100644 --- a/taoyao-client-openharmony/taoyao/media/oh-package.json5 +++ b/taoyao-client-openharmony/taoyao/media/oh-package.json5 @@ -1,11 +1,11 @@ { - "main" : "", - "name" : "media", - "author": "acgist", + "main" : "", + "name" : "media", + "author" : "acgist", "version": "1.0.0", "license": "Apache-2.0", - "description": "桃夭媒体终端", - "dependencies" : { + "description" : "桃夭媒体终端", + "dependencies": { "libtaoyao.so": "file:./src/main/cpp/types/libtaoyao" }, "devDependencies" : {}, diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp index ece8bcb..54d82e9 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp @@ -20,10 +20,41 @@ #include #include +static std::mutex taoyaoMutex; static std::mutex roomMutex; +#ifndef TAOYAO_JSON_SIZE +#define TAOYAO_JSON_SIZE 2048 +#endif + +#ifndef TAOYAO_JSON_BODY +#define TAOYAO_JSON_BODY() \ +napi_value ret; \ + size_t argc = 1; \ + napi_value args[1] = {nullptr}; \ + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); \ + size_t length; \ + char chars[2048]; \ + napi_get_value_string_utf8(env, args[0], chars, sizeof(chars), &length); \ + nlohmann::json json = nlohmann::json::parse(chars); \ + nlohmann::json body = json["body"]; +#endif + +#ifndef TAOYAO_ROOM_CHECK +#define TAOYAO_ROOM_CHECK(action) \ +std::string roomId = body["roomId"]; \ +auto room = acgist::roomMap.find(roomId); \ +if(room == acgist::roomMap.end()) { \ + OH_LOG_WARN(LOG_APP, "房间无效:%s %s", #action, roomId.data()); \ + napi_create_int32(env, -1, &ret); \ + return ret; \ +} +#endif + namespace acgist { +// 终端ID +static std::string clientId = ""; // JS环境 static napi_env env = nullptr; // 是否加载 @@ -55,48 +86,60 @@ static void printSupportCodec() { /** * 加载系统 */ -static void init() { - if(initTaoyao) { - return; +static void init(napi_env env, napi_callback_info info) { + { + std::lock_guard taoyaoLock(taoyaoMutex); + if(initTaoyao) { + return; + } + initTaoyao = true; } - initTaoyao = true; + TAOYAO_JSON_BODY(); + acgist::clientId = json["clientId"]; OH_LOG_INFO(LOG_APP, "加载libtaoyao"); - // 编码能力 printSupportCodec(); std::string version = mediasoupclient::Version(); OH_LOG_INFO(LOG_APP, "加载MediasoupClient:%s", version.data()); mediasoupclient::Initialize(); OH_LOG_INFO(LOG_APP, "加载媒体功能"); mediaManager = new MediaManager(); - mediaManager->initPeerConnectionFactory(); + mediaManager->init(); } /** * 卸载系统 */ static napi_value shutdown(napi_env env, napi_callback_info info) { - if(!initTaoyao) { - OH_LOG_INFO(LOG_APP, "已经卸载libtaoyao"); - return 0; + { + std::lock_guard taoyaoLock(taoyaoMutex); + if(!initTaoyao) { + OH_LOG_INFO(LOG_APP, "已经卸载libtaoyao"); + return 0; + } + initTaoyao = false; } - initTaoyao = false; OH_LOG_INFO(LOG_APP, "卸载libtaoyao"); OH_LOG_INFO(LOG_APP, "释放mediasoupclient"); mediasoupclient::Cleanup(); - // 删除房间 - for(auto iterator = roomMap.begin(); iterator != roomMap.end(); ++iterator) { + OH_LOG_INFO(LOG_APP, "清空房间"); + for(auto iterator = acgist::roomMap.begin(); iterator != acgist::roomMap.end(); ++iterator) { delete iterator->second; iterator->second = nullptr; } - roomMap.clear(); - // 关闭媒体 + acgist::roomMap.clear(); + OH_LOG_INFO(LOG_APP, "关闭媒体"); if (mediaManager != nullptr) { delete mediaManager; mediaManager = nullptr; } + OH_LOG_INFO(LOG_APP, "释放全局变量"); // napi_delete_reference(env, acgist::sendRef); // napi_delete_reference(env, acgist::requestRef); - return 0; + env = nullptr; + // 返回结果 + napi_value ret; + napi_create_int32(env, 0, &ret); + return ret; } /** @@ -124,9 +167,12 @@ std::string request(const std::string& signal, const std::string& body) { napi_create_string_utf8(acgist::env, signal.data(), NAPI_AUTO_LENGTH, &data[0]); napi_create_string_utf8(acgist::env, body.data(), NAPI_AUTO_LENGTH, &data[1]); napi_call_function(acgist::env, nullptr, callback, 2, data, &ret); - char chars[2048]; + char chars[TAOYAO_JSON_SIZE]; size_t length; napi_get_value_string_utf8(env, ret, chars, sizeof(chars), &length); + // TODO: promise + // napi_create_promise + // napi_resolve_deferred return chars; } @@ -134,18 +180,23 @@ std::string request(const std::string& signal, const std::string& body) { * 房间关闭 */ static napi_value roomClose(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); { - std::lock_guard guard(roomMutex); - auto iterator = roomMap.find("roomId"); - if(iterator == roomMap.end()) { - + std::lock_guard roomLock(roomMutex); + std::string roomId = body["roomId"]; + auto iterator = acgist::roomMap.find(roomId); + if(iterator == acgist::roomMap.end()) { + OH_LOG_WARN(LOG_APP, "关闭房间无效:%s", roomId.data()); + napi_create_int32(env, -1, &ret); } else { + OH_LOG_INFO(LOG_APP, "关闭房间:%s", roomId.data()); delete iterator->second; iterator->second = nullptr; - roomMap.erase(iterator); + acgist::roomMap.erase(iterator); + napi_create_int32(env, 0, &ret); } } - return 0; + return ret; } /** @@ -153,44 +204,64 @@ static napi_value roomClose(napi_env env, napi_callback_info info) { * 其他终端进入房间,自己进入房间逻辑参考房间邀请。 */ static napi_value roomEnter(napi_env env, napi_callback_info info) { - return 0; + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("进入房间"); + std::string clientId = body["clientId"]; + OH_LOG_INFO(LOG_APP, "进入房间:%s %s", roomId.data(), clientId.data()); + if(clientId == acgist::clientId) { + // 忽略关闭自己 + napi_create_int32(env, -2, &ret); + return ret; + } + nlohmann::json status = body["status"]; + std::string name = status["name"]; + int result = room->newRemoteClient(clientId, name); + napi_create_int32(env, result, &ret); + return ret; } /** * 踢出房间 * 踢出房间以后终端离开房间 */ -static napi_value roomExpel(napi_env env, napi_callback_info info) { return 0; } +static napi_value roomExpel(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("踢出房间"); + OH_LOG_INFO(LOG_APP, "进入房间:%s", roomId.data()); + nlohmann::json requestBody = { + { "roomId", roomId }, + }; + acgist::send("room::leave", requestBody.dump()); + delete room->second; + room->second = nullptr; + acgist::roomMap.erase(room); + napi_create_int32(env, 0, &ret); + return ret; +} /** * 房间邀请 * 邀请终端进入房间 */ static napi_value roomInvite(napi_env env, napi_callback_info info) { - size_t argc = 1; - napi_value args[1] = { nullptr }; - napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - size_t length; - char chars[2048]; - napi_get_value_string_utf8(env, args[0], chars, sizeof(chars), &length); - nlohmann::json json = nlohmann::json::parse(chars); - nlohmann::json body = json["body"]; - // TODO: 试试引用 - std::string roomId = body["roomId"]; - std::string password = body["password"]; - napi_value ret; + TAOYAO_JSON_BODY(); { - std::lock_guard guard(roomMutex); - auto iterator = roomMap.find(roomId); - if(iterator == roomMap.end()) { + std::lock_guard roomLock(roomMutex); + // TODO: 试试引用 + std::string roomId = body["roomId"]; + std::string password = body["password"]; + auto oldRoom = acgist::roomMap.find(roomId); + if(oldRoom == acgist::roomMap.end()) { OH_LOG_INFO(LOG_APP, "进入房间:%s", roomId.data()); auto room = new acgist::Room(roomId, mediaManager); - roomMap[roomId] = room; - int enterRet = room->enter(password); - if(enterRet == acgist::SUCCESS_CODE) { + int result = room->enter(password); + if(result == acgist::SUCCESS_CODE) { + acgist::roomMap.insert({ roomId, room }); room->produceMedia(); + } else { + delete room; } - napi_create_int32(env, enterRet, &ret); + napi_create_int32(env, result, &ret); } else { OH_LOG_INFO(LOG_APP, "已经进入房间:%s", roomId.data()); napi_create_int32(env, -1, &ret); @@ -203,48 +274,137 @@ static napi_value roomInvite(napi_env env, napi_callback_info info) { * 离开房间 * 其他终端离开房间 */ -static napi_value roomLeave(napi_env env, napi_callback_info info) { return 0; } +static napi_value roomLeave(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("离开房间"); + std::string clientId = body["clientId"]; + OH_LOG_INFO(LOG_APP, "离开房间:%s %s", roomId.data(), clientId.data()); + if(clientId == acgist::clientId) { + // 忽略关闭自己 + napi_create_int32(env, -2, &ret); + return ret; + } + int result = room->second->closeRemoteClient(clientId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 终端列表 * 房间所有终端列表首次进入方便加载终端列表信息 */ -static napi_value roomClientList(napi_env env, napi_callback_info info) { return 0; } +static napi_value roomClientList(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("终端列表"); + nlohmann::json clients = body["clients"]; + if(clients.empty()) { + napi_create_int32(env, 0, &ret); + return ret; + } + for(auto client = clients.begin(); client != clients.end(); ++client) { + std::string clientId = (*client)["clientId"]; + std::string name = (*client)["name"]; + if(clientId == acgist::clientId) { + // 忽略关闭自己 + continue; + } + room->second->newRemoteClient(clientId, name); + } + napi_create_int32(env, 0, &ret); + return ret; +} /** * 媒体消费(被动通知) */ -static napi_value mediaConsume(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaConsume(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK(); + TAOYAO_ROOM_CHECK("媒体消费"); + int result = room->second->newConsumer(body); + acgist::send(chars); + // acgist::send(json.dump()); + napi_create_int32(env, result, &ret); + return ret; +} /** * 消费者关闭(被动通知) */ -static napi_value mediaConsumerClose(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaConsumerClose(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("消费者关闭"); + std::string consumerId = body["consumerId"]; + TAOYAO_ROOM_CHECK("消费者关闭:%s", consumerId.data()); + int result = room->second->closeConsumer(consumerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 消费者暂停(被动通知) */ -static napi_value mediaConsumerPause(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaConsumerPause(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("消费者暂停"); + std::string consumerId = body["consumerId"]; + TAOYAO_ROOM_CHECK("消费者暂停:%s", consumerId.data()); + int result = room->second->pauseConsumer(consumerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 消费者恢复(被动通知) */ -static napi_value mediaConsumerResume(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaConsumerResume(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("消费者恢复"); + std::string consumerId = body["consumerId"]; + TAOYAO_ROOM_CHECK("消费者恢复:%s", consumerId.data()); + int result = room->second->resumeConsumer(consumerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 生产者关闭(被动通知) */ -static napi_value mediaProducerClose(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaProducerClose(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("生产者关闭"); + std::string producerId = body["producerId"]; + TAOYAO_ROOM_CHECK("生产者关闭:%s", producerId.data()); + int result = room->second->closeProducer(producerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 生产者暂停(被动通知) */ -static napi_value mediaProducerPause(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaProducerPause(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("生产者暂停"); + std::string producerId = body["producerId"]; + TAOYAO_ROOM_CHECK("生产者暂停:%s", producerId.data()); + int result = room->second->pauseProducer(producerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 生产者恢复(被动通知) */ -static napi_value mediaProducerResume(napi_env env, napi_callback_info info) { return 0; } +static napi_value mediaProducerResume(napi_env env, napi_callback_info info) { + TAOYAO_JSON_BODY(); + TAOYAO_ROOM_CHECK("生产者恢复"); + std::string producerId = body["producerId"]; + TAOYAO_ROOM_CHECK("生产者恢复:%s", producerId.data()); + int result = room->second->resumeProducer(producerId); + napi_create_int32(env, result, &ret); + return ret; +} /** * 注册发送回调 @@ -265,8 +425,6 @@ static napi_value registerRequest(napi_env env, napi_callback_info info) { napi_value args[1] = { nullptr }; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); napi_create_reference(env, args[0], 1, &acgist::requestRef); - // napi_create_promise - // napi_resolve_deferred return 0; } @@ -276,6 +434,7 @@ EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { acgist::env = env; napi_property_descriptor desc[] = { + { "init", nullptr, acgist::init, nullptr, nullptr, nullptr, napi_default, nullptr }, { "shutdown", nullptr, acgist::shutdown, nullptr, nullptr, nullptr, napi_default, nullptr }, { "roomClose", nullptr, acgist::roomClose, nullptr, nullptr, nullptr, napi_default, nullptr }, { "roomEnter", nullptr, acgist::roomEnter, nullptr, nullptr, nullptr, napi_default, nullptr }, diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/deps/README.md b/taoyao-client-openharmony/taoyao/media/src/main/cpp/deps/README.md new file mode 100644 index 0000000..cb96878 --- /dev/null +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/deps/README.md @@ -0,0 +1,13 @@ +# 依赖 + +[WebRTC](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc) + +下载文件放到响应目录 + +``` +deps + ├─libmediasoupclient + └─webrtc + ├─lib + └─src +``` diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Capturer.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Capturer.hpp index dfa68ee..866820e 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Capturer.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Capturer.hpp @@ -12,8 +12,9 @@ * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/camera/native-camera-recording.md * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/audio/using-ohaudio-for-recording.md */ -#ifndef taoyao_Capturer_HPP -#define taoyao_Capturer_HPP + +#ifndef TAOYAO_CAPTURER_HPP +#define TAOYAO_CAPTURER_HPP #include @@ -172,4 +173,4 @@ public: } -#endif // taoyao_Capturer_HPP +#endif // TAOYAO_CAPTURER_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Client.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Client.hpp index 6944b25..c09e3d3 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Client.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Client.hpp @@ -3,11 +3,14 @@ * * @author acgist */ -#ifndef taoyao_Client_HPP -#define taoyao_Client_HPP + +#ifndef TAOYAO_CLIENT_HPP +#define TAOYAO_CLIENT_HPP #include "MediaManager.hpp" +#include "mediasoupclient.hpp" + namespace acgist { /** @@ -16,6 +19,10 @@ namespace acgist { class Client { public: + // 终端ID + std::string clientId; + // 终端名称 + std::string name; // 媒体管理 acgist::MediaManager* mediaManager = nullptr; // 音频轨道 @@ -28,12 +35,6 @@ public: virtual ~Client(); public: - /** - * 资源释放 - * - * @return 是否成功 - */ - virtual bool release() = 0; }; @@ -47,7 +48,6 @@ public: virtual ~RoomClient(); public: - virtual bool release() override; }; @@ -61,7 +61,6 @@ public: virtual ~LocalClient(); public: - virtual bool release() override; }; @@ -70,15 +69,26 @@ public: */ class RemoteClient : public RoomClient { +public: + // 消费者列表 + std::map consumers; + public: RemoteClient(acgist::MediaManager* mediaManager); virtual ~RemoteClient(); public: - virtual bool release() override; + // 添加消费者 + bool addConsumer(const std::string& consuemrId, mediasoupclient::Consumer* consumer); + // 关闭消费者 + bool closeConsumer(const std::string& consumerId); + // 暂停消费者 + bool pauseConsumer(const std::string& consumerId); + // 恢复消费者 + bool resumeConsumer(const std::string& consumerId); }; } -#endif // taoyao_Client_HPP +#endif // TAOYAO_CLIENT_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/MediaManager.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/MediaManager.hpp index 154bbb7..7e81f61 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/MediaManager.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/MediaManager.hpp @@ -6,8 +6,9 @@ * * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/avcodec/obtain-supported-codecs.md */ -#ifndef taoyao_MediaManager_HPP -#define taoyao_MediaManager_HPP + +#ifndef TAOYAO_MEDIAMANAGER_HPP +#define TAOYAO_MEDIAMANAGER_HPP #include #include @@ -20,30 +21,36 @@ namespace acgist { class TaoyaoAudioSink : public webrtc::AudioTrackSinkInterface { - }; class TaoyaoVideoSource : public webrtc::VideoTrackSourceInterface { - }; class TaoyaoVideoSink : public rtc::VideoSinkInterface { - }; class MediaManager { + public: MediaManager(); - ~MediaManager(); + virtual ~MediaManager(); + public: int localClientRef = 0; std::unique_ptr networkThread = nullptr; std::unique_ptr signalingThread = nullptr; std::unique_ptr workerThread = nullptr; rtc::scoped_refptr peerConnectionFactory = nullptr; -public: + +protected: // 加载PC工厂 - bool initPeerConnectionFactory(); + bool newPeerConnectionFactory(); + // 释放PC工厂 + bool releasePeerConnectionFactory(); + +public: + // 加载媒体 + bool init(); // 新增本地终端 int newLocalClient(); // 释放本地终端 @@ -64,8 +71,9 @@ public: rtc::scoped_refptr getAudioTrack(); // 视频来源 rtc::scoped_refptr getVideoTrack(); + }; } -#endif // taoyao_MediaManager_HPP +#endif // TAOYAO_MEDIAMANAGER_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp index 3c6bb1f..bc05432 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp @@ -5,6 +5,7 @@ * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/audio/audio-playback-overview.md * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/media/using-ndk-avplayer-for-playerback.md */ + #ifndef TAOYAO_PALYER_HPP #define TAOYAO_PALYER_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Room.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Room.hpp index 1b0035a..c5cdd40 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Room.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Room.hpp @@ -3,8 +3,9 @@ * * @author acgist */ -#ifndef taoyao_Room_HPP -#define taoyao_Room_HPP + +#ifndef TAOYAO_ROOM_HPP +#define TAOYAO_ROOM_HPP #include #include @@ -218,7 +219,9 @@ public: acgist::MediaManager* mediaManager = nullptr; // 本地终端 acgist::LocalClient* client = nullptr; - // 远程终端 + // ID映射:consumerId = clientId + std::map consumerIdClientId; + // 远程终端:clientId = RemoteClient std::map clients; // WebRTC配置 webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration; @@ -240,8 +243,10 @@ public: mediasoupclient::Producer::Listener* producerListener = nullptr; // 消费者监听器 mediasoupclient::Consumer::Listener* consumerListener = nullptr; - // 消费者列表 - std::map consumers; + // 本地音频 + rtc::scoped_refptr audioTrack = nullptr; + // 本地视频 + rtc::scoped_refptr videoTrack = nullptr; public: Room(const std::string& roomId, acgist::MediaManager* mediaManager); @@ -262,19 +267,47 @@ public: * @return 状态 */ int produceMedia(); + // 创建发送通道 int createSendTransport(); + // 创建接收通道 int createRecvTransport(); + // 生产音频 int produceAudio(); + // 生产视频 int produceVideo(); + // 关闭房间 int close(); - int closeConsumer(); + // 关闭本地消费者 + int closeClient(); + // 关闭远程消费者 + int closeClients(); + // 关闭音频生产者 int closeAudioProducer(); + // 关闭视频生产者 int closeVideoProducer(); + // 关闭通道 int closeTransport(); - int newRemoteClient(); + // 新建远程终端 + int newRemoteClient(const std::string& clientId, const std::string& name); + // 删除远程终端 + int closeRemoteClient(const std::string& clientId); + // 新增消费者 + int newConsumer(nlohmann::json& body); + // 删除消费者 + int closeConsumer(const std::string& consumerId); + // 暂停消费者 + int pauseConsumer(const std::string& consumerId); + // 恢复消费者 + int resumeConsumer(const std::string& consumerId); + // 关闭生产者 + int closeProducer(const std::string& producerId); + // 暂停生产者 + int pauseProducer(const std::string& producerId); + // 恢复生产者 + int resumeProducer(const std::string& producerId); }; } -#endif // taoyao_Room_HPP +#endif // TAOYAO_ROOM_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp index 29da80b..bce17e4 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp @@ -1,6 +1,7 @@ /** * 信令 */ + #ifndef TAOYAO_SIGNAL_HPP #define TAOYAO_SIGNAL_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/LocalClient.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/LocalClient.cpp index 1c20b11..bae6cb5 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/LocalClient.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/LocalClient.cpp @@ -5,10 +5,5 @@ acgist::LocalClient::LocalClient(acgist::MediaManager* mediaManager) : acgist::R } acgist::LocalClient::~LocalClient() { - this->release(); this->mediaManager->releaseLocalClient(); } - -bool acgist::LocalClient::release() { - return true; -} diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/MediaManager.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/MediaManager.cpp index ece1e85..17c655f 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/MediaManager.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/MediaManager.cpp @@ -14,7 +14,7 @@ #include #include -static std::mutex refMutex; +static std::mutex lockMutex; acgist::MediaManager::MediaManager() { } @@ -23,7 +23,11 @@ acgist::MediaManager::~MediaManager() { // TODO:验证是否需要释放线程和工厂 } -bool acgist::MediaManager::initPeerConnectionFactory() { +bool acgist::MediaManager::init() { + return true; +} + +bool acgist::MediaManager::newPeerConnectionFactory() { OH_LOG_INFO(LOG_APP, "加载PeerConnectionFactory"); this->networkThread = rtc::Thread::CreateWithSocketServer(); this->signalingThread = rtc::Thread::Create(); @@ -33,6 +37,7 @@ bool acgist::MediaManager::initPeerConnectionFactory() { this->workerThread->SetName("worker_thread", nullptr); if (!this->networkThread->Start() || !this->signalingThread->Start() || !this->workerThread->Start()) { OH_LOG_WARN(LOG_APP, "WebRTC线程启动失败"); + // TODO: 释放线程 return false; } this->peerConnectionFactory = webrtc::CreatePeerConnectionFactory( @@ -47,25 +52,43 @@ bool acgist::MediaManager::initPeerConnectionFactory() { nullptr, nullptr, // TODO: 视频工厂 -// webrtc::CreateBuiltinVideoEncoderFactory(), -// webrtc::CreateBuiltinVideoDecoderFactory(), + // webrtc::CreateBuiltinVideoEncoderFactory(), + // webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, nullptr /* audio_processing */ ); return this->peerConnectionFactory != nullptr; } +bool acgist::MediaManager::releasePeerConnectionFactory() { + OH_LOG_INFO(LOG_APP, "释放PeerConnectionFactory"); + // TODO:释放 + return true; +} + int acgist::MediaManager::newLocalClient() { { - std::lock_guard guard(refMutex); + std::lock_guard mediaLock(lockMutex); this->localClientRef++; + if(this->localClientRef > 0) { + this->newPeerConnectionFactory(); + this->startCapture(); + } } } int acgist::MediaManager::releaseLocalClient() { { - std::lock_guard guard(refMutex); + std::lock_guard mediaLock(lockMutex); this->localClientRef--; + if(this->localClientRef <= 0) { + if(this->localClientRef < 0) { + this->localClientRef = 0; + } else { + this->stopCapture(); + this->releasePeerConnectionFactory(); + } + } } } @@ -83,6 +106,18 @@ bool acgist::MediaManager::startVideoCapture() { return true; } +bool acgist::MediaManager::stopCapture() { + return true; +} + +bool acgist::MediaManager::stopAudioCapture() { + return true; +} + +bool acgist::MediaManager::stopVideoCapture() { + return true; +} + rtc::scoped_refptr acgist::MediaManager::getAudioTrack() { cricket::AudioOptions options; options.highpass_filter = true; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RemoteClient.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RemoteClient.cpp index 8672935..07d91bc 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RemoteClient.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RemoteClient.cpp @@ -1,7 +1,74 @@ #include "../include/Client.hpp" +#include + +#include "hilog/log.h" + +static std::mutex clientMutex; + acgist::RemoteClient::RemoteClient(acgist::MediaManager* mediaManager) : RoomClient(mediaManager) {} -acgist::RemoteClient::~RemoteClient() {} +acgist::RemoteClient::~RemoteClient() { + for(auto iterator = this->consumers.begin(); iterator != this->consumers.end(); ++iterator) { + iterator->second->Close(); + delete iterator->second; + iterator->second = nullptr; + } + this->consumers.clear(); +} -bool acgist::RemoteClient::release() { return true; } +bool acgist::RemoteClient::addConsumer(const std::string& consumerId, mediasoupclient::Consumer* consumer) { + std::lock_guard clientLock(lockMutex); + auto oldConsumer = this->consumers.find(clientId); + if(oldConsumer != this->consumers.end()) { + OH_LOG_INFO(LOG_APP, "关闭旧的消费者:%s", consumerId.data()); + oldConsumer->second->Close(); + delete oldConsumer->second; + oldConsumer->second = nullptr; + this->consumers.erase(oldConsumer); + } + OH_LOG_INFO(LOG_APP, "添加新的消费者:%s", consumerId.data()); + this->consumers.insert({ consumerId, consumer }); + webrtc::MediaStreamTrackInterface* trackPointer = consumer->GetTrack(); + // TODO: 播放 + return true; +} + +bool acgist::RemoteClient::closeConsumer(const std::string& consumerId) { + std::lock_guard clientLock(lockMutex); + auto consumer = this->consumers.find(consumerId); + if(consumer == this->consumers.end()) { + OH_LOG_INFO(LOG_APP, "消费者已经关闭:%s", consumerId.data()); + return false; + } + OH_LOG_INFO(LOG_APP, "关闭消费者:%s", consumerId.data()); + consumer->second->Close(); + delete consumer->second; + consumer->second = nullptr; + this->consumers.erase(consumer); + return true; +} + +bool acgist::RemoteClient::pauseConsumer(const std::string& consumerId) { + std::lock_guard clientLock(lockMutex); + auto consumer = this->consumers.find(consumerId); + if(consumer == this->consumers.end()) { + OH_LOG_INFO(LOG_APP, "无效消费者:%s", consumerId.data()); + return false; + } + OH_LOG_INFO(LOG_APP, "暂停消费者:%s", consumerId.data()); + consumer->second->Pause(); + return true; +} + +bool acgist::RemoteClient::resumeConsumer(const std::string& consumerId) { + std::lock_guard clientLock(lockMutex); + auto consumer = this->consumers.find(consumerId); + if(consumer == this->consumers.end()) { + OH_LOG_INFO(LOG_APP, "无效消费者:%s", consumerId.data()); + return false; + } + OH_LOG_INFO(LOG_APP, "恢复消费者:%s", consumerId.data()); + consumer->second->Resume(); + return true; +} diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Room.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Room.cpp index cef92f4..4df294d 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Room.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Room.cpp @@ -16,6 +16,7 @@ acgist::Room::Room(const std::string& roomId, acgist::MediaManager* mediaManager acgist::Room::~Room() { this->close(); + this->consumerIdClientId.clear(); // rtcConfiguration if (this->device != nullptr) { delete this->device; @@ -53,10 +54,10 @@ acgist::Room::~Room() { delete this->consumerListener; this->consumerListener = nullptr; } - if(this->client != nullptr) { - delete this->client; - this->client = nullptr; - } + // TODO: delete audio track + // TODO: delete video track + // TODO: delete local client + // TODO: delete remote client } int acgist::Room::enter(const std::string& password) { @@ -109,6 +110,7 @@ int acgist::Room::produceMedia() { } int acgist::Room::createSendTransport() { + OH_LOG_INFO(LOG_APP, "创建发送通道:%s", this->roomId.data()); nlohmann::json requestBody = { { "roomId", this->roomId }, { "forceTcp", false }, @@ -135,6 +137,7 @@ int acgist::Room::createSendTransport() { } int acgist::Room::createRecvTransport() { + OH_LOG_INFO(LOG_APP, "创建接收通道:%s", this->roomId.data()); nlohmann::json requestBody = { { "roomId", this->roomId }, { "forceTcp", false }, @@ -161,39 +164,112 @@ int acgist::Room::createRecvTransport() { } int acgist::Room::produceAudio() { + if(!this->device->CanProduce("audio") || this->audioProducer == nullptr) { + OH_LOG_INFO(LOG_APP, "不能生产音频媒体:%s", this->roomId.data()); + return -1; + } + // TODO:track + if(this->audioTrack->state() == webrtc::MediaStreamTrackInterface::TrackState::kEnded) { + OH_LOG_INFO(LOG_APP, "音频媒体状态错误:%s", this->roomId.data()); + return -2; + } + OH_LOG_INFO(LOG_APP, "生产音频媒体:%s", this->roomId.data()); + nlohmann::json codecOptions = { + { "opusStereo", true }, + { "opusDtx", true } + }; + this->audioProducer = this->sendTransport->Produce( + this->producerListener, + this->audioTrack, + nullptr, + &codecOptions, + nullptr + ); return 0; } int acgist::Room::produceVideo() { + if(!this->device->CanProduce("video") || this->videoProducer == nullptr) { + OH_LOG_INFO(LOG_APP, "不能生产视频媒体:%s", this->roomId.data()); + return -1; + } + // TODO:track + if(this->videoTrack->state() == webrtc::MediaStreamTrackInterface::TrackState::kEnded) { + OH_LOG_INFO(LOG_APP, "视频媒体状态错误:%s", this->roomId.data()); + return -2; + } + OH_LOG_INFO(LOG_APP, "生产视频媒体:%s", this->roomId.data()); + // TODO:配置读取同时测试效果 + nlohmann::json codecOptions = { + // x-google-start-bitrate + { "videoGoogleStartBitrate", 1200 }, + // x-google-min-bitrate + { "videoGoogleMinBitrate", 800 }, + // x-google-max-bitrate + { "videoGoogleMaxBitrate", 1600 } + }; + // 如果需要使用`Simulcast`打开下面配置 + // std::vector encodings; + // webrtc::RtpEncodingParameters min; + // webrtc::RtpEncodingParameters mid; + // webrtc::RtpEncodingParameters max; + // min.active = true; + // min.max_framerate = 15; + // min.min_bitrate_bps = 400; + // min.max_bitrate_bps = 800; + // encodings.emplace_back(min); + // encodings.emplace_back(mid); + // encodings.emplace_back(max); + // 强制设置编码器 + // nlohmann::json codec = this->device->GetRtpCapabilities()["codec"]; + this->videoProducer = this->sendTransport->Produce( + this->producerListener, + this->videoTrack, + nullptr, + &codecOptions, + nullptr + ); return 0; } int acgist::Room::close() { OH_LOG_INFO(LOG_APP, "关闭房间:%s", this->roomId.data()); - this->closeConsumer(); + this->closeClient(); + this->closeClients(); this->closeAudioProducer(); this->closeVideoProducer(); this->closeTransport(); return 0; } -int acgist::Room::closeConsumer() { +int acgist::Room::closeClient() { std::lock_guard lockRoom(roomMutex); - for (auto iterator = this->consumers.begin(); iterator != this->consumers.end(); ++iterator) { + OH_LOG_INFO(LOG_APP, "关闭本地终端:%s", this->roomId.data()); + if(this->client != nullptr) { + delete this->client; + this->client = nullptr; + } + return 0; +} + +int acgist::Room::closeClients() { + std::lock_guard lockRoom(roomMutex); + OH_LOG_INFO(LOG_APP, "关闭远程终端:%s", this->roomId.data()); + for (auto iterator = this->clients.begin(); iterator != this->clients.end(); ++iterator) { if (iterator->second == nullptr) { continue; } - OH_LOG_INFO(LOG_APP, "关闭消费者:%s", iterator->second->GetId().data()); - iterator->second->Close(); + OH_LOG_INFO(LOG_APP, "关闭消费者:%s", iterator->first.data()); delete iterator->second; iterator->second = nullptr; } - this->consumers.clear(); + this->clients.clear(); return 0; } int acgist::Room::closeAudioProducer() { std::lock_guard lockRoom(roomMutex); + OH_LOG_INFO(LOG_APP, "关闭音频生产者:%s", this->roomId.data()); if (this->audioProducer != nullptr) { this->audioProducer->Close(); } @@ -202,6 +278,7 @@ int acgist::Room::closeAudioProducer() { int acgist::Room::closeVideoProducer() { std::lock_guard lockRoom(roomMutex); + OH_LOG_INFO(LOG_APP, "关闭视频生产者:%s", this->roomId.data()); if (this->videoProducer != nullptr) { this->videoProducer->Close(); } @@ -210,6 +287,7 @@ int acgist::Room::closeVideoProducer() { int acgist::Room::closeTransport() { std::lock_guard lockRoom(roomMutex); + OH_LOG_INFO(LOG_APP, "关闭通道:%s", this->roomId.data()); if (this->sendTransport != nullptr) { this->sendTransport->Close(); } @@ -219,6 +297,165 @@ int acgist::Room::closeTransport() { return 0; } +int acgist::Room::newRemoteClient(const std::string& clientId, const std::string& name) { + std::lock_guard lockRoom(roomMutex); + auto oldClient = this->clients.find(clientId); + if(oldClient != this->clients.end()) { + OH_LOG_INFO(LOG_APP, "已经存在远程终端:%s", clientId.data()); + delete oldClient->second; + oldClient->second = null; + this->clients.erase(oldClient); + } + OH_LOG_INFO(LOG_APP, "新增远程终端:%s", clientId.data()); + acgist::RemoteClient* client = new acgist::RemoteClient(this->mediaManager); + client->clientId = clientId; + client->name = name; + this->clients.insert({ clientId, client }); + return 0; +} + +int acgist::Room::closeRemoteClient(const std::string& clientId) { + std::lock_guard lockRoom(roomMutex); + auto client = this->clients.find(clientId); + if(client == this->clients.end()) { + OH_LOG_INFO(LOG_APP, "远程终端已经删除:%s", clientId.data()); + return -1; + } + OH_LOG_INFO(LOG_APP, "删除远程终端:%s", clientId.data()); + delete client->second; + client->second = nullptr; + this->clients->erase(client); + // TODO: 清理consumerIdClientId + return 0; +} + +int acgist::Room::newConsumer(nlohmann::json& body) { + std::lock_guard lockRoom(roomMutex); + mediasoupclient::Consumer* consumer = this->recvTransport->Consume( + this->consumerListener, + body["consumerId"], + body["producerId"], + body["kind"], + &body["rtpParameters"] + ); + std::string kind = body["kind"]; + std::string sourceId = body["sourceId"]; + std::string consumerId = body["consumerId"]; + OH_LOG_INFO(LOG_APP, "新增媒体消费:%s %s %s", kind.data(), sourceId.data(), consumerId.data()); + auto oldClient = this->clients.find(sourceId); + acgist::RemoteClient* client = nullptr; + if(oldClient == this->clients.end()) { + // 假如媒体上来时间比进入房间消息快:基本上不可能出现这种情况 + client = new acgist::RemoteClient(this->mediaManager); + client->clientId = clientId; + client->name = clientId; + this->clients.insert({ clientId, client }); + } else { + client = oldClient->second; + } + client->addConsumer(consumer->GetId(), consumer); + this->consumerIdClientId.insert({ consumer->GetId(), sourceId }); + return 0; +} + +int acgist::Room::closeConsumer(const std::string& consumerId) { + std::lock_guard lockRoom(roomMutex); + auto clientId = this->consumerIdClientId.find(consumerId); + if(clientId == this->consumerIdClientId.end()) { + OH_LOG_INFO(LOG_APP, "关闭消费者无效:%s", consumerId.data()); + return -1; + } + auto client = this->clients.find(clientId->second); + if(client == this->clients.end()) { + OH_LOG_INFO(LOG_APP, "关闭消费者无效:%s %s", consumerId.data(), clientId->second.data()); + return -2; + } + client->second->closeConsumer(consumerId); + return 0; +} + +int acgist::Room::pauseConsumer(const std::string& consumerId) { + std::lock_guard lockRoom(roomMutex); + auto clientId = this->consumerIdClientId.find(consumerId); + if(clientId == this->consumerIdClientId.end()) { + OH_LOG_INFO(LOG_APP, "暂停消费者无效:%s", consumerId.data()); + return -1; + } + auto client = this->clients.find(clientId->second); + if(client == this->clients.end()) { + OH_LOG_INFO(LOG_APP, "暂停消费者无效:%s %s", consumerId.data(), clientId->second.data()); + return -2; + } + client->second->pauseConsumer(consumerId); + return 0; +} + +int acgist::Room::resumeConsumer(const std::string& consumerId) { + std::lock_guard lockRoom(roomMutex); + auto clientId = this->consumerIdClientId.find(consumerId); + if(clientId == this->consumerIdClientId.end()) { + OH_LOG_INFO(LOG_APP, "恢复消费者无效:%s", consumerId.data()); + return -1; + } + auto client = this->clients.find(clientId->second); + if(client == this->clients.end()) { + OH_LOG_INFO(LOG_APP, "恢复消费者无效:%s %s", consumerId.data(), clientId->second.data()); + return -2; + } + client->second->resumeConsumer(consumerId); + return 0; +} + +int acgist::Room::closeProducer(const std::string& producerId) { + std::lock_guard lockRoom(roomMutex); + if(this->audioProducer != nullptr && this->audioProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "关闭音频生产者:%s", producerId.data()); + this->audioProducer->Close(); + delete this->audioProducer; + this->audioProducer == nullptr; + // TODO: 释放 + // this->videoTrack->Dspo + } else if(this->videoProducer != nullptr && this->videoProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "关闭视频生产者:%s", producerId.data()); + this->videoProducer->Close(); + delete this->videoProducer; + this->videoProducer == nullptr; + // TODO: 释放 + // this->videoTrack->Dspo + } else { + return -1; + } + return 0; +} + +int acgist::Room::pauseProducer(const std::string& producerId) { + std::lock_guard lockRoom(roomMutex); + if(this->audioProducer != nullptr && this->audioProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "暂停音频生产者:%s", producerId.data()); + this->audioProducer->Pause(); + } else if(this->videoProducer != nullptr && this->videoProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "暂停视频生产者:%s", producerId.data()); + this->videoProducer->Pause(); + } else { + return -1; + } + return 0; +} + +int acgist::Room::resumeProducer(const std::string& producerId) { + std::lock_guard lockRoom(roomMutex); + if(this->audioProducer != nullptr && this->audioProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "恢复音频生产者:%s", producerId.data()); + this->audioProducer->Resume(); + } else if(this->videoProducer != nullptr && this->videoProducer->GetId() == producerId) { + OH_LOG_INFO(LOG_APP, "恢复视频生产者:%s", producerId.data()); + this->videoProducer->Resume(); + } else { + return -1; + } + return 0; +} + acgist::SendListener::SendListener(Room* room) : room(room) { } diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RoomClient.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RoomClient.cpp index c5f52d5..0353fbd 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RoomClient.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/RoomClient.cpp @@ -3,5 +3,3 @@ acgist::RoomClient::RoomClient(acgist::MediaManager* mediaManager) : acgist::Client(mediaManager) {} acgist::RoomClient::~RoomClient() {} - -bool acgist::RoomClient::release() { return true; } diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/types/libtaoyao/index.d.ts b/taoyao-client-openharmony/taoyao/media/src/main/cpp/types/libtaoyao/index.d.ts index 8b13ba2..9e49598 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/types/libtaoyao/index.d.ts +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/types/libtaoyao/index.d.ts @@ -1,3 +1,4 @@ +export const init : (json: string) => number; export const shutdown : (json: string) => number; export const roomClose : (json: string) => number; export const roomEnter : (json: string) => number; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/ets/entryability/EntryAbility.ts b/taoyao-client-openharmony/taoyao/media/src/main/ets/entryability/EntryAbility.ts index 7bb3d5c..e006e04 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/ets/entryability/EntryAbility.ts +++ b/taoyao-client-openharmony/taoyao/media/src/main/ets/entryability/EntryAbility.ts @@ -1,33 +1,33 @@ -import hilog from '@ohos.hilog'; -import window from '@ohos.window'; -import UIAbility from '@ohos.app.ability.UIAbility'; +import hilog from "@ohos.hilog"; +import window from "@ohos.window"; +import UIAbility from "@ohos.app.ability.UIAbility"; export default class EntryAbility extends UIAbility { onCreate(want, launchParam) { - hilog.info(0x0000, 'EntryAbility', 'onCreate'); + hilog.info(0x0000, "EntryAbility", "onCreate"); } onDestroy() { - hilog.info(0x0000, 'EntryAbility', 'onDestroy'); + hilog.info(0x0000, "EntryAbility", "onDestroy"); } onWindowStageCreate(windowStage: window.WindowStage) { - hilog.info(0x0000, 'EntryAbility', 'onWindowStageCreate'); - windowStage.loadContent('pages/Index', (err, data) => { + hilog.info(0x0000, "EntryAbility", "onWindowStageCreate"); + windowStage.loadContent("pages/Index", (err, data) => { }); } onWindowStageDestroy() { - hilog.info(0x0000, 'EntryAbility', 'onWindowStageDestroy'); + hilog.info(0x0000, "EntryAbility", "onWindowStageDestroy"); } onForeground() { - hilog.info(0x0000, 'EntryAbility', 'onForeground'); + hilog.info(0x0000, "EntryAbility", "onForeground"); } onBackground() { - hilog.info(0x0000, 'EntryAbility', 'onBackground'); + hilog.info(0x0000, "EntryAbility", "onBackground"); } }; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/ets/pages/Index.ets b/taoyao-client-openharmony/taoyao/media/src/main/ets/pages/Index.ets index 86b2498..e41af5d 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/ets/pages/Index.ets +++ b/taoyao-client-openharmony/taoyao/media/src/main/ets/pages/Index.ets @@ -14,7 +14,7 @@ struct Index { signal.connect(); }); } - .width('50%'); + .width("50%"); Column() { Button("断开信令") .fontSize(20) @@ -23,9 +23,9 @@ struct Index { signal.close(); }); } - .width('50%'); + .width("50%"); } - .height('100%'); + .height("100%"); } } diff --git a/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/Setting.ets b/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/Setting.ets index cae4582..e33161c 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/Setting.ets +++ b/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/Setting.ets @@ -5,26 +5,28 @@ */ class Signal { + // 终端名称 - name: string = "鸿蒙"; + name : string = "鸿蒙"; // 终端ID - clientId: string = "harmony"; + clientId : string = "harmony"; // 终端类型 clientType: string = "MOBILE"; // 信令账号 - username: string = "taoyao"; + username : string = "taoyao"; // 信令密码 - password: string = "taoyao"; + password : string = "taoyao"; + }; class Setting { // 信令地址 - signalAddress: string = "wss://192.168.8.204:8888/websocket.signal"; + signalAddress: string = "wss://192.168.1.100:8888/websocket.signal"; // 信令版本 version: string = "1.0.0"; // 信令配置 - signal: Signal = new Signal(); + signal : Signal = new Signal(); }; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/TaoyaoSignal.ets b/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/TaoyaoSignal.ets index a6e373e..91b41c8 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/TaoyaoSignal.ets +++ b/taoyao-client-openharmony/taoyao/media/src/main/ets/taoyao/TaoyaoSignal.ets @@ -1,5 +1,5 @@ /** - * 信令连接 + * 信令 * * @author acgist */ @@ -44,7 +44,6 @@ class TaoyaoSignal { this.socket.close(); } this.connected = false; - hilog.info(0x0000, "TaoyaoSignal", "连接信令:%s", setting.signalAddress); this.socket = webSocket.createWebSocket(); this.socket.on("open", (err: BusinessError, value: Object) => { hilog.info(0x0000, "TaoyaoSignal", "打开信令:%s", setting.signalAddress, value, err); @@ -52,11 +51,12 @@ class TaoyaoSignal { this.connected = true; }); this.socket.on("message", (err: BusinessError, value: string | ArrayBuffer) => { - hilog.debug(0x0000, "TaoyaoSignal", "信令消息:%s", value, err); + const message = value?.toString(); + hilog.debug(0x0000, "TaoyaoSignal", "信令消息:%s", message, err); try { - this.onMessage(value.toString()); + this.onMessage(message); } catch (error) { - hilog.error(0x0000, "TaoyaoSignal", "处理信令消息异常:%s", value, error); + hilog.error(0x0000, "TaoyaoSignal", "处理信令消息异常:%s", message, error); } }); this.socket.on("close", (err: BusinessError, value: Object) => { @@ -67,6 +67,7 @@ class TaoyaoSignal { hilog.error(0x0000, "TaoyaoSignal", "信令异常:%s", setting.signalAddress, err); this.reconnect(); }); + hilog.info(0x0000, "TaoyaoSignal", "连接信令:%s", setting.signalAddress); this.socket.connect(setting.signalAddress, (err: BusinessError, value: boolean) => { hilog.info(0x0000, "TaoyaoSignal", "信令连接成功:%s", setting.signalAddress, value, err); }); @@ -109,15 +110,15 @@ class TaoyaoSignal { "battery" : 100, "charging" : true }); - const body : Record = response.body as Record; - const index : number = body.index as number; + const body = response.body as Record; + const index = body.index as number; this.clientIndex = index; hilog.info(0x0000, "TaoyaoSignal", "信令注册成功:%d", index); this.heartbeat(); } /** - * 心跳 + * 心跳信令 */ heartbeat() { if(this.heartbeatTimer) { @@ -166,7 +167,7 @@ class TaoyaoSignal { "body" : body }; try { - hilog.debug(0x0000, "TaoyaoSignal", "发送消息:%o", message); + hilog.debug(0x0000, "TaoyaoSignal", "发送消息:%o", message); this.socket?.send(JSON.stringify(message)); } catch (error) { hilog.error(0x0000, "TaoyaoSignal", "发送消息异常:%o", message, error); @@ -182,8 +183,8 @@ class TaoyaoSignal { * @returns 响应 */ async request(signal: string, body: Record): Promise> { - const id = this.buildId(); return new Promise>((resolve, reject) => { + const id = this.buildId(); const header: Record = { "v" : setting.version, "id" : id, @@ -224,13 +225,12 @@ class TaoyaoSignal { onMessage(message: string) { const json : Record = JSON.parse(message); const header: Record = json.header as Record; - const body : Record = json.body as Record; const id : number = header.id as number; const signal: string = header.signal as string; if (this.callbackMapping.has(id)) { hilog.debug(0x0000, "TaoyaoSignal", "处理同步消息:%s", message); try { - const callback: Function = this.callbackMapping.get(id) as Function; + const callback = this.callbackMapping.get(id) as Function; if(callback(json)) { return; } @@ -238,21 +238,73 @@ class TaoyaoSignal { this.callbackMapping.delete(id); } } - hilog.debug(0x0000, "TaoyaoSignal", "处理异步消息:%s", message); + let ret: number = 0; switch (signal) { + case "room::close": + ret = taoyaoModule.roomClose(message); + break; + case "room::enter": + ret = taoyaoModule.roomEnter(message); + break; + case "room::expel": + ret = taoyaoModule.roomExpel(message); + break; case "room::invite": - taoyaoModule.roomInvite(message); + ret = taoyaoModule.roomInvite(message); + break; + case "room::leave": + ret = taoyaoModule.roomLeave(message); + break; + case "room::client::list": + ret = taoyaoModule.roomClientList(message); + break; + case "media::consume": + ret = taoyaoModule.mediaConsume(message); + break; + case "media::consumer::close": + ret = taoyaoModule.mediaConsumerClose(message); + break; + case "media::consumer::pause": + ret = taoyaoModule.mediaConsumerPause(message); + break; + case "media::consumer::resume": + ret = taoyaoModule.mediaConsumerResume(message); + break; + case "media::producer::close": + ret = taoyaoModule.mediaProducerClose(message); + break; + case "media::producer::pause": + ret = taoyaoModule.mediaProducerPause(message); + break; + case "media::producer::resume": + ret = taoyaoModule.mediaProducerResume(message); break; default: - hilog.error(0x0000, "TaoyaoSignal", "没有适配信令:%s", signal); + ret = -1; + hilog.warn(0x0000, "TaoyaoSignal", "没有适配信令:%s", signal); break; } + hilog.debug(0x0000, "TaoyaoSignal", "处理异步消息:%d %s", ret, message); } + /** + * 注册发送消息 + * + * @param signal 信令 + * @param body 主体 + */ nativeSend(signal: string, body: string) { this.send(signal, JSON.parse(body)); } + /** + * 注册请求消息 + * + * @param signal 信令 + * @param body 主体 + * + * @returns 响应 + */ async nativeRequest(signal: string, body: string): Promise { const response = await this.request(signal, JSON.parse(body)); return JSON.stringify(response); @@ -262,6 +314,8 @@ class TaoyaoSignal { const signal = new TaoyaoSignal(); +// 加载系统 +taoyaoModule.init(JSON.stringify(setting.signal)); // 注册回调 taoyaoModule.registerSend(signal.nativeSend); taoyaoModule.registerRequest(signal.nativeRequest);