From f9dec2c79fbd35fa7aa22345302b46f5a5030ca2 Mon Sep 17 00:00:00 2001 From: acgist <289547414@qq.com> Date: Tue, 7 May 2024 08:16:38 +0800 Subject: [PATCH] =?UTF-8?q?[*]=20=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- .../taoyao/media/src/main/cpp/webrtc/Room.cpp | 2 +- .../taoyao/media/src/main/cpp/bind.cpp | 57 ++-- .../media/src/main/cpp/include/Client.hpp | 44 ++- .../media/src/main/cpp/include/Palyer.hpp | 21 -- .../media/src/main/cpp/include/Player.hpp | 64 ++++ .../media/src/main/cpp/include/Room.hpp | 240 +++++++++++++- .../media/src/main/cpp/include/Signal.hpp | 36 ++ .../media/src/main/cpp/media/AudioPlayer.cpp | 11 + .../media/src/main/cpp/media/Client.cpp | 6 + .../media/src/main/cpp/media/LocalClient.cpp | 14 + .../media/src/main/cpp/media/MediaManager.cpp | 18 +- .../media/src/main/cpp/media/Player.cpp | 7 + .../media/src/main/cpp/media/RemoteClient.cpp | 7 + .../taoyao/media/src/main/cpp/media/Room.cpp | 307 +++++++++++++++++- .../media/src/main/cpp/media/RoomClient.cpp | 7 + .../media/src/main/cpp/media/VideoEncoder.cpp | 3 +- .../media/src/main/cpp/media/VideoPlayer.cpp | 15 + 18 files changed, 802 insertions(+), 59 deletions(-) delete mode 100644 taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Palyer.hpp create mode 100644 taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp create mode 100644 taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp diff --git a/README.md b/README.md index 06b3160..0e9f21a 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ |:--|:--|:--|:--| |Mediasoup|支持|完成|视频房间(会议模式)| -> 鸿蒙不会实现所有功能,其他功能可以参考`Web`或者`Android`自行实现。 +> 鸿蒙不会实现所有功能,其他功能可以参考`Web`或者`Android`以及鸿蒙官网自行实现。 ### 注意事项 diff --git a/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp b/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp index dd71358..67f32bf 100644 --- a/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp +++ b/taoyao-client-android/taoyao/media/src/main/cpp/webrtc/Room.cpp @@ -106,7 +106,7 @@ namespace acgist { */ std::future OnProduceData(mediasoupclient::SendTransport* transport, const nlohmann::json& sctpStreamParameters, const std::string& label, const std::string& protocol, const nlohmann::json& appData) override { const std::string cTransportId = transport->GetId(); - LOG_I("生产数据:%s - %s - %s -%s", this->room->roomId.data(), cTransportId.data(), label.data(), protocol.data()); + LOG_I("生产数据:%s - %s - %s - %s", this->room->roomId.data(), cTransportId.data(), label.data(), protocol.data()); std::promise promise; return promise.get_future(); } 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 ca5150c..0057f92 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/bind.cpp @@ -14,15 +14,16 @@ #include "mediasoupclient.hpp" #include "./include/Room.hpp" +#include "./include/Signal.hpp" #include "./include/MediaManager.hpp" #include #include -namespace acgist { - static std::mutex roomMutex; +namespace acgist { + // JS环境 static napi_env env = nullptr; // 是否加载 @@ -101,7 +102,7 @@ static napi_value shutdown(napi_env env, napi_callback_info info) { /** * 发送消息 */ -static void send(const std::string& signal, const std::string& body) { +void send(const std::string& signal, const std::string& body) { napi_value ret; napi_value callback = nullptr; napi_get_reference_value(env, acgist::sendRef, &callback); @@ -115,7 +116,7 @@ static void send(const std::string& signal, const std::string& body) { /** * 发送请求 */ -static std::string request(const std::string& signal, const std::string& body) { +std::string request(const std::string& signal, const std::string& body) { napi_value ret; napi_value callback = nullptr; napi_get_reference_value(env, acgist::requestRef, &callback); @@ -132,7 +133,20 @@ static std::string request(const std::string& signal, const std::string& body) { /** * 房间关闭 */ -static napi_value roomClose(napi_env env, napi_callback_info info) { return 0; } +static napi_value roomClose(napi_env env, napi_callback_info info) { + { + std::lock_guard guard(roomMutex); + auto iterator = roomMap.find("roomId"); + if(iterator == roomMap.end()) { + + } else { + delete iterator->second; + iterator->second = nullptr; + roomMap.erase(iterator); + } + } + return 0; +} /** * 进入房间 @@ -153,30 +167,33 @@ static napi_value roomExpel(napi_env env, napi_callback_info info) { return 0; } * 邀请终端进入房间 */ static napi_value roomInvite(napi_env env, napi_callback_info info) { - napi_value ret; size_t argc = 1; napi_value args[1] = { nullptr }; - // TODO: 是否需要释放 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - char chars[2048]; size_t length; - // TODO: 是否需要释放 + 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"]; std::string roomId = body["roomId"]; std::string password = body["password"]; - std::lock_guard guard(roomMutex); - auto iterator = roomMap.find(roomId); - if(iterator == roomMap.end()) { - OH_LOG_INFO(LOG_APP, "进入房间:%s", roomId.c_str()); - auto room = new acgist::Room(roomId, mediaManager); - roomMap[roomId] = room; - int enterRet = room->enter(password); - napi_create_int32(env, enterRet, &ret); - } else { - OH_LOG_INFO(LOG_APP, "已经进入房间:%s", roomId.c_str()); - napi_create_int32(env, -1, &ret); + napi_value ret; + { + std::lock_guard guard(roomMutex); + auto iterator = roomMap.find(roomId); + if(iterator == roomMap.end()) { + OH_LOG_INFO(LOG_APP, "进入房间:%s", roomId.c_str()); + auto room = new acgist::Room(roomId, mediaManager); + roomMap[roomId] = room; + int enterRet = room->enter(password); + if(enterRet == acgist::SUCCESS_CODE) { + room->produceMedia(); + } + napi_create_int32(env, enterRet, &ret); + } else { + OH_LOG_INFO(LOG_APP, "已经进入房间:%s", roomId.c_str()); + napi_create_int32(env, -1, &ret); + } } return ret; } 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 42eabdf..6944b25 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 @@ -10,7 +10,22 @@ namespace acgist { +/** + * 终端 + */ class Client { + +public: + // 媒体管理 + acgist::MediaManager* mediaManager = nullptr; + // 音频轨道 + webrtc::AudioTrackInterface* audioTrack = nullptr; + // 视频轨道 + webrtc::VideoTrackInterface* videoTrack = nullptr; + +public: + Client(acgist::MediaManager* mediaManager); + virtual ~Client(); public: /** @@ -22,18 +37,45 @@ public: }; +/** + * 房间终端 + */ class RoomClient : public Client { public: - acgist::MediaManager* mediaManager; + RoomClient(acgist::MediaManager* mediaManager); + virtual ~RoomClient(); + +public: + virtual bool release() override; }; +/** + * 本地终端 + */ class LocalClient : public RoomClient { + +public: + LocalClient(acgist::MediaManager* mediaManager); + virtual ~LocalClient(); + +public: + virtual bool release() override; }; +/** + * 远程终端 + */ class RemoteClient : public RoomClient { + +public: + RemoteClient(acgist::MediaManager* mediaManager); + virtual ~RemoteClient(); + +public: + virtual bool release() override; }; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Palyer.hpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Palyer.hpp deleted file mode 100644 index 97bc365..0000000 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Palyer.hpp +++ /dev/null @@ -1,21 +0,0 @@ -/** - * 播放器 - * - * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/media/video-playback.md - * 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_H -#define TAOYAO_PALYER_H - -namespace acgist { - -class Player {}; - -class AudioPlayer {}; - -class VideoPlayer {}; - -} - -#endif //TAOYAO_PALYER_H 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 new file mode 100644 index 0000000..3c6bb1f --- /dev/null +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Player.hpp @@ -0,0 +1,64 @@ +/** + * 播放器 + * + * https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/media/video-playback.md + * 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 + +namespace acgist { + +/** + * 播放器 + */ +class Player { + +public: + Player(); + virtual ~Player(); + +public: + // 开始播放 + virtual bool start() = 0; + // 结束播放 + virtual bool stop() = 0; + +}; + +/** + * 音频播放器 + */ +class AudioPlayer: public Player { + +public: + AudioPlayer(); + virtual ~AudioPlayer(); + +public: + virtual bool start() override; + virtual bool stop() override; + +}; + +/** + * 视频播放器 + * + * TODO: 实现留给有缘人了~.~! + */ +class VideoPlayer: public Player { + +public: + VideoPlayer(); + virtual ~VideoPlayer(); + +public: + virtual bool start() override; + virtual bool stop() override; + +}; + +} + +#endif //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 40ffe61..1b0035a 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 @@ -6,29 +6,243 @@ #ifndef taoyao_Room_HPP #define taoyao_Room_HPP +#include #include -#include #include "./Client.hpp" +#include "./Signal.hpp" #include "./MediaManager.hpp" +#include "mediasoupclient.hpp" + namespace acgist { +class Room; + +/** + * 发送通道监听器 + */ +class SendListener : public mediasoupclient::SendTransport::Listener { + +public: + /** + * 房间指针 + */ + Room* room; + +public: + /** + * 发送通道监听器 + * + * @param room 房间指针 + */ + explicit SendListener(Room* room); + /** + * 析构函数 + */ + virtual ~SendListener(); + +public: + /** + * 连接通道 + * + * @param transport 通道指针 + * @param dtlsParameters DTLS参数 + * + * @return future + */ + std::future OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) override; + + /** + * 通道状态改变 + * + * @param transport 通道指针 + * @param connectionState 当前状态 + */ + void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override; + + /** + * 通道生产媒体 + * + * @param transport 通道指针 + * @param kind 媒体类型 + * @param rtpParameters RTP参数 + * @param appData 应用数据 + * + * @return 生产者ID + */ + std::future OnProduce(mediasoupclient::SendTransport* transport, const std::string& kind, nlohmann::json rtpParameters, const nlohmann::json& appData) override; + + /** + * 通道生产数据 + * 注意:需要自己实现 + * + * @param transport 通道指针 + * @param sctpStreamParameters SCTP参数 + * @param label 标记 + * @param protocol 协议 + * @param appData 应用数据 + * + * @return 生产者ID + */ + std::future OnProduceData(mediasoupclient::SendTransport* transport, const nlohmann::json& sctpStreamParameters, const std::string& label, const std::string& protocol, const nlohmann::json& appData) override; + +}; + +/** + * 接收通道监听器 + */ +class RecvListener : public mediasoupclient::RecvTransport::Listener { + +public: + /** + * 房间指针 + */ + Room* room; + +public: + /** + * 接收通道监听器 + * + * @param room 房间指针 + */ + explicit RecvListener(Room* room); + /** + * 析构函数 + */ + virtual ~RecvListener(); + + /** + * 连接通道 + * + * @param transport 通道指针 + * @param dtlsParameters DTLS参数 + * + * @return future + */ + std::future OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) override; + + /** + * 通道状态改变 + * + * @param transport 通道指针 + * @param connectionState 通道状态 + */ + void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override; + +}; + +/** + * 生产者监听器 + */ +class ProducerListener : public mediasoupclient::Producer::Listener { + +public: + /** + * 房间指针 + */ + Room* room; + +public: + /** + * 生产者监听器 + * + * @param room 房间指针 + */ + explicit ProducerListener(Room* room); + /** + * 析构函数 + */ + virtual ~ProducerListener(); + + /** + * 通道关闭 + * + * @param producer 生产者 + */ + void OnTransportClose(mediasoupclient::Producer* producer) override; + +}; + +/** + * 消费者监听器 + */ +class ConsumerListener : public mediasoupclient::Consumer::Listener { + +public: + /** + * 房间指针 + */ + Room* room; + +public: + /** + * 消费者监听器 + * + * @param room 房间指针 + */ + explicit ConsumerListener(Room* room); + /** + * 析构函数 + */ + virtual ~ConsumerListener(); + + /** + * 通道关闭 + * + * @param consumer 消费者 + */ + void OnTransportClose(mediasoupclient::Consumer* consumer) override; + +}; + +/** + * 房间 + */ class Room { public: + // 生产消息:没有实现 + bool dataProduce = false; + // 生产音频 bool audioProduce = true; + // 生产视频 bool videoProduce = true; + // 消费音频 bool audioConsume = true; + // 消费视频 bool videoConsume = true; + // 房间ID std::string roomId = ""; + // 媒体管理 + acgist::MediaManager* mediaManager = nullptr; // 本地终端 acgist::LocalClient* client = nullptr; // 远程终端 - std::vector clients; - // 媒体管理 - acgist::MediaManager* mediaManager = nullptr; - + std::map clients; + // WebRTC配置 + webrtc::PeerConnectionInterface::RTCConfiguration rtcConfiguration; + // 房间Device + mediasoupclient::Device* device = nullptr; + // 发送通道 + mediasoupclient::SendTransport* sendTransport = nullptr; + // 接收通道 + mediasoupclient::RecvTransport* recvTransport = nullptr; + // 发送监听器 + mediasoupclient::SendTransport::Listener* sendListener = nullptr; + // 接收监听器 + mediasoupclient::RecvTransport::Listener* recvListener = nullptr; + // 音频生产者 + mediasoupclient::Producer* audioProducer = nullptr; + // 视频生产者 + mediasoupclient::Producer* videoProducer = nullptr; + // 生产者监听器 + mediasoupclient::Producer::Listener* producerListener = nullptr; + // 消费者监听器 + mediasoupclient::Consumer::Listener* consumerListener = nullptr; + // 消费者列表 + std::map consumers; + public: Room(const std::string& roomId, acgist::MediaManager* mediaManager); virtual ~Room(); @@ -39,10 +253,24 @@ public: * * @param password 密码 * - * @return 是否成功 + * @return 状态 */ int enter(const std::string& password); + /** + * 生成媒体 + * + * @return 状态 + */ + int produceMedia(); + int createSendTransport(); + int createRecvTransport(); + int produceAudio(); + int produceVideo(); int close(); + int closeConsumer(); + int closeAudioProducer(); + int closeVideoProducer(); + int closeTransport(); int newRemoteClient(); }; 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 new file mode 100644 index 0000000..29da80b --- /dev/null +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/include/Signal.hpp @@ -0,0 +1,36 @@ +/** + * 信令 + */ +#ifndef TAOYAO_SIGNAL_HPP +#define TAOYAO_SIGNAL_HPP + +#include + +#include + +namespace acgist { + +// 成功状态编码 +extern const int SUCCESS_CODE = 0; + +/** + * 发送消息 + * + * @param signal 信令 + * @param body 主体 + */ +extern void send(const std::string& signal, const std::string& body); + +/** + * 发送请求 + * + * @param signal 信令 + * @param body 主体 + * + * @return 响应 + */ +extern std::string request(const std::string& signal, const std::string& body); + +} + +#endif //TAOYAO_SIGNAL_HPP diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/AudioPlayer.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/AudioPlayer.cpp index e69de29..daf5ec6 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/AudioPlayer.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/AudioPlayer.cpp @@ -0,0 +1,11 @@ +#include "../include/Player.hpp" + +acgist::AudioPlayer::AudioPlayer() { +} + +acgist::AudioPlayer::~AudioPlayer() { +} + +bool acgist::AudioPlayer::start() { return true; } + +bool acgist::AudioPlayer::stop() { return true; } diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Client.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Client.cpp index e69de29..b1f7384 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Client.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Client.cpp @@ -0,0 +1,6 @@ +#include "../include/Client.hpp" + +acgist::Client::Client(acgist::MediaManager* mediaManager) : mediaManager(mediaManager) { +} + +acgist::Client::~Client() {} 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 e69de29..1c20b11 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 @@ -0,0 +1,14 @@ +#include "../include/Client.hpp" + +acgist::LocalClient::LocalClient(acgist::MediaManager* mediaManager) : acgist::RoomClient(mediaManager) { + this->mediaManager->newLocalClient(); +} + +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 0b47711..ece1e85 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 @@ -1,5 +1,7 @@ #include "../include/MediaManager.hpp" +#include + #include "hilog/log.h" #include "api/create_peerconnection_factory.h" @@ -12,6 +14,8 @@ #include #include +static std::mutex refMutex; + acgist::MediaManager::MediaManager() { } @@ -52,7 +56,17 @@ bool acgist::MediaManager::initPeerConnectionFactory() { } int acgist::MediaManager::newLocalClient() { - this->localClientRef++; + { + std::lock_guard guard(refMutex); + this->localClientRef++; + } +} + +int acgist::MediaManager::releaseLocalClient() { + { + std::lock_guard guard(refMutex); + this->localClientRef--; + } } bool acgist::MediaManager::startCapture() { @@ -71,7 +85,7 @@ bool acgist::MediaManager::startVideoCapture() { rtc::scoped_refptr acgist::MediaManager::getAudioTrack() { cricket::AudioOptions options; - options.highpass_filter = true; + options.highpass_filter = true; options.auto_gain_control = true; options.echo_cancellation = true; options.noise_suppression = true; diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Player.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Player.cpp index e69de29..882154e 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Player.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/Player.cpp @@ -0,0 +1,7 @@ +#include "../include/Player.hpp" + +acgist::Player::Player() { +} + +acgist::Player::~Player() { +} 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 e69de29..8672935 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 @@ -0,0 +1,7 @@ +#include "../include/Client.hpp" + +acgist::RemoteClient::RemoteClient(acgist::MediaManager* mediaManager) : RoomClient(mediaManager) {} + +acgist::RemoteClient::~RemoteClient() {} + +bool acgist::RemoteClient::release() { 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 7c562c7..681f4ee 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 @@ -1,20 +1,317 @@ #include "../include/Room.hpp" -#include "Client.hpp" + +#include + +#include "hilog/log.h" + +static std::mutex roomMutex; acgist::Room::Room(const std::string& roomId, acgist::MediaManager* mediaManager) : roomId(roomId), mediaManager(mediaManager) { - + this->device = new mediasoupclient::Device(); + this->sendListener = new acgist::SendListener(this); + this->recvListener = new acgist::RecvListener(this); + this->producerListener = new acgist::ProducerListener(this); + this->consumerListener = new acgist::ConsumerListener(this); } acgist::Room::~Room() { + this->close(); + // rtcConfiguration + if (this->device != nullptr) { + delete this->device; + this->device = nullptr; + } + if (this->sendListener != nullptr) { + delete this->sendListener; + this->sendListener = nullptr; + } + if (this->sendTransport != nullptr) { + delete this->sendTransport; + this->sendTransport = nullptr; + } + if (this->recvListener != nullptr) { + delete this->recvListener; + this->recvListener = nullptr; + } + if (this->recvTransport != nullptr) { + delete this->recvTransport; + this->recvTransport = nullptr; + } + if (this->audioProducer != nullptr) { + delete this->audioProducer; + this->audioProducer = nullptr; + } + if (this->videoProducer != nullptr) { + delete this->videoProducer; + this->videoProducer = nullptr; + } + if (this->producerListener != nullptr) { + delete this->producerListener; + this->producerListener = nullptr; + } + if (this->consumerListener != nullptr) { + delete this->consumerListener; + this->consumerListener = nullptr; + } if(this->client != nullptr) { - this->client->release(); delete this->client; this->client = nullptr; } } int acgist::Room::enter(const std::string& password) { - this->mediaManager->newLocalClient(); -// this->client = new LocalClient(); + if (this->device->IsLoaded()) { + OH_LOG_WARN(LOG_APP, "Device配置已经加载:%s", this->roomId.data()); + return -1; + } + // 本地终端 + this->client = new acgist::LocalClient(this->mediaManager); + // 房间能力 + nlohmann::json requestBody = { + { "roomId", this->roomId } + }; + std::string response = acgist::request("media::router::rtp::capabilities", requestBody.dump()); + nlohmann::json json = nlohmann::json::parse(response); + nlohmann::json responseBody = json["body"]; + nlohmann::json rtpCapabilities = responseBody["rtpCapabilities"]; + // 加载设备 + // this->rtcConfiguration->set_cpu_adaptation(false); + mediasoupclient::PeerConnection::Options options; + options.config = this->rtcConfiguration; + options.factory = this->mediaManager->peerConnectionFactory.get(); + this->device->Load(rtpCapabilities, &options); + // 进入房间 + requestBody = { + { "roomId", this->roomId }, + { "password", password }, + { "rtpCapabilities", this->device->GetRtpCapabilities().dump() }, + { "sctpCapabilities", this->device->GetSctpCapabilities().dump() } + }; + response = acgist::request("room::enter", requestBody.dump()); + OH_LOG_INFO(LOG_APP, "进入房间:%s", this->roomId.data()); return 0; } + +int acgist::Room::produceMedia() { + OH_LOG_INFO(LOG_APP, "生成媒体:%s", this->roomId.data()); + if(this->audioProduce || this->videoProduce) { + this->createSendTransport(); + } + if(this->audioConsume || this->videoConsume) { + this->createRecvTransport(); + } + if(this->audioProduce) { + this->produceAudio(); + } + if(this->videoProduce) { + this->produceVideo(); + } +} + +int acgist::Room::createSendTransport() { + nlohmann::json requestBody = { + { "roomId", this->roomId }, + { "forceTcp", false }, + { "producing", true }, + { "consuming", false }, + // { "sctpCapabilities", sctpCapabilities }, + }; + std::string response = acgist::request("media::transport::webrtc::create", requestBody.dump()); + nlohmann::json json = nlohmann::json::parse(response); + nlohmann::json responseBody = json["body"]; + mediasoupclient::PeerConnection::Options options; + options.config = this->rtcConfiguration; + options.factory = this->mediaManager->peerConnectionFactory.get(); + this->sendTransport = this->device->CreateSendTransport( + this->sendListener, + responseBody["transportId"], + responseBody["iceParameters"], + responseBody["iceCandidates"], + responseBody["dtlsParameters"], + responseBody["sctpParameters"], + &options + ); + return 0; +} + +int acgist::Room::createRecvTransport() { + nlohmann::json requestBody = { + { "roomId", this->roomId }, + { "forceTcp", false }, + { "producing", false }, + { "consuming", true }, + // { "sctpCapabilities", sctpCapabilities }, + }; + std::string response = acgist::request("media::transport::webrtc::create", requestBody.dump()); + nlohmann::json json = nlohmann::json::parse(response); + nlohmann::json responseBody = json["body"]; + mediasoupclient::PeerConnection::Options options; + options.config = this->rtcConfiguration; + options.factory = this->mediaManager->peerConnectionFactory.get(); + this->recvTransport = this->device->CreateRecvTransport( + this->recvListener, + json["transportId"], + json["iceParameters"], + json["iceCandidates"], + json["dtlsParameters"], + json["sctpParameters"], + &options + ); + return 0; +} + +int acgist::Room::produceAudio() { + return 0; +} + +int acgist::Room::produceVideo() { + return 0; +} + +int acgist::Room::close() { + OH_LOG_INFO(LOG_APP, "关闭房间:%s", this->roomId.data()); + this->closeConsumer(); + this->closeAudioProducer(); + this->closeVideoProducer(); + this->closeTransport(); + return 0; +} + +int acgist::Room::closeConsumer() { + std::lock_guard lockRoom(roomMutex); + for (auto iterator = this->consumers.begin(); iterator != this->consumers.end(); ++iterator) { + if (iterator->second == nullptr) { + continue; + } + OH_LOG_INFO(LOG_APP, "关闭消费者:%s", iterator->second->GetId().data()); + iterator->second->Close(); + delete iterator->second; + iterator->second = nullptr; + } + this->consumers.clear(); + return 0; +} + +int acgist::Room::closeAudioProducer() { + std::lock_guard lockRoom(roomMutex); + if (this->audioProducer != nullptr) { + this->audioProducer->Close(); + } + return 0; +} + +int acgist::Room::closeVideoProducer() { + std::lock_guard lockRoom(roomMutex); + if (this->videoProducer != nullptr) { + this->videoProducer->Close(); + } + return 0; +} + +int acgist::Room::closeTransport() { + std::lock_guard lockRoom(roomMutex); + if (this->sendTransport != nullptr) { + this->sendTransport->Close(); + } + if (this->recvTransport != nullptr) { + this->recvTransport->Close(); + } + return 0; +} + +acgist::SendListener::SendListener(Room* room) : room(room) { +} + +acgist::SendListener::~SendListener() { +} + +std::future acgist::SendListener::OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) { + OH_LOG_INFO(LOG_APP, "连接发送通道:%s - %s", this->room->roomId.data(), transport->GetId().data()); + nlohmann::json requestBody = { + { "roomId", this->roomId }, + { "transportId", transport->GetId() }, + { "dtlsParameters", dtlsParameters }, + }; + std::string response = acgist::send("media::transport::webrtc::connect", requestBody.dump()); + std::promise promise; + promise.set_value(); + return promise.get_future(); +} + +void acgist::SendListener::OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) { + OH_LOG_INFO(LOG_APP, "发送通道状态改变:%s - %s - %s", this->room->roomId.data(), transport->GetId().data(), connectionState.data()); + // TODO: 异常关闭逻辑 +} + +std::future acgist::SendListener::OnProduce(mediasoupclient::SendTransport* transport, const std::string& kind, nlohmann::json rtpParameters, const nlohmann::json& appData) override { + OH_LOG_INFO(LOG_APP, "生产媒体:%s - %s - %s", this->room->roomId.data(), transport->GetId().data(), kind.data()); + nlohmann::json requestBody = { + { "kind", kind }, + { "roomId", this.roomId }, + { "transportId", transport->GetId() }, + { "rtpParameters", rtpParameters }, + }; + std::string response = acgist::request("media::produce", requestBody.dump()); + nlohmann::json json = nlohmann::json::parse(response); + nlohmann::json responseBody = json["body"]; + std::string producerId = responseBody["producerId"]; + std::promise promise; + promise.set_value(producerId); + return promise.get_future(); +} + +std::future acgist::SendListener::OnProduceData(mediasoupclient::SendTransport* transport, const nlohmann::json& sctpStreamParameters, const std::string& label, const std::string& protocol, const nlohmann::json& appData) override; { + OH_LOG_INFO(LOG_APP, "生产数据:%s - %s - %s - %s", this->room->roomId.data(), transport->GetId().data(), label.data(), protocol.data()); + // TODO: 代码实现 + std::promise promise; + // promise.set_value("producerId"); + return promise.get_future(); +} + +acgist::RecvListener::RecvListener(acgist::Room* room) : room(room) { +} + +acgist::RecvListener::~RecvListener() { +} + +std::future acgist::RecvListener::OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) { + OH_LOG_INFO(LOG_APP, "连接接收通道:%s - %s", this->room->roomId.data(), transport->GetId().data()); + nlohmann::json requestBody = { + { "roomId", this->roomId }, + { "transportId", transport->GetId() }, + { "dtlsParameters", dtlsParameters }, + }; + std::string response = acgist::send("media::transport::webrtc::connect", requestBody.dump()); + std::promise promise; + promise.set_value(); + return promise.get_future(); +} + +void acgist::RecvListener::OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) { + OH_LOG_INFO(LOG_APP, "接收通道状态改变:%s - %s - %s", this->room->roomId.data(), transport->GetId().data(), connectionState.data()); + // TODO: 异常关闭逻辑 +} + +acgist::ProducerListener::ProducerListener(acgist::Room* room) : room(room) { +} + +acgist::ProducerListener::~ProducerListener() { +} + +void acgist::ProducerListener::OnTransportClose(mediasoupclient::Producer* producer) { + OH_LOG_INFO(LOG_APP, "生产者通道关闭:%s - %s", this->room->roomId.data(), producer->GetId().data()); + producer->Close(); + // TODO: 异常关闭逻辑 +} + +acgist::ConsumerListener::ConsumerListener(acgist::Room* room) : room(room) { +} + +acgist::ConsumerListener::~ConsumerListener() { +} + +void acgist::ConsumerListener::OnTransportClose(mediasoupclient::Consumer* consumer) { + OH_LOG_INFO(LOG_APP, "消费者通道关闭:%s - %s", this->room->roomId.data(), consumer->GetId().data()); + consumer->Close(); + // TODO: 异常关闭逻辑 +} 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 e69de29..c5f52d5 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 @@ -0,0 +1,7 @@ +#include "../include/Client.hpp" + +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/media/VideoEncoder.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoEncoder.cpp index 42ca9b7..758ff1c 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoEncoder.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoEncoder.cpp @@ -147,13 +147,12 @@ static void OnNewOutputBuffer(OH_AVCodec* codec, uint32_t index, OH_AVBuffer* bu OH_AVErrCode ret = OH_AVBuffer_GetBufferAttr(buffer, &info); char* data = reinterpret_cast(OH_AVBuffer_GetAddr(buffer)); // TODO: 解析 - rtc::scoped_refptr videoFrameBuffer = webrtc::I420Buffer::Copy(width, height, (uint8_t*)data, 0, (uint8_t*)data, 0, (uint8_t*)data, 0); + rtc::scoped_refptr videoFrameBuffer = webrtc::I420Buffer::Copy(width, height, (uint8_t*) data, 0, (uint8_t*) data, 0, (uint8_t*) data, 0); // webrtc::NV12Buffer::Create(width, height); webrtc::VideoFrame::Builder builder; webrtc::VideoFrame videoFrame = builder .set_timestamp_ms(rtc::TimeMillis()) .set_video_frame_buffer(videoFrameBuffer) - .set_rotation(webrtc::VideoRotation::kVideoRotation_0) .build(); for (auto iterator = videoCapturer->map.begin(); iterator != videoCapturer->map.end(); ++iterator) { iterator->second->OnFrame(videoFrame); diff --git a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoPlayer.cpp b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoPlayer.cpp index e69de29..22fed95 100644 --- a/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoPlayer.cpp +++ b/taoyao-client-openharmony/taoyao/media/src/main/cpp/media/VideoPlayer.cpp @@ -0,0 +1,15 @@ +#include "../include/Player.hpp" + +acgist::VideoPlayer::VideoPlayer() { +} + +acgist::VideoPlayer::~VideoPlayer() { +} + +bool acgist::VideoPlayer::start() { + return true; +} + +bool acgist::VideoPlayer::stop() { + return true; +}