diff --git a/Android/APIExample/app/build.gradle b/Android/APIExample/app/build.gradle
index 4c1eeaa7..e4a03be0 100644
--- a/Android/APIExample/app/build.gradle
+++ b/Android/APIExample/app/build.gradle
@@ -71,6 +71,10 @@ android {
pickFirst 'lib/x86_64/libbytertc_vp8codec_extension.so'
pickFirst 'lib/x86_64/libh265enc.so'
+
+ // 删除重复的 libc++ 共享库
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
@@ -92,10 +96,9 @@ dependencies {
implementation files('libs/ByteEffect.aar')
implementation'com.faceunity:core:8.7.0'
implementation'com.faceunity:model:8.7.0'
- implementation "com.bytedanceapi:ttsdk-player_premium:1.40.2.8"
+ implementation 'com.bytedanceapi:ttsdk-player_premium:1.47.1.10'
+ implementation 'com.bytedanceapi:ttsdk-ttlivepull_rtc:1.47.1.10'
- implementation ("com.bytedanceapi:ttsdk-ttlivepull:1.40.2.8") {
- }
implementation 'commons-net:commons-net:3.6'
// 日志上报 SDK,用于点播日志上传, 使用 6.14.3 及以上版本
diff --git a/Android/APIExample/app/src/main/java/rtc/volcengine/apiexample/examples/PullStreamActivity.java b/Android/APIExample/app/src/main/java/rtc/volcengine/apiexample/examples/PullStreamActivity.java
index 19501a22..c78621c5 100644
--- a/Android/APIExample/app/src/main/java/rtc/volcengine/apiexample/examples/PullStreamActivity.java
+++ b/Android/APIExample/app/src/main/java/rtc/volcengine/apiexample/examples/PullStreamActivity.java
@@ -6,22 +6,19 @@
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
-import android.view.Surface;
import android.view.SurfaceView;
-import android.widget.Button;
import android.widget.EditText;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
import android.widget.TextView;
import com.bytedance.vcloud.cacheModule.utils.CmLog;
import com.pandora.common.env.Env;
import com.pandora.common.env.config.Config;
import com.pandora.common.env.config.VodConfig;
-import com.pandora.live.player.LivePlayerBuilder;
import com.pandora.ttlicense2.LicenseManager;
import com.ss.mediakit.medialoader.AVMDLLog;
import com.ss.ttvideoengine.utils.TTVideoEngineLog;
-import com.ss.videoarch.liveplayer.ILiveListener;
-import com.ss.videoarch.liveplayer.INetworkClient;
import com.ss.videoarch.liveplayer.VeLivePlayer;
import com.ss.videoarch.liveplayer.VeLivePlayerAudioFrame;
import com.ss.videoarch.liveplayer.VeLivePlayerConfiguration;
@@ -32,13 +29,8 @@
import com.ss.videoarch.liveplayer.VeLivePlayerStreamData;
import com.ss.videoarch.liveplayer.VeLivePlayerVideoFrame;
import com.ss.videoarch.liveplayer.VideoLiveManager;
-import com.ss.videoarch.liveplayer.log.LiveError;
-import com.ss.videoarch.liveplayer.log.VeLivePlayerLog;
-
-import org.json.JSONObject;
import java.io.File;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import rtc.volcengine.apiexample.BaseActivity;
@@ -58,6 +50,10 @@ public class PullStreamActivity extends BaseActivity {
private TextView seiMsg;
private VeLivePlayer livePlayer;
+ private VeLivePlayerDef.VeLivePlayerFormat streamFormat; // 选中的是 FLV 拉流还是 RTM 拉流
+ private VeLivePlayerDef.VeLivePlayerProtocol streamProtocol; // 使用的拉流协议
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,9 +74,6 @@ protected void onCreate(Bundle savedInstanceState) {
// 配置播放器回调
livePlayer.setObserver(mLivePlayerObserver);
-
-
-
}
// VeLivePlayerObserver 回调
@@ -183,6 +176,27 @@ private void initUI() {
surfaceView = findViewById(R.id.video_view);
livePlayer.setSurfaceHolder(surfaceView.getHolder());
+ RadioGroup radioGroup = findViewById(R.id.streamTypeGroup);
+
+ // 默认选择 FLV 拉流
+ radioGroup.check(R.id.flvStreamType);
+ streamFormat = VeLivePlayerDef.VeLivePlayerFormat.VeLivePlayerFormatFLV;
+ streamProtocol = VeLivePlayerDef.VeLivePlayerProtocol.VeLivePlayerProtocolTCP;
+
+ // 设置监听器
+ radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
+ switch (checkedId) {
+ case R.id.flvStreamType:
+ streamFormat = VeLivePlayerDef.VeLivePlayerFormat.VeLivePlayerFormatFLV;
+ streamProtocol = VeLivePlayerDef.VeLivePlayerProtocol.VeLivePlayerProtocolTCP;
+ break;
+ case R.id.rtmStreamType:
+ streamFormat = VeLivePlayerDef.VeLivePlayerFormat.VeLivePlayerFormatRTM;
+ streamProtocol = VeLivePlayerDef.VeLivePlayerProtocol.VeLivePlayerProtocolTLS;
+ break;
+ }
+ });
+
btnStartPull = findViewById(R.id.btn_start_pull);
btnStopPull = findViewById(R.id.btn_stop_pull);
urlInput = findViewById(R.id.url_input);
@@ -195,32 +209,29 @@ private void initUI() {
return;
}
- // 配置 RTM 地址
- VeLivePlayerStreamData.VeLivePlayerStream playStreamRTM = new VeLivePlayerStreamData.VeLivePlayerStream();
- playStreamRTM.url = url;
- playStreamRTM.format = VeLivePlayerDef.VeLivePlayerFormat.VeLivePlayerFormatFLV;
- playStreamRTM.resolution = VeLivePlayerDef.VeLivePlayerResolution.VeLivePlayerResolutionOrigin;
- playStreamRTM.streamType = VeLivePlayerDef.VeLivePlayerStreamType.VeLivePlayerStreamTypeMain;
+ // 配置流信息
+ VeLivePlayerStreamData.VeLivePlayerStream playStream = new VeLivePlayerStreamData.VeLivePlayerStream();
+ playStream.url = url;
+ playStream.format = streamFormat;
+ playStream.resolution = new VeLivePlayerDef.VeLivePlayerResolution(VeLivePlayerDef.VeLivePlayerResolution.VeLivePlayerResolutionOrigin);
+ playStream.streamType = VeLivePlayerDef.VeLivePlayerStreamType.VeLivePlayerStreamTypeMain;
// 创建 VeLivePlayerStreamData
VeLivePlayerStreamData streamData = new VeLivePlayerStreamData();
streamData.mainStreamList = new ArrayList<>();
-// 添加 RTM 流地址
- streamData.mainStreamList.add(playStreamRTM);
+ // 添加流
+ streamData.mainStreamList.add(playStream);
// 配置默认 format 和 protocol
- streamData.defaultFormat = VeLivePlayerDef.VeLivePlayerFormat.VeLivePlayerFormatFLV;
- streamData.defaultProtocol = VeLivePlayerDef.VeLivePlayerProtocol.VeLivePlayerProtocolTCP;
+ streamData.defaultFormat = streamFormat;
+ streamData.defaultProtocol = streamProtocol;
-// 配置播放源
+ // 配置播放源
livePlayer.setPlayStreamData(streamData);
-// 开始播放
+ // 开始播放
livePlayer.play();
-
-// livePlayer.setPlayUrl(url);
-// livePlayer.play();
});
btnStopPull.setOnClickListener(v -> livePlayer.stop());
}
diff --git a/Android/APIExample/app/src/main/res/layout/activity_pull_stream.xml b/Android/APIExample/app/src/main/res/layout/activity_pull_stream.xml
index 413179cf..d7fe0d6a 100644
--- a/Android/APIExample/app/src/main/res/layout/activity_pull_stream.xml
+++ b/Android/APIExample/app/src/main/res/layout/activity_pull_stream.xml
@@ -12,6 +12,36 @@
android:layout_width="match_parent"
android:layout_height="400dp" />
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Android/APIExample/settings.gradle b/Android/APIExample/settings.gradle
index c7c9c060..3be91350 100644
--- a/Android/APIExample/settings.gradle
+++ b/Android/APIExample/settings.gradle
@@ -14,6 +14,16 @@ dependencyResolutionManagement {
mavenCentral()
maven { url 'https://artifact.bytedance.com/repository/Volcengine/' }
maven { url 'https://maven.faceunity.com/repository/maven-public/' }
+ maven {
+ url "https://artifact.bytedance.com/repository/thrall_base/"
+ credentials {
+ username = 'veVOS'
+ password = 'KUC9TpKrqbryrxHz'
+ }
+ authentication {
+ digest(BasicAuthentication)
+ }
+ }
}
}
rootProject.name = "APIExample"
diff --git a/iOS/ApiExample/ApiExample/ImportantComponents/PullRTMP/PullRTMPViewController.swift b/iOS/ApiExample/ApiExample/ImportantComponents/PullRTMP/PullRTMPViewController.swift
index 6ddf8342..2bceec1b 100644
--- a/iOS/ApiExample/ApiExample/ImportantComponents/PullRTMP/PullRTMPViewController.swift
+++ b/iOS/ApiExample/ApiExample/ImportantComponents/PullRTMP/PullRTMPViewController.swift
@@ -8,9 +8,12 @@ import Foundation
import TTSDKFramework
-class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
+class PullRTMPViewController: BaseViewController, VeLivePlayerObserver {
var livePlayer: TVLManager?
+ // TVL拉流 或 RTM拉流,默认TVL拉流
+ var streamFormat: VeLivePlayerFormat = .FLV
+ var streamProtocol: VeLivePlayerProtocol = .TCP
override func viewDidLoad() {
super.viewDidLoad()
@@ -47,6 +50,8 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
}
func buildTVEngine() -> Void {
+ print(TTSDKManager.sdkVersionString)
+
// 创建播放器
self.livePlayer = TVLManager.init()
@@ -63,7 +68,7 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
print("setConfig")
self.livePlayer?.setConfig(config)
- self.livePlayer?.setObserver(self)
+ self.livePlayer?.setObserver(self)
}
func buildRenderView() -> Void {
@@ -87,20 +92,41 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
func createUI() -> Void {
+ view.addSubview(ttsdkVersionLabel)
+
view.addSubview(liveView)
- view.addSubview(urlTextFieldView)
+ view.addSubview(streamTypeControl)
+
+ view.addSubview(urlTextFieldView)
view.addSubview(startButton)
view.addSubview(stopButton)
+ view.addSubview(receivedSEILabel)
+ view.addSubview(receivedSEITextField)
+
liveView.snp.makeConstraints { make in
make.top.equalTo(topView.snp.bottom)
make.left.right.equalToSuperview()
make.height.equalTo(liveView.snp.width)
}
+ ttsdkVersionLabel.snp.makeConstraints { make in
+ make.top.equalTo(liveView.snp.bottom).offset(5)
+ make.left.equalToSuperview().offset(10)
+ make.right.equalToSuperview().offset(-10)
+ make.height.equalTo(30)
+ }
+
+ streamTypeControl.snp.makeConstraints { make in
+ make.top.equalTo(ttsdkVersionLabel.snp.bottom).offset(10)
+ make.left.equalToSuperview().offset(10)
+ make.right.equalToSuperview().offset(-10)
+ make.height.equalTo(30)
+ }
+
urlTextFieldView.snp.makeConstraints { make in
- make.top.equalTo(liveView.snp.bottom).offset(20)
+ make.top.equalTo(streamTypeControl.snp.bottom).offset(20)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(36)
@@ -114,36 +140,63 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
stopButton.snp.makeConstraints { make in
make.centerY.equalTo(startButton)
- make.left.equalTo(startButton.snp.right).offset(20)
+ make.left.equalTo(startButton.snp.right).offset(10)
make.right.equalToSuperview().offset(-10)
make.width.height.equalTo(startButton)
}
- view.addSubview(receivedSEILabel)
- view.addSubview(receivedSEITextField)
-
receivedSEILabel.snp.makeConstraints { make in
- make.top.equalTo(startButton.snp.bottom).offset(20)
+ make.top.equalTo(startButton.snp.bottom).offset(10)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(30)
}
receivedSEITextField.snp.makeConstraints { make in
- make.top.equalTo(receivedSEILabel.snp.bottom).offset(20)
+ make.top.equalTo(receivedSEILabel.snp.bottom).offset(5)
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
- make.bottom.equalToSuperview().offset(-20)
-
+ make.bottom.equalToSuperview().offset(-10)
+ make.height.equalTo(30)
+ }
+ }
+
+ @objc func streamTypeControlChanged(_ sender: UISegmentedControl) {
+ let selectedStreamTypeIndex = sender.selectedSegmentIndex
+
+ if selectedStreamTypeIndex == 0 {
+ streamFormat = .FLV
+ streamProtocol = .TCP
+ print("Selected stream type: FLV")
+ } else if selectedStreamTypeIndex == 1 {
+ streamFormat = .RTM
+ streamProtocol = .TLS
+ print("Selected stream type: RTM")
}
}
@objc func startPull() {
- if let text = self.urlTextFieldView.text, !text.isEmpty {
- self.livePlayer?.setPlayUrl(text)
+ if let urlText = self.urlTextFieldView.text, !urlText.isEmpty {
+ ToastComponents.shared.show(withMessage: "当前拉流URL : \(urlText)")
+
+ let playerStream = VeLivePlayerStream()
+ playerStream.url = urlText
+ playerStream.format = streamFormat
+ playerStream.resolution = .origin
+ playerStream.type = .main
+
+ let streamData = VeLivePlayerStreamData()
+ streamData.mainStream = [playerStream]
+ streamData.defaultFormat = streamFormat
+ streamData.defaultProtocol = streamProtocol
+
+ // 不再使用 self.livePlayer?.setPlayUrl(text)
+ self.livePlayer?.setPlay(streamData)
self.livePlayer?.play()
+
+ print("URL: \(urlText)")
} else {
- ToastComponents.shared.show(withMessage: "无效的推流地址")
+ ToastComponents.shared.show(withMessage: "拉流URL为空!")
}
}
@@ -152,12 +205,26 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
}
// MARK: Lazy laod
+ lazy var ttsdkVersionLabel: UILabel = {
+ let label = UILabel()
+ label.text = "TTSDK版本:\(TTSDKManager.sdkVersionString)"
+ return label
+ }()
+
lazy var liveView: UIView = {
let view = UIView.init()
view.backgroundColor = .groupTableViewBackground
return view
}()
+ lazy var streamTypeControl: UISegmentedControl = {
+ let control = UISegmentedControl(items: ["FLV拉流", "RTM拉流"])
+ control.selectedSegmentIndex = 0 // 默认FLV拉流
+ control.addTarget(self, action: #selector(streamTypeControlChanged(_:)), for: .valueChanged)
+ control.translatesAutoresizingMaskIntoConstraints = false
+ return control
+ }()
+
lazy var urlTextFieldView: TextFieldView = {
let settingView = TextFieldView()
settingView.title = "拉流地址"
@@ -196,7 +263,10 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
// MARK: VeLivePlayerObserver
func onError(_ player: TVLManager, error: VeLivePlayerError) {
ToastComponents.shared.show(withMessage: "onError:\(error.errorMsg ?? "")")
-
+ }
+
+ func onFirstVideoFrameRender(_ player: TVLManager, isFirstFrame: Bool) {
+ ToastComponents.shared.show(withMessage: "First Video Frame Received")
}
func onReceiveSeiMessage(_ player: TVLManager, message: String) {
@@ -206,8 +276,6 @@ class PullRTMPViewController: BaseViewController,VeLivePlayerObserver {
func onPlayerStatusUpdate(_ player: TVLManager, status: VeLivePlayerStatus) {
ToastComponents.shared.show(withMessage: "onPlayerStatusUpdate:\(status.rawValue)")
-
-
}
}
diff --git a/iOS/ApiExample/Podfile b/iOS/ApiExample/Podfile
index 14356512..3875248c 100644
--- a/iOS/ApiExample/Podfile
+++ b/iOS/ApiExample/Podfile
@@ -20,7 +20,7 @@ target 'ApiExample' do
# 相芯美颜SDK
pod 'FURenderKit', '8.7.0'
- ## TT rtmp拉流sdk
- pod 'TTSDKFramework', '1.40.3.6-premium', :subspecs => ['LivePull']
+ # TTSDK RTMP拉流模块
+ pod 'TTSDKFramework', '1.47.1.12-premium', :subspecs => ['LivePull-RTS']
end