[*] 回调

This commit is contained in:
acgist
2023-04-11 08:13:16 +08:00
parent 124b161644
commit 9c31ca4f64
23 changed files with 507 additions and 288 deletions

View File

@@ -25,9 +25,9 @@ android {
}
dependencies {
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
api 'org.apache.commons:commons-lang3:3.12.0'
api 'org.apache.commons:commons-collections4:4.4'
api 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
testImplementation 'junit:junit:4.13.2'
}

View File

@@ -156,16 +156,8 @@ public class Message implements Cloneable, Serializable {
/**
* @return Map消息主体
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public Map<String, Object> body() {
if (this.body instanceof Map) {
return (Map<String, Object>) this.body;
} else if (this.body == null) {
return new HashMap<>();
} else {
Log.w(Message.class.getSimpleName(), "信令主体类型错误:" + this.body);
return new HashMap<>();
}
public <T> T body() {
return (T) this.body;
}
@Override

View File

@@ -32,11 +32,7 @@ dependencies {
implementation project(path: ':boot')
implementation project(path: ':media')
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
}

View File

@@ -147,7 +147,6 @@ public class MainActivity extends AppCompatActivity implements Serializable {
final Resources resources = this.getResources();
MediaManager.getInstance().initContext(
this.mainHandler, this.getApplicationContext(),
resources.getBoolean(R.bool.preview),
resources.getBoolean(R.bool.playAudio),
resources.getBoolean(R.bool.playVideo),
resources.getBoolean(R.bool.audioConsume),
@@ -210,7 +209,7 @@ public class MainActivity extends AppCompatActivity implements Serializable {
private void action(View view) {
this.threadHandler.post(() -> {
// 进入房间
Taoyao.taoyao.roomEnter("d8f1e91c-58d0-4e58-ad67-decc0fd61df2", null);
Taoyao.taoyao.roomEnter("022a16bd-94b9-4d40-889e-d364da065bd2", null);
});
}

View File

@@ -18,8 +18,12 @@ import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import com.acgist.taoyao.boot.model.Message;
import com.acgist.taoyao.client.signal.Taoyao;
import com.acgist.taoyao.media.MediaManager;
import com.acgist.taoyao.media.signal.ITaoyaoListener;
import java.util.Map;
/**
* 媒体服务
@@ -53,6 +57,8 @@ public class MediaService extends Service {
private Taoyao taoyao;
private Handler mainHandler;
private final ITaoyaoListener taoyaoListener = new ITaoyaoListener() {
};
@Override
public void onCreate() {
@@ -154,7 +160,7 @@ public class MediaService extends Service {
port, host, resources.getString(R.string.version),
name, clientId, resources.getString(R.string.clientType), username, password,
resources.getInteger(R.integer.timeout), resources.getString(R.string.encrypt), resources.getString(R.string.encryptSecret),
this.mainHandler, context
this.mainHandler, context, this.taoyaoListener
);
MediaManager.getInstance().initTaoyao(this.taoyao);
Toast.makeText(this.getApplicationContext(), "连接信令", Toast.LENGTH_SHORT).show();

View File

@@ -30,6 +30,7 @@ import com.acgist.taoyao.media.MediaManager;
import com.acgist.taoyao.media.client.Room;
import com.acgist.taoyao.media.client.SessionClient;
import com.acgist.taoyao.media.signal.ITaoyao;
import com.acgist.taoyao.media.signal.ITaoyaoListener;
import org.apache.commons.lang3.ArrayUtils;
@@ -130,6 +131,10 @@ public final class Taoyao implements ITaoyao {
* 服务上下文
*/
private final Context context;
/**
* 信令监听
*/
private final ITaoyaoListener taoyaoListener;
/**
* Wifi管理器
*/
@@ -175,7 +180,7 @@ public final class Taoyao implements ITaoyao {
int port, String host, String version,
String name, String clientId, String clientType, String username, String password,
int timeout, String algo, String secret,
Handler mainHandler, Context context
Handler mainHandler, Context context, ITaoyaoListener taoyaoListener
) {
this.close = false;
this.connect = false;
@@ -193,6 +198,7 @@ public final class Taoyao implements ITaoyao {
this.decrypt = plaintext ? null : this.buildCipher(Cipher.DECRYPT_MODE, algo, secret);
this.mainHandler = mainHandler;
this.context = context;
this.taoyaoListener = taoyaoListener;
this.wifiManager = context.getSystemService(WifiManager.class);
this.powerManager = context.getSystemService(PowerManager.class);
this.batteryManager = context.getSystemService(BatteryManager.class);
@@ -246,6 +252,7 @@ public final class Taoyao implements ITaoyao {
// 开始连接
Log.d(Taoyao.class.getSimpleName(), "连接信令:" + this.host + ":" + this.port);
this.socket = new Socket();
this.taoyaoListener.onConnect();
try {
// 设置读取超时时间:不要设置一直阻塞
// socket.setSoTimeout(this.timeout);
@@ -255,6 +262,7 @@ public final class Taoyao implements ITaoyao {
this.output = this.socket.getOutputStream();
this.clientRegister();
this.connect = true;
this.taoyaoListener.onConnected();
synchronized (this) {
this.notifyAll();
}
@@ -320,6 +328,7 @@ public final class Taoyao implements ITaoyao {
Taoyao.this.on(content);
} catch (Exception e) {
Log.e(Taoyao.class.getSimpleName(), "处理信令异常:" + content, e);
this.taoyaoListener.onError(e);
}
}
}
@@ -407,6 +416,7 @@ public final class Taoyao implements ITaoyao {
if(!this.connect) {
return;
}
this.taoyaoListener.onDisconnect();
Log.d(Taoyao.class.getSimpleName(), "释放信令:" + this.host + ":" + this.port);
this.connect = false;
CloseableUtils.close(this.input);
@@ -497,36 +507,39 @@ public final class Taoyao implements ITaoyao {
}
private void dispatch(final String content, final Header header, final Message message) {
final Map<String, Object> body = message.body();
if(this.taoyaoListener.preOnMessage(message)) {
return;
}
switch (header.getSignal()) {
case "client::config" -> this.clientConfig(message, body);
case "client::register" -> this.clientRegister(message, body);
case "client::reboot" -> this.clientReboot(message, body);
case "client::shutdown" -> this.clientShutdown(message, body);
case "media::consume" -> this.mediaConsume(message, body);
// case "media::audio::volume" -> this.mediaAudioVolume(message, body);
case "media::consumer::close" -> this.mediaConsumerClose(message, body);
case "media::consumer::pause" -> this.mediaConsumerPause(message, body);
// case "media::consumer::request::key::frame" -> this.mediaConsumerRequestKeyFrame(message, body);
case "media::consumer::resume" -> this.mediaConsumerResume(message, body);
// case "media::consumer::set::preferred::layers" -> this.mediaConsumerSetPreferredLayers(message, body);
// case "media::consumer::status" -> this.mediaConsumerStatus(message, body);
case "media::producer::close" -> this.mediaProducerClose(message, body);
case "media::producer::pause" -> this.mediaProducerPause(message, body);
case "media::producer::resume" -> this.mediaProducerResume(message, body);
// case "media::producer::video::orientation:change" -> this.mediaVideoOrientationChange(message, body);
case "room::close" -> this.roomClose(message, body);
case "room::enter" -> this.roomEnter(message, body);
case "room::expel" -> this.roomExpel(message, body);
case "room::invite" -> this.roomInivte(message, body);
case "room::leave" -> this.roomLeave(message, body);
case "session::call" -> this.sessionCall(message, body);
case "session::close" -> this.sessionClose(message, body);
case "session::exchange" -> this.sessionExchange(message, body);
case "session::pause" -> this.sessionPause(message, body);
case "session::resume" -> this.sessionResume(message, body);
case "client::config" -> this.clientConfig(message, message.body());
case "client::register" -> this.clientRegister(message, message.body());
case "client::reboot" -> this.clientReboot(message, message.body());
case "client::shutdown" -> this.clientShutdown(message, message.body());
case "media::consume" -> this.mediaConsume(message, message.body());
// case "media::audio::volume" -> this.mediaAudioVolume(message, message.body());
case "media::consumer::close" -> this.mediaConsumerClose(message, message.body());
case "media::consumer::pause" -> this.mediaConsumerPause(message, message.body());
// case "media::consumer::request::key::frame" -> this.mediaConsumerRequestKeyFrame(message, message.body());
case "media::consumer::resume" -> this.mediaConsumerResume(message, message.body());
// case "media::consumer::set::preferred::layers" -> this.mediaConsumerSetPreferredLayers(message, message.body());
// case "media::consumer::status" -> this.mediaConsumerStatus(message, message.body());
case "media::producer::close" -> this.mediaProducerClose(message, message.body());
case "media::producer::pause" -> this.mediaProducerPause(message, message.body());
case "media::producer::resume" -> this.mediaProducerResume(message, message.body());
// case "media::producer::video::orientation:change" -> this.mediaVideoOrientationChange(message, message.body());
case "room::close" -> this.roomClose(message, message.body());
case "room::enter" -> this.roomEnter(message, message.body());
case "room::expel" -> this.roomExpel(message, message.body());
case "room::invite" -> this.roomInivte(message, message.body());
case "room::leave" -> this.roomLeave(message, message.body());
case "session::call" -> this.sessionCall(message, message.body());
case "session::close" -> this.sessionClose(message, message.body());
case "session::exchange" -> this.sessionExchange(message, message.body());
case "session::pause" -> this.sessionPause(message, message.body());
case "session::resume" -> this.sessionResume(message, message.body());
default -> Log.d(Taoyao.class.getSimpleName(), "没有适配信令:" + content);
}
this.taoyaoListener.postOnMessage(message);
}
/**
@@ -672,6 +685,7 @@ public final class Taoyao implements ITaoyao {
this.name, this.clientId,
key, password,
this, this.mainHandler,
resources.getBoolean(R.bool.preview),
resources.getBoolean(R.bool.dataConsume),
resources.getBoolean(R.bool.audioConsume),
resources.getBoolean(R.bool.videoConsume),

View File

@@ -28,6 +28,7 @@ set(
${SOURCE_DIR}/include/Log.hpp
${SOURCE_DIR}/include/MediaManager.hpp
${SOURCE_DIR}/include/Room.hpp
${SOURCE_DIR}/include/RouterCallback.hpp
${SOURCE_DIR}/include/RtpAudioPublisher.hpp
${SOURCE_DIR}/include/RtpClient.hpp
${SOURCE_DIR}/include/RtpVideoPublisher.hpp
@@ -36,6 +37,7 @@ set(
${SOURCE_DIR}/rtp/RtpVideoPublisher.cpp
${SOURCE_DIR}/webrtc/MediaManager.cpp
${SOURCE_DIR}/webrtc/Room.cpp
${SOURCE_DIR}/webrtc/RouterCallback.cpp
)
set(LIBWEBRTC_BINARY_PATH ${LIBWEBRTC_BINARY_PATH}/${ANDROID_ABI} CACHE STRING "libwebrtc binary path" FORCE)

View File

@@ -53,11 +53,7 @@ android {
}
dependencies {
implementation project(path: ':boot')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
api project(path: ':boot')
api fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.13.2'
}

View File

@@ -6,8 +6,14 @@ namespace acgist {
#define LOG_TAG "libtaoyao"
#define LOG_D(message, ...) acgist::__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, message, __VA_ARGS__)
#define LOG_I(message, ...) acgist::__android_log_print(ANDROID_LOG_INFO, LOG_TAG, message, __VA_ARGS__)
#define LOG_W(message, ...) acgist::__android_log_print(ANDROID_LOG_WARN, LOG_TAG, message, __VA_ARGS__)
#define LOG_E(message, ...) acgist::__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, message, __VA_ARGS__)
#define LOG_D(format, ...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s " format, __func__, ##__VA_ARGS__)
#define LOG_I(format, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s " format, __func__, ##__VA_ARGS__)
#define LOG_W(format, ...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s " format, __func__, ##__VA_ARGS__)
#define LOG_E(format, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s " format, __func__, ##__VA_ARGS__)
//#define LOG_D(...) acgist::__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
//#define LOG_I(...) acgist::__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
//#define LOG_W(...) acgist::__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
//#define LOG_E(...) acgist::__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
}

View File

@@ -1,14 +1,9 @@
#pragma once
#include <map>
#include <iostream>
#include "jni.h"
#include "Log.hpp"
#include "mediasoupclient.hpp"
namespace acgist {
jmethodID closeCallback;
}

View File

@@ -1,44 +1,39 @@
#pragma once
#include <map>
#include <string>
#include <iostream>
#include "jni.h"
#include "sdk/android/src/jni/pc/peer_connection.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
#include "Log.hpp"
#include "mediasoupclient.hpp"
#include "RouterCallback.hpp"
namespace acgist {
class Room {
class Room : public RouterCallback {
public:
std::string roomId;
mediasoupclient::Device *device;
mediasoupclient::PeerConnection *peerConnection;
mediasoupclient::SendTransport *sendTransport;
mediasoupclient::RecvTransport *recvTransport;
mediasoupclient::SendTransport::Listener *sendListener;
mediasoupclient::RecvTransport::Listener *recvListener;
mediasoupclient::Producer *audioProducer;
mediasoupclient::Producer *videoProducer;
mediasoupclient::Producer::Listener *producerListener;
mediasoupclient::Consumer::Listener *consumerListener;
mediasoupclient::Device* device;
mediasoupclient::PeerConnection* peerConnection;
mediasoupclient::SendTransport* sendTransport;
mediasoupclient::RecvTransport* recvTransport;
mediasoupclient::SendTransport::Listener* sendListener;
mediasoupclient::RecvTransport::Listener* recvListener;
mediasoupclient::Producer* audioProducer;
mediasoupclient::Producer* videoProducer;
mediasoupclient::Producer::Listener* producerListener;
mediasoupclient::Consumer::Listener* consumerListener;
std::map<std::string, mediasoupclient::Consumer*> consumers;
public:
JNIEnv *env;
jobject routerCallback;
public:
Room(std::string roomId, JNIEnv *env, jobject routerCallback);
Room(std::string roomId, JNIEnv* env, jobject routerCallback);
virtual ~Room();
public:
void enter(std::string rtpCapabilities, webrtc::PeerConnectionFactoryInterface *factory, webrtc::PeerConnectionInterface::RTCConfiguration &rtcConfiguration);
void enter(std::string rtpCapabilities, webrtc::PeerConnectionFactoryInterface* factory, webrtc::PeerConnectionInterface::RTCConfiguration& rtcConfiguration);
void createSendTransport(std::string body);
void createRecvTransport(std::string body);
void mediaProduceAudio(webrtc::MediaStreamInterface *mediaStream);
void mediaProduceVideo(webrtc::MediaStreamInterface *mediaStream);
void mediaProduceAudio(webrtc::MediaStreamInterface* mediaStream);
void mediaProduceVideo(webrtc::MediaStreamInterface* mediaStream);
void mediaConsume(std::string message);
void mediaProducerPause(std::string producerId);
void mediaProducerResume(std::string producerId);

View File

@@ -0,0 +1,29 @@
#pragma once
#include <string>
#include "jni.h"
#include "mediasoupclient.hpp"
namespace acgist {
class RouterCallback {
public:
JNIEnv* env;
jobject routerCallback;
public:
void enterCallback(std::string rtpCapabilities, std::string sctpCapabilities);
void sendTransportConnectCallback(std::string transportId, std::string dtlsParameters);
std::string sendTransportProduceCallback(std::string kind, std::string transportId, std::string rtpParameters);
void recvTransportConnectCallback(std::string transportId, std::string dtlsParameters);
void producerNewCallback(std::string kind, std::string producerId, webrtc::MediaStreamTrackInterface* producerMediaTrackPointer);
void producerPauseCallback(std::string producerId);
void producerResumeCallback(std::string producerId);
void producerCloseCallback(std::string producerId);
void consumerNewCallback(std::string message, webrtc::MediaStreamTrackInterface* consumerMediaTrackPointer);
void consumerPauseCallback(std::string consumerId);
void consumerResumeCallback(std::string consumerId);
void consumerCloseCallback(std::string consumerId);
};
}

View File

@@ -1,11 +1,11 @@
#include "Room.hpp"
#include "MediaManager.hpp"
namespace acgist {
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_MediaManager_nativeInit(JNIEnv *env, jobject me) {
LOG_I("加载MediasoupClient", mediasoupclient::Version().data());
Java_com_acgist_taoyao_media_MediaManager_nativeInit(JNIEnv* env, jobject me) {
std::string version = mediasoupclient::Version();
LOG_I("加载MediasoupClient", version.data());
mediasoupclient::Initialize();
// => { spatialLayers: 2, temporalLayers: 3 }
// mediasoupclient::parseScalabilityMode("L2T3");
@@ -14,8 +14,8 @@ namespace acgist {
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_MediaManager_nativeStop(JNIEnv *env, jobject me) {
std::cout << "释放mediasoupclient" << std::endl;
Java_com_acgist_taoyao_media_MediaManager_nativeStop(JNIEnv* env, jobject me) {
LOG_I("释放mediasoupclient");
mediasoupclient::Cleanup();
}

View File

@@ -5,77 +5,38 @@ namespace acgist {
class SendListener : public mediasoupclient::SendTransport::Listener {
public:
Room *room;
JNIEnv *env;
jobject routerCallback;
Room* room;
public:
SendListener(Room *room, JNIEnv *env, jobject routerCallback) {
SendListener(Room* room) {
this->room = room;
this->env = env;
this->routerCallback = routerCallback;
}
virtual ~SendListener() {
}
public:
std::future<void> OnConnect(mediasoupclient::Transport *transport, const nlohmann::json &dtlsParameters) override {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID sendTransportConnectCallback = this->env->GetMethodID(jCallbackClazz, "sendTransportConnectCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char *cTransportId = transport->GetId().data();
jstring jTransportId = this->env->NewStringUTF(cTransportId);
const char *cDtlsParameters = dtlsParameters.dump().data();
jstring jDtlsParameters = this->env->NewStringUTF(cDtlsParameters);
this->env->CallVoidMethod(
this->routerCallback,
sendTransportConnectCallback,
jTransportId,
jDtlsParameters
);
this->env->DeleteLocalRef(jTransportId);
this->env->ReleaseStringUTFChars(jTransportId, cTransportId);
this->env->DeleteLocalRef(jDtlsParameters);
this->env->ReleaseStringUTFChars(jDtlsParameters, cDtlsParameters);
this->env->DeleteLocalRef(jCallbackClazz);
std::future<void> OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) override {
const std::string cTransportId = transport->GetId();
const std::string cDtlsParameters = dtlsParameters.dump();
this->room->sendTransportConnectCallback(cTransportId, cDtlsParameters);
return std::future<void>();
}
void OnConnectionStateChange(mediasoupclient::Transport *transport, const std::string &connectionState) override {
void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override {
// 状态变化
}
std::future<std::string> OnProduce(mediasoupclient::SendTransport *transport, const std::string &kind, nlohmann::json rtpParameters, const nlohmann::json &appData) override {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID sendTransportProduceCallback = this->env->GetMethodID(jCallbackClazz, "sendTransportProduceCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char *cKind = kind.data();
jstring jKind = this-> env->NewStringUTF(cKind);
const char *cTransportId = transport->GetId().data();
jstring jTransportId = this-> env->NewStringUTF(cTransportId);
const char *cRtpParameters = rtpParameters.dump().data();
jstring jRtpParameters = this-> env->NewStringUTF(cRtpParameters);
std::promise<std::string> promise;
jstring jResult = (jstring) this->env->CallObjectMethod(
this->routerCallback,
sendTransportProduceCallback,
jKind,
jTransportId,
jRtpParameters
);
const char *cResult = this-> env->GetStringUTFChars(jResult, 0);
std::string result(cResult);
std::future<std::string> OnProduce(mediasoupclient::SendTransport* transport, const std::string& kind, nlohmann::json rtpParameters, const nlohmann::json& appData) override {
const std::string cTransportId = transport->GetId();
const std::string cRtpParameters = rtpParameters.dump();
std::string result = this->room->sendTransportProduceCallback(kind, cTransportId, cRtpParameters);
std::promise <std::string> promise;
promise.set_value(result);
this-> env->DeleteLocalRef(jResult);
this-> env->DeleteLocalRef(jKind);
this-> env->ReleaseStringUTFChars(jKind, cKind);
this-> env->DeleteLocalRef(jResult);
this-> env->ReleaseStringUTFChars(jResult, cResult);
this-> env->DeleteLocalRef(jTransportId);
this-> env->ReleaseStringUTFChars(jTransportId, cTransportId);
this-> env->DeleteLocalRef(jRtpParameters);
this-> env->ReleaseStringUTFChars(jRtpParameters, cRtpParameters);
this-> env->DeleteLocalRef(jCallbackClazz);
return promise.get_future();
}
std::future<std::string> OnProduceData(mediasoupclient::SendTransport *transport, const nlohmann::json &sctpStreamParameters, const std::string &label, const std::string &protocol, const nlohmann::json &appData) override {
std::future<std::string> OnProduceData(mediasoupclient::SendTransport* transport, const nlohmann::json& sctpStreamParameters, const std::string& label, const std::string& protocol, const nlohmann::json& appData) override {
// 数据生产
return std::future<std::string>();
}
@@ -85,39 +46,24 @@ namespace acgist {
class RecvListener : public mediasoupclient::RecvTransport::Listener {
public:
Room *room;
JNIEnv *env;
jobject routerCallback;
Room* room;
public:
RecvListener(Room *room, JNIEnv *env, jobject routerCallback) {
RecvListener(Room* room) {
this->room = room;
this->env = env;
this->routerCallback = routerCallback;
}
std::future<void> OnConnect(mediasoupclient::Transport *transport, const nlohmann::json &dtlsParameters) override {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID recvTransportConnectCallback = this->env->GetMethodID(jCallbackClazz, "recvTransportConnectCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char *cTransportId = transport->GetId().data();
jstring jTransportId = this-> env->NewStringUTF(cTransportId);
const char *cDtlsParameters = dtlsParameters.dump().data();
jstring jDtlsParameters = this-> env->NewStringUTF(cDtlsParameters);
this->env->CallVoidMethod(
this->routerCallback,
recvTransportConnectCallback,
jTransportId,
jDtlsParameters
);
this-> env->DeleteLocalRef(jTransportId);
this-> env->ReleaseStringUTFChars(jTransportId, cTransportId);
this-> env->DeleteLocalRef(jDtlsParameters);
this-> env->ReleaseStringUTFChars(jDtlsParameters, cDtlsParameters);
this-> env->DeleteLocalRef(jCallbackClazz);
virtual ~RecvListener() {
}
std::future<void> OnConnect(mediasoupclient::Transport* transport, const nlohmann::json& dtlsParameters) override {
const std::string cTransportId = transport->GetId();
const std::string cDtlsParameters = dtlsParameters.dump();
this->room->recvTransportConnectCallback(cTransportId, cDtlsParameters);
return std::future<void>();
}
void OnConnectionStateChange(mediasoupclient::Transport *transport, const std::string &connectionState) override {
void OnConnectionStateChange(mediasoupclient::Transport* transport, const std::string& connectionState) override {
// 状态变化
}
@@ -126,18 +72,17 @@ namespace acgist {
class ProducerListener : public mediasoupclient::Producer::Listener {
public:
Room *room;
JNIEnv *env;
jobject routerCallback;
Room* room;
public:
ProducerListener(Room *room, JNIEnv *env, jobject routerCallback) {
ProducerListener(Room* room) {
this->room = room;
this->env = env;
this->routerCallback = routerCallback;
}
void OnTransportClose(mediasoupclient::Producer *producer) override {
virtual ~ProducerListener() {
}
void OnTransportClose(mediasoupclient::Producer* producer) override {
}
@@ -146,18 +91,17 @@ namespace acgist {
class ConsumerListener : public mediasoupclient::Consumer::Listener {
public:
Room *room;
JNIEnv *env;
jobject routerCallback;
Room* room;
public:
ConsumerListener(Room *room, JNIEnv *env, jobject routerCallback) {
ConsumerListener(Room* room) {
this->room = room;
this->env = env;
this->routerCallback = routerCallback;
}
void OnTransportClose(mediasoupclient::Consumer *consumer) override {
virtual ~ConsumerListener() {
}
void OnTransportClose(mediasoupclient::Consumer* consumer) override {
}
@@ -165,17 +109,17 @@ namespace acgist {
Room::Room(
std::string roomId,
JNIEnv *env,
JNIEnv* env,
jobject routerCallback
) {
this->roomId = roomId;
this->env = env;
this->routerCallback = routerCallback;
this->device = new mediasoupclient::Device();
this->sendListener = new SendListener(this, env, routerCallback);
this->recvListener = new RecvListener(this, env, routerCallback);
this->producerListener = new ProducerListener(this, env, routerCallback);
this->consumerListener = new ConsumerListener(this, env, routerCallback);
this->sendListener = new SendListener(this);
this->recvListener = new RecvListener(this);
this->producerListener = new ProducerListener(this);
this->consumerListener = new ConsumerListener(this);
}
Room::~Room() {
@@ -188,22 +132,25 @@ namespace acgist {
delete this->videoProducer;
delete this->producerListener;
delete this->consumerListener;
this-> env->DeleteLocalRef(this->routerCallback);
this-> env->DeleteGlobalRef(this->routerCallback);
this->env->DeleteLocalRef(this->routerCallback);
this->env->DeleteGlobalRef(this->routerCallback);
}
void Room::enter(
std::string rtpCapabilities,
webrtc::PeerConnectionFactoryInterface *factory,
webrtc::PeerConnectionInterface::RTCConfiguration &rtcConfiguration
webrtc::PeerConnectionFactoryInterface* factory,
webrtc::PeerConnectionInterface::RTCConfiguration& rtcConfiguration
) {
nlohmann::json json;
// TODO全局
mediasoupclient::PeerConnection::Options options;
options.config = rtcConfiguration;
options.config = rtcConfiguration;
options.factory = factory;
json["routerRtpCapabilities"] = nlohmann::json::parse(rtpCapabilities);
this->device->Load(json, &options);
const std::string cRtpCapabilities = this->device->GetRtpCapabilities().dump();
const std::string cSctpCapabilities = this->device->GetSctpCapabilities().dump();
this->enterCallback(cRtpCapabilities, cSctpCapabilities);
}
void Room::createSendTransport(std::string body) {
@@ -232,7 +179,7 @@ namespace acgist {
);
}
void Room::mediaProduceAudio(webrtc::MediaStreamInterface *mediaStream) {
void Room::mediaProduceAudio(webrtc::MediaStreamInterface* mediaStream) {
if(!this->device->CanProduce("audio")) {
return;
}
@@ -250,7 +197,7 @@ namespace acgist {
);
}
void Room::mediaProduceVideo(webrtc::MediaStreamInterface *mediaStream) {
void Room::mediaProduceVideo(webrtc::MediaStreamInterface* mediaStream) {
if(this->device->CanProduce("video")) {
return;
}
@@ -288,7 +235,7 @@ namespace acgist {
void Room::mediaConsume(std::string message) {
nlohmann::json json = nlohmann::json::parse(message);
nlohmann::json body = json["body"];
mediasoupclient::Consumer *consumer = this->recvTransport->Consume(
mediasoupclient::Consumer* consumer = this->recvTransport->Consume(
this->consumerListener,
body["consumerId"],
body["producerId"],
@@ -297,23 +244,28 @@ namespace acgist {
);
this->consumers.insert({ consumer->GetId(), consumer });
webrtc::MediaStreamTrackInterface* trackPointer = consumer->GetTrack();
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID consumerNewCallback = this->env->GetMethodID(jCallbackClazz, "consumerNewCallback", "(Ljava/lang/String;J;)V");
const char *cMessage = message.data();
jstring jMessage = this-> env->NewStringUTF(cMessage);
this->env->CallVoidMethod(
this->routerCallback,
consumerNewCallback,
jMessage,
(jlong) trackPointer
);
this-> env->DeleteLocalRef(jMessage);
this-> env->ReleaseStringUTFChars(jMessage, cMessage);
this-> env->DeleteLocalRef(jCallbackClazz);
this->consumerNewCallback(message, trackPointer);
};
void Room::mediaProducerPause(std::string producerId) {
}
void Room::mediaProducerResume(std::string producerId) {
}
void Room::mediaProducerClose(std::string producerId) {
}
void Room::mediaConsumerPause(std::string consumerId) {
}
void Room::mediaConsumerResume(std::string consumerId) {
}
void Room::mediaConsumerClose(std::string consumerId) {
}
void Room::close() {
delete this->device;
}
extern "C" JNIEXPORT void JNICALL
@@ -327,123 +279,130 @@ namespace acgist {
// TODO为什么不能转换测试是否因为stun配置问题
webrtc::JavaParamRef<jobject> jRtcConfigurationRef(jRtcConfiguration);
// webrtc::jni::JavaToNativeMediaConstraints()
webrtc::jni::JavaToNativeRTCConfiguration(env, jRtcConfigurationRef, &rtcConfiguration);
const char* rtpCapabilities = env->GetStringUTFChars(jRtpCapabilities, 0);
// webrtc::jni::JavaToNativeRTCConfiguration(env, jRtcConfigurationRef, &rtcConfiguration);
const char* rtpCapabilities = env->GetStringUTFChars(jRtpCapabilities, nullptr);
room->enter(
rtpCapabilities,
reinterpret_cast<webrtc::PeerConnectionFactoryInterface*>(factoryPointer),
// (webrtc::PeerConnectionFactoryInterface*) factoryPointer,
rtcConfiguration
);
env->ReleaseStringUTFChars(jRtpCapabilities, rtpCapabilities);
env->DeleteLocalRef(jRtpCapabilities);
env->ReleaseStringUTFChars(jRtpCapabilities, rtpCapabilities);
env->DeleteLocalRef(jRtcConfiguration);
// delete rtpCapabilities;
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeNewRoom(
JNIEnv *env, jobject me,
JNIEnv* env, jobject me,
jstring jRoomId, jobject jRouterCallback
) {
const char* roomId = env->GetStringUTFChars(jRoomId, 0);
jobject routerCallback = env->NewGlobalRef(jRouterCallback);
const char* roomId = env->GetStringUTFChars(jRoomId, nullptr);
Room* room = new Room(roomId, env, routerCallback);
env->DeleteLocalRef(jRoomId);
env->ReleaseStringUTFChars(jRoomId, roomId);
return (jlong) room;
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeCloseRoom(JNIEnv *env, jobject me, jlong nativeRoomPointer) {
Java_com_acgist_taoyao_media_client_Room_nativeCloseRoom(JNIEnv* env, jobject me, jlong nativeRoomPointer) {
Room* room = (Room*) nativeRoomPointer;
room->close();
delete room;
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeCreateSendTransport(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jBody) {
Java_com_acgist_taoyao_media_client_Room_nativeCreateSendTransport(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jBody) {
Room* room = (Room*) nativeRoomPointer;
const char* body = env->GetStringUTFChars(jBody, 0);
const char* body = env->GetStringUTFChars(jBody, nullptr);
room->createSendTransport(body);
env->DeleteLocalRef(jBody);
env->ReleaseStringUTFChars(jBody, body);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeCreateRecvTransport(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jBody) {
Java_com_acgist_taoyao_media_client_Room_nativeCreateRecvTransport(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jBody) {
Room* room = (Room*) nativeRoomPointer;
const char* body = env->GetStringUTFChars(jBody, 0);
const char* body = env->GetStringUTFChars(jBody, nullptr);
room->createRecvTransport(body);
env->DeleteLocalRef(jBody);
env->ReleaseStringUTFChars(jBody, body);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaProduceAudio(JNIEnv *env, jobject me, jlong nativeRoomPointer, jlong mediaStreamPointer) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaProduceAudio(JNIEnv* env, jobject me, jlong nativeRoomPointer, jlong mediaStreamPointer) {
Room* room = (Room*) nativeRoomPointer;
webrtc::MediaStreamInterface *mediaStream = reinterpret_cast<webrtc::MediaStreamInterface*>(mediaStreamPointer);
webrtc::MediaStreamInterface* mediaStream = reinterpret_cast<webrtc::MediaStreamInterface*>(mediaStreamPointer);
room->mediaProduceAudio(mediaStream);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaProduceVideo(JNIEnv *env, jobject me, jlong nativeRoomPointer, jlong mediaStreamPointer) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaProduceVideo(JNIEnv* env, jobject me, jlong nativeRoomPointer, jlong mediaStreamPointer) {
Room* room = (Room*) nativeRoomPointer;
webrtc::MediaStreamInterface *mediaStream = reinterpret_cast<webrtc::MediaStreamInterface*>(mediaStreamPointer);
webrtc::MediaStreamInterface* mediaStream = reinterpret_cast<webrtc::MediaStreamInterface*>(mediaStreamPointer);
room->mediaProduceVideo(mediaStream);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsume(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jMessage) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsume(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jMessage) {
Room* room = (Room*) nativeRoomPointer;
const char *message = env->GetStringUTFChars(jMessage, 0);
const char* message = env->GetStringUTFChars(jMessage, nullptr);
room->mediaConsume(message);
env->DeleteLocalRef(jMessage);
env->ReleaseStringUTFChars(jMessage, message);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerPause(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerPause(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Room* room = (Room*) nativeRoomPointer;
const char *producerId = env->GetStringUTFChars(jProducerId, 0);
const char* producerId = env->GetStringUTFChars(jProducerId, nullptr);
room->mediaProducerPause(producerId);
env->DeleteLocalRef(jProducerId);
env->ReleaseStringUTFChars(jProducerId, producerId);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerResume(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerResume(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Room* room = (Room*) nativeRoomPointer;
const char *producerId = env->GetStringUTFChars(jProducerId, 0);
const char* producerId = env->GetStringUTFChars(jProducerId, nullptr);
room->mediaProducerResume(producerId);
env->DeleteLocalRef(jProducerId);
env->ReleaseStringUTFChars(jProducerId, producerId);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerClose(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaProducerClose(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jProducerId) {
Room* room = (Room*) nativeRoomPointer;
const char *producerId = env->GetStringUTFChars(jProducerId, 0);
const char* producerId = env->GetStringUTFChars(jProducerId, nullptr);
room->mediaProducerClose(producerId);
env->DeleteLocalRef(jProducerId);
env->ReleaseStringUTFChars(jProducerId, producerId);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerPause(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerPause(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Room* room = (Room*) nativeRoomPointer;
const char *consumerId = env->GetStringUTFChars(jConsumerId, 0);
const char* consumerId = env->GetStringUTFChars(jConsumerId, nullptr);
room->mediaConsumerPause(consumerId);
env->DeleteLocalRef(jConsumerId);
env->ReleaseStringUTFChars(jConsumerId, consumerId);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerResume(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerResume(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Room* room = (Room*) nativeRoomPointer;
const char *consumerId = env->GetStringUTFChars(jConsumerId, 0);
const char* consumerId = env->GetStringUTFChars(jConsumerId, nullptr);
room->mediaConsumerResume(consumerId);
env->DeleteLocalRef(jConsumerId);
env->ReleaseStringUTFChars(jConsumerId, consumerId);
}
extern "C" JNIEXPORT void JNICALL
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerClose(JNIEnv *env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Java_com_acgist_taoyao_media_client_Room_nativeMediaConsumerClose(JNIEnv* env, jobject me, jlong nativeRoomPointer, jstring jConsumerId) {
Room* room = (Room*) nativeRoomPointer;
const char *consumerId = env->GetStringUTFChars(jConsumerId, 0);
const char* consumerId = env->GetStringUTFChars(jConsumerId, nullptr);
room->mediaConsumerClose(consumerId);
env->DeleteLocalRef(jConsumerId);
env->ReleaseStringUTFChars(jConsumerId, consumerId);
}

View File

@@ -0,0 +1,100 @@
#include "RouterCallback.hpp"
namespace acgist {
void RouterCallback::enterCallback(std::string rtpCapabilities, std::string sctpCapabilities) {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID recvTransportConnectCallback = this->env->GetMethodID(jCallbackClazz, "enterCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char* cRtpCapabilities = rtpCapabilities.data();
const char* cSctpCapabilities = sctpCapabilities.data();
jstring jRtpCapabilities = this->env->NewStringUTF(cRtpCapabilities);
jstring jScrpCapabilities = this->env->NewStringUTF(cSctpCapabilities);
this->env->CallVoidMethod(
this->routerCallback,
recvTransportConnectCallback,
jRtpCapabilities,
jScrpCapabilities
);
this->env->DeleteLocalRef(jRtpCapabilities);
this->env->DeleteLocalRef(jScrpCapabilities);
this->env->DeleteLocalRef(jCallbackClazz);
}
void RouterCallback::sendTransportConnectCallback(std::string transportId, std::string dtlsParameters) {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID sendTransportConnectCallback = this->env->GetMethodID(jCallbackClazz, "sendTransportConnectCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char* cTransportId = transportId.data();
const char* cDtlsParameters = dtlsParameters.data();
jstring jTransportId = this->env->NewStringUTF(cTransportId);
jstring jDtlsParameters = this->env->NewStringUTF(cDtlsParameters);
this->env->CallVoidMethod(
this->routerCallback,
sendTransportConnectCallback,
jTransportId,
jDtlsParameters
);
this->env->DeleteLocalRef(jTransportId);
this->env->DeleteLocalRef(jDtlsParameters);
this->env->DeleteLocalRef(jCallbackClazz);
}
std::string RouterCallback::sendTransportProduceCallback(std::string kind, std::string transportId, std::string rtpParameters) {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID sendTransportProduceCallback = this->env->GetMethodID(jCallbackClazz, "sendTransportProduceCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char* cKind = kind.data();
const char* cTransportId = transportId.data();
const char* cRtpParameters = rtpParameters.data();
jstring jKind = this->env->NewStringUTF(cKind);
jstring jTransportId = this->env->NewStringUTF(cTransportId);
jstring jRtpParameters = this->env->NewStringUTF(cRtpParameters);
jstring jResult = (jstring) this->env->CallObjectMethod(
this->routerCallback,
sendTransportProduceCallback,
jKind,
jTransportId,
jRtpParameters
);
const char* result = this->env->GetStringUTFChars(jResult, nullptr);
this->env->DeleteLocalRef(jResult);
this->env->ReleaseStringUTFChars(jResult, result);
this->env->DeleteLocalRef(jKind);
this->env->DeleteLocalRef(jTransportId);
this->env->DeleteLocalRef(jRtpParameters);
this->env->DeleteLocalRef(jCallbackClazz);
return result;
}
void RouterCallback::recvTransportConnectCallback(std::string transportId, std::string dtlsParameters) {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID recvTransportConnectCallback = this->env->GetMethodID(jCallbackClazz, "recvTransportConnectCallback", "(Ljava/lang/String;Ljava/lang/String;)V");
const char* cTransportId = transportId.data();
const char* cDtlsParameters = dtlsParameters.data();
jstring jTransportId = this->env->NewStringUTF(cTransportId);
jstring jDtlsParameters = this->env->NewStringUTF(cDtlsParameters);
this->env->CallVoidMethod(
this->routerCallback,
recvTransportConnectCallback,
jTransportId,
jDtlsParameters
);
this->env->DeleteLocalRef(jTransportId);
this->env->DeleteLocalRef(jDtlsParameters);
this->env->DeleteLocalRef(jCallbackClazz);
}
void RouterCallback::consumerNewCallback(std::string message, webrtc::MediaStreamTrackInterface* consumerMediaTrackPointer) {
jclass jCallbackClazz = this->env->GetObjectClass(this->routerCallback);
jmethodID consumerNewCallback = this->env->GetMethodID(jCallbackClazz, "consumerNewCallback", "(Ljava/lang/String;J;)V");
const char* cMessage = message.data();
jstring jMessage = this->env->NewStringUTF(cMessage);
this->env->CallVoidMethod(
this->routerCallback,
consumerNewCallback,
jMessage,
(jlong) consumerMediaTrackPointer
);
this->env->DeleteLocalRef(jMessage);
this->env->DeleteLocalRef(jCallbackClazz);
}
}

View File

@@ -106,10 +106,6 @@ public final class MediaManager {
* 当前终端数量
*/
private volatile int clientCount;
/**
* 是否预览视频
*/
private boolean preview;
/**
* 是否打开音频播放
*/
@@ -166,10 +162,13 @@ public final class MediaManager {
* 媒体流:声音、视频
*/
private MediaStream mediaStream;
private AudioSource audioSource;
private VideoSource videoSource;
/**
* 视频捕获
*/
private VideoCapturer videoCapturer;
private SurfaceTextureHelper surfaceTextureHelper;
/**
* PeerConnectionFactory
*/
@@ -190,14 +189,14 @@ public final class MediaManager {
for (MediaCodecInfo mediaCodecInfo : mediaCodecList.getCodecInfos()) {
// if (mediaCodecInfo.isEncoder()) {
final String[] supportedTypes = mediaCodecInfo.getSupportedTypes();
Log.d(RecordClient.class.getSimpleName(), "编码器名称:" + mediaCodecInfo.getName());
Log.d(RecordClient.class.getSimpleName(), "编码器类型:" + String.join(" , ", supportedTypes));
Log.d(MediaManager.class.getSimpleName(), "编码器名称:" + mediaCodecInfo.getName());
Log.d(MediaManager.class.getSimpleName(), "编码器类型:" + String.join(" , ", supportedTypes));
for (String supportType : supportedTypes) {
final MediaCodecInfo.CodecCapabilities codecCapabilities = mediaCodecInfo.getCapabilitiesForType(supportType);
final int[] colorFormats = codecCapabilities.colorFormats;
Log.d(RecordClient.class.getSimpleName(), "编码器格式:" + codecCapabilities.getMimeType());
Log.d(MediaManager.class.getSimpleName(), "编码器支持的文件格式:" + codecCapabilities.getMimeType());
// MediaCodecInfo.CodecCapabilities.COLOR_*
Log.d(RecordClient.class.getSimpleName(), "编码器支持格式:" + IntStream.of(colorFormats).boxed().map(String::valueOf).collect(Collectors.joining(" , ")));
// final int[] colorFormats = codecCapabilities.colorFormats;
// Log.d(MediaManager.class.getSimpleName(), "编码器支持的色彩格式:" + IntStream.of(colorFormats).boxed().map(String::valueOf).collect(Collectors.joining(" , ")));
}
// }
}
@@ -210,7 +209,6 @@ public final class MediaManager {
/**
* @param handler Handler
* @param context 上下文
* @param preview 是否预览视频
* @param playAudio 是否播放音频
* @param playVideo 是否播放视频
* @param audioConsume 是否消费音频
@@ -220,14 +218,13 @@ public final class MediaManager {
*/
public void initContext(
Handler handler, Context context,
boolean preview, boolean playAudio, boolean playVideo,
boolean playAudio, boolean playVideo,
boolean audioConsume, boolean videoConsume,
boolean audioProduce, boolean videoProduce,
TransportType transportType
) {
this.handler = handler;
this.context = context;
this.preview = preview;
this.playAudio = playAudio;
this.playVideo = playVideo;
this.audioConsume = audioConsume;
@@ -355,7 +352,7 @@ public final class MediaManager {
.setVideoDecoderFactory(videoDecoderFactory)
.setVideoEncoderFactory(videoEncoderFactory)
.createPeerConnectionFactory();
this.mediaStream = this.peerConnectionFactory.createLocalMediaStream("ARDAMS");
this.mediaStream = this.peerConnectionFactory.createLocalMediaStream("Taoyao");
Arrays.stream(videoEncoderFactory.getSupportedCodecs()).forEach(v -> {
Log.d(MediaManager.class.getSimpleName(), "支持的视频解码器:" + v.name);
});
@@ -412,8 +409,8 @@ public final class MediaManager {
mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
// mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression2", "true"));
// mediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googTypingNoiseDetection", "true"));
final AudioSource audioSource = this.peerConnectionFactory.createAudioSource(mediaConstraints);
final AudioTrack audioTrack = this.peerConnectionFactory.createAudioTrack("ARDAMSa0", audioSource);
this.audioSource = this.peerConnectionFactory.createAudioSource(mediaConstraints);
final AudioTrack audioTrack = this.peerConnectionFactory.createAudioTrack("TaoyaoA0", this.audioSource);
// audioTrack.setVolume(100);
audioTrack.setEnabled(true);
this.mediaStream.addTrack(audioTrack);
@@ -473,15 +470,15 @@ public final class MediaManager {
*/
private void initVideoTrack() {
// 加载视频
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("MediaVideoThread", this.eglBase.getEglBaseContext());
// surfaceTextureHelper.setTextureSize();
// surfaceTextureHelper.setFrameRotation();
final VideoSource videoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
this.surfaceTextureHelper = SurfaceTextureHelper.create("MediaVideoThread", this.eglBase.getEglBaseContext());
// this.surfaceTextureHelper.setTextureSize();
// this.surfaceTextureHelper.setFrameRotation();
this.videoSource = this.peerConnectionFactory.createVideoSource(this.videoCapturer.isScreencast());
// 美颜水印
// videoSource.setVideoProcessor();
this.videoCapturer.initialize(surfaceTextureHelper, this.context, videoSource.getCapturerObserver());
// this.videoSource.setVideoProcessor();
this.videoCapturer.initialize(this.surfaceTextureHelper, this.context, this.videoSource.getCapturerObserver());
this.videoCapturer.startCapture(480, 640, 30);
final VideoTrack videoTrack = this.peerConnectionFactory.createVideoTrack("ARDAMSv0", videoSource);
final VideoTrack videoTrack = this.peerConnectionFactory.createVideoTrack("TaoyaoV0", this.videoSource);
videoTrack.addSink(videoFrame -> {
if(this.recordClient != null) {
this.recordClient.putVideo(videoFrame);
@@ -492,17 +489,12 @@ public final class MediaManager {
Log.i(MediaManager.class.getSimpleName(), "加载视频:" + videoTrack.id());
}
public boolean isPreview() {
return this.preview;
}
public MediaStream getMediaStream() {
return this.mediaStream;
}
/**
* @param flag Config.WHAT_*
* @param forceEnabled 是否强制播放
* @param videoTrack 视频媒体流Track
*
* @return 播放控件
@@ -575,8 +567,8 @@ public final class MediaManager {
final Iterator<AudioTrack> iterator = this.mediaStream.audioTracks.iterator();
while (iterator.hasNext()) {
track = iterator.next();
iterator.remove();
track.dispose();
iterator.remove();
}
}
}
@@ -585,9 +577,7 @@ public final class MediaManager {
* 关闭视频
*/
private void closeVideoTrack() {
// 次码流
this.closeVideoTrack(this.mediaStream.videoTracks);
// 主码流
this.closeVideoTrack(this.mediaStream.preservedVideoTracks);
}
@@ -602,8 +592,8 @@ public final class MediaManager {
final Iterator<VideoTrack> iterator = list.iterator();
while (iterator.hasNext()) {
track = iterator.next();
iterator.remove();
track.dispose();
iterator.remove();
}
}
}
@@ -618,14 +608,26 @@ public final class MediaManager {
this.eglBase.release();
this.eglBase = null;
}
if (this.videoCapturer != null) {
this.videoCapturer.dispose();
this.videoCapturer = null;
if(this.audioSource != null) {
this.audioSource.dispose();
this.audioSource = null;
}
if(this.videoSource != null) {
this.videoSource.dispose();
this.videoSource = null;
}
if (this.mediaStream != null) {
this.mediaStream.dispose();
this.mediaStream = null;
}
if (this.videoCapturer != null) {
this.videoCapturer.dispose();
this.videoCapturer = null;
}
if(this.surfaceTextureHelper != null) {
this.surfaceTextureHelper.dispose();
this.surfaceTextureHelper = null;
}
if (this.peerConnectionFactory != null) {
this.peerConnectionFactory.dispose();
this.peerConnectionFactory = null;

View File

@@ -13,7 +13,7 @@ public interface RouterCallback {
default void sendTransportConnectCallback(String transportId, String dtlsParameters) {};
default String sendTransportProduceCallback(String kind, String transportId, String rtpParameters) { return null; };
default void recvTransportConnectCallback(String transportId, String dtlsParameters) {};
default void producerNewCallback(String kind, String producerId, long producerMediaTrackPointer) { };
default void producerNewCallback(String kind, String producerId, long producerMediaTrackPointer) {};
default void producerPauseCallback(String producerId) {};
default void producerResumeCallback(String producerId) {};
default void producerCloseCallback(String producerId) {};

View File

@@ -5,5 +5,6 @@ package com.acgist.taoyao.media.audio;
*
* @author acgist
*/
public class VoiceChangerProcesser {
public class AudioChangerProcesser {
}

View File

@@ -36,6 +36,7 @@ public class Room extends CloseableClient implements RouterCallback {
private final String clientId;
private final String roomId;
private final String password;
private final boolean preview;
private final boolean dataConsume;
private final boolean audioConsume;
private final boolean videoConsume;
@@ -47,24 +48,27 @@ public class Room extends CloseableClient implements RouterCallback {
private Map<String, RemoteClient> remoteClients;
private PeerConnection.RTCConfiguration rtcConfiguration;
private PeerConnectionFactory peerConnectionFactory;
private String rtpCapabilities;
private String sctpCapabilities;
public Room(
String name, String clientId,
String roomId, String password,
ITaoyao taoyao, Handler handler,
boolean preview,
boolean dataConsume, boolean audioConsume, boolean videoConsume,
boolean dataProduce, boolean audioProduce, boolean videoProduce
) {
super(taoyao, handler);
this.name = name;
this.clientId = clientId;
this.roomId = roomId;
this.roomId = roomId;
this.password = password;
this.dataConsume = dataConsume;
this.preview = preview;
this.dataConsume = dataConsume;
this.audioConsume = audioConsume;
this.videoConsume = videoConsume;
this.dataProduce = dataProduce;
this.dataProduce = dataProduce;
this.audioProduce = audioProduce;
this.videoProduce = videoProduce;
this.nativeRoomPointer = this.nativeNewRoom(roomId, this);
@@ -268,11 +272,13 @@ public class Room extends CloseableClient implements RouterCallback {
@Override
public void enterCallback(String rtpCapabilities, String sctpCapabilities) {
this.rtpCapabilities = rtpCapabilities;
this.sctpCapabilities = sctpCapabilities;
this.taoyao.request(this.taoyao.buildMessage(
"room::enter",
"roomId", this.roomId,
"password", this.password,
"rtpCapabilities", rtpCapabilities,
"roomId", this.roomId,
"password", this.password,
"rtpCapabilities", rtpCapabilities,
"sctpCapabilities", sctpCapabilities
));
}
@@ -281,8 +287,8 @@ public class Room extends CloseableClient implements RouterCallback {
public void sendTransportConnectCallback(String transportId, String dtlsParameters) {
this.taoyao.request(this.taoyao.buildMessage(
"media::transport::webrtc::connect",
"roomId", this.roomId,
"transportId", transportId,
"roomId", this.roomId,
"transportId", transportId,
"dtlsParameters", JSONUtils.toMap(dtlsParameters)
));
}

View File

@@ -0,0 +1,59 @@
package com.acgist.taoyao.media.signal;
import com.acgist.taoyao.boot.model.Message;
import java.util.Map;
/**
* 信令监听
*
* @author acgist
*/
public interface ITaoyaoListener {
/**
* 前置信令处理
*
* @param message 信令消息
*
* @return 是否继续处理信令
*/
default boolean preOnMessage(Message message) {
return false;
}
/**
* 后置信令处理
*
* @param message 信令消息
*/
default void postOnMessage(Message message) {
}
/**
* 信令正在连接
*/
default void onConnect() {
}
/**
* 信令连接成功
*/
default void onConnected() {
}
/**
* 信令断开连接
*/
default void onDisconnect() {
}
/**
* 信令异常
*
* @param throwable 异常
*/
default void onError(Throwable throwable) {
}
}

View File

@@ -1,9 +1,30 @@
package com.acgist.taoyao.media.video;
import org.webrtc.VideoFrame;
import org.webrtc.VideoProcessor;
import org.webrtc.VideoSink;
/**
* AI处理器
*
* @author acgist
*/
public class AiProcesser {
public class AiProcesser implements VideoProcessor {
@Override
public void setSink(VideoSink videoSink) {
}
@Override
public void onCapturerStarted(boolean status) {
}
@Override
public void onCapturerStopped() {
}
@Override
public void onFrameCaptured(VideoFrame videoFrame) {
}
}

View File

@@ -1,9 +1,29 @@
package com.acgist.taoyao.media.video;
import org.webrtc.VideoFrame;
import org.webrtc.VideoProcessor;
import org.webrtc.VideoSink;
/**
* 美颜处理器
*
* @author acgist
*/
public class BeautyProcesser {
public class BeautyProcesser implements VideoProcessor {
@Override
public void setSink(VideoSink videoSink) {
}
@Override
public void onCapturerStarted(boolean status) {
}
@Override
public void onCapturerStopped() {
}
@Override
public void onFrameCaptured(VideoFrame videoFrame) {
}
}

View File

@@ -1,9 +1,30 @@
package com.acgist.taoyao.media.video;
import org.webrtc.VideoFrame;
import org.webrtc.VideoProcessor;
import org.webrtc.VideoSink;
/**
* 水印处理器
*
* @author acgist
*/
public class WatermarkProcesser {
public class WatermarkProcesser implements VideoProcessor {
@Override
public void setSink(VideoSink videoSink) {
}
@Override
public void onCapturerStarted(boolean status) {
}
@Override
public void onCapturerStopped() {
}
@Override
public void onFrameCaptured(VideoFrame videoFrame) {
}
}