集成完直播后提交代码

This commit is contained in:
xuhuixiang
2026-02-06 14:55:21 +08:00
commit ea9ffa06ff
960 changed files with 75063 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alivc.live.baselive_pull">
<application>
<activity
android:name=".ui.PlayerActivity"
android:alwaysRetainTaskState="true"
android:screenOrientation="portrait"
android:theme="@style/AVLiveTheme" />
</application>
</manifest>

View File

@@ -0,0 +1,132 @@
package com.alivc.live.baselive_pull.adapter;
import android.annotation.SuppressLint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.alivc.live.baselive_pull.R;
import com.alivc.live.baselive_pull.bean.Constants;
import com.alivc.live.baselive_pull.listener.ButtonClickListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PlayButtonListAdapter extends RecyclerView.Adapter {
private ButtonClickListener clickListener;
private boolean isItemHide = false;
public void setClickListener(ButtonClickListener clickListener) {
this.clickListener = clickListener;
mButtonEnableMap = new HashMap<>();
}
private List<String> mListDatas = new ArrayList<>();
private Map<String,Boolean> mButtonEnableMap;
public void setData(List<String> data){
if(data == null){
return;
}
mListDatas.clear();
mListDatas.addAll(data);
notifyDataSetChanged();
}
public List<String> getData(){
return mListDatas;
}
public void hideItems(boolean isItemHide){
this.isItemHide = isItemHide;
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.live_recycle_button_item_view, parent, false);
ButtonHolder buttonHolder = new ButtonHolder(view);
return buttonHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") final int position) {
// position 从 0开始
ButtonHolder viewHolder= (ButtonHolder) holder;
viewHolder.textView.setText(mListDatas.get(position));
viewHolder.imageView.setImageResource(Constants.getLive_img_soure().get(mListDatas.get(position)));
viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(clickListener!=null){
clickListener.onButtonClick(mListDatas.get(position),position);
}
}
});
boolean enable = true;
if (mButtonEnableMap.containsKey(mListDatas.get(position))){
enable = mButtonEnableMap.get(mListDatas.get(position));
}
if(!enable){
if("开始推流".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_push_gray);
}
if("数据指标".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_data_gray);
}
if("麦克风".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_microphone_gray);
}
if("调节参数".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_adjust_gray);
}
}else {
if("开始推流".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_push);
}
if("麦克风".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_microphone);
}
if("数据指标".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setImageResource(R.drawable.live_data);
}
}
viewHolder.imageView.setEnabled(enable);
//针对数据指标做特殊处理
if("数据指标".equalsIgnoreCase(mListDatas.get(position))){
viewHolder.imageView.setEnabled(true);
}
}
@Override
public int getItemCount() {
return mListDatas.size();
}
private class ButtonHolder extends RecyclerView.ViewHolder {
private TextView textView;
private ImageView imageView;
public ButtonHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv_anchor_text);
imageView=itemView.findViewById(R.id.iv_anchor);
}
}
public void setButtonEnable(String buttonName,boolean enable){
mButtonEnableMap.put(buttonName,enable);
int position = -1;
for (int i = 0; i < mListDatas.size(); i++) {
if (mListDatas.get(i).equals(buttonName)){
position = i;
}
}
if (position>=0){
notifyItemChanged(position);
}
}
}

View File

@@ -0,0 +1,65 @@
package com.alivc.live.baselive_pull.bean;
import com.alivc.live.baselive_pull.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Constants {
private static List<String> live_push_button;
private static List<String> live_pull_button;
private static List<String> live_play_button;
private static HashMap<String,Integer> live_img_soure;
public static HashMap<String,Integer> getLive_img_soure() {
return live_img_soure;
}
static {
/**
* push页面的按钮
* */
live_push_button = new ArrayList<>();
live_img_soure=new HashMap<>();
live_img_soure.put("开始推流", R.drawable.live_push);
live_img_soure.put("美颜", R.drawable.live_beauty);
live_img_soure.put("音效",R.drawable.live_sound);
live_img_soure.put("摄像头",R.drawable.live_carmer);
live_img_soure.put("静音",R.drawable.mute_btn);
live_img_soure.put("调节参数",R.drawable.live_adjust_parm);
live_img_soure.put("数据指标",R.drawable.live_data);
live_push_button.add("开始推流");
live_push_button.add("美颜");
live_push_button.add("音效");
live_push_button.add("静音");
live_push_button.add("摄像头");
live_push_button.add("调节参数");
live_push_button.add("数据指标");
/**
* pull页面按钮
*/
live_pull_button = new ArrayList<>();
live_pull_button.add("暂停观看");
live_pull_button.add("静音");
live_pull_button.add("听筒切换");
live_img_soure.put("暂停观看",R.drawable.finish_play);
live_img_soure.put("听筒切换",R.drawable.telephone_change);
/**
* play页面按钮
*/
live_play_button = new ArrayList<>();
live_play_button.add("暂停观看");
}
public static List<String> getPushActivityButtonList(){
return live_push_button;
}
public static List<String> getPullActivityButtonList(){
return live_pull_button;
}
public static List<String> getPlayActivityButtonList(){
return live_play_button;
}
}

View File

@@ -0,0 +1,44 @@
package com.alivc.live.baselive_pull.bean.rmsbean;
/**
* Auto-generated: 2024-08-06 14:42:42
*/
public class RMSCanvas {
private int w;
private int h;
private int bgnd;
public void setW(int w) {
this.w = w;
}
public int getW() {
return w;
}
public void setH(int h) {
this.h = h;
}
public int getH() {
return h;
}
public void setBgnd(int bgnd) {
this.bgnd = bgnd;
}
public int getBgnd() {
return bgnd;
}
@Override
public String toString() {
return "Canvas{" +
"w=" + w +
", h=" + h +
", bgnd=" + bgnd +
'}';
}
}

View File

@@ -0,0 +1,66 @@
package com.alivc.live.baselive_pull.bean.rmsbean;
import java.util.List;
/**
* Auto-generated: 2024-08-06 14:42:42
*/
public class RMSPeriodicBean {
private RMSCanvas canvas;
private List<RMSStream> stream;
private String source;
private String ver;
private long ts;
public void setCanvas(RMSCanvas canvas) {
this.canvas = canvas;
}
public RMSCanvas getCanvas() {
return canvas;
}
public void setStream(List<RMSStream> stream) {
this.stream = stream;
}
public List<RMSStream> getStream() {
return stream;
}
public void setSource(String source) {
this.source = source;
}
public String getSource() {
return source;
}
public void setVer(String ver) {
this.ver = ver;
}
public String getVer() {
return ver;
}
public void setTs(long ts) {
this.ts = ts;
}
public long getTs() {
return ts;
}
@Override
public String toString() {
return "JsonRootBean{" +
"canvas=" + canvas +
", stream=" + stream +
", source='" + source + '\'' +
", ver='" + ver + '\'' +
", ts=" + ts +
'}';
}
}

View File

@@ -0,0 +1,154 @@
package com.alivc.live.baselive_pull.bean.rmsbean;
/**
* Auto-generated: 2024-08-06 14:42:42
*/
public class RMSStream {
private String uid;
private int paneid;
private int zorder;
private int x;
private int y;
private int w;
private int h;
private int type;
private int status;
private int cameraDisabled;
private int muted;
private int vol;
private int vad;
private int netQuality;
public void setUid(String uid) {
this.uid = uid;
}
public String getUid() {
return uid;
}
public void setPaneid(int paneid) {
this.paneid = paneid;
}
public int getPaneid() {
return paneid;
}
public void setZorder(int zorder) {
this.zorder = zorder;
}
public int getZorder() {
return zorder;
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public void setW(int w) {
this.w = w;
}
public int getW() {
return w;
}
public void setH(int h) {
this.h = h;
}
public int getH() {
return h;
}
public void setType(int type) {
this.type = type;
}
public int getType() {
return type;
}
public void setStatus(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
public void setCameraDisabled(int cameraDisabled) {
this.cameraDisabled = cameraDisabled;
}
public int getCameraDisabled() {
return cameraDisabled;
}
public void setMuted(int muted) {
this.muted = muted;
}
public int getMuted() {
return muted;
}
public void setVol(int vol) {
this.vol = vol;
}
public int getVol() {
return vol;
}
public void setVad(int vad) {
this.vad = vad;
}
public int getVad() {
return vad;
}
public void setNetQuality(int netQuality) {
this.netQuality = netQuality;
}
public int getNetQuality() {
return netQuality;
}
@Override
public String toString() {
return "Stream{" +
"uid='" + uid + '\'' +
", paneid=" + paneid +
", zorder=" + zorder +
", x=" + x +
", y=" + y +
", w=" + w +
", h=" + h +
", type=" + type +
", status=" + status +
", cameraDisabled=" + cameraDisabled +
", muted=" + muted +
", vol=" + vol +
", vad=" + vad +
", netQuality=" + netQuality +
'}';
}
}

View File

@@ -0,0 +1,5 @@
package com.alivc.live.baselive_pull.listener;
public interface ButtonClickListener {
void onButtonClick(String message, int position);
}

View File

@@ -0,0 +1,379 @@
package com.alivc.live.baselive_pull.ui;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.acker.simplezxing.activity.CaptureActivity;
import com.alivc.live.baselive_pull.R;
import com.alivc.live.baselive_pull.bean.Constants;
import com.alivc.live.baselive_pull.listener.ButtonClickListener;
import com.alivc.live.baselive_pull.ui.widget.PlayButtonListView;
import com.alivc.live.commonbiz.BuildConfig;
import com.alivc.live.commonbiz.test.PushDemoTestConstants;
import com.alivc.live.commonui.dialog.CommonDialog;
import com.alivc.live.commonui.messageview.AutoScrollMessagesView;
import com.alivc.live.commonui.utils.StatusBarUtil;
import com.alivc.live.commonutils.TextFormatUtil;
import com.alivc.live.commonutils.ToastUtils;
import com.aliyun.player.AliPlayer;
import com.aliyun.player.AliPlayerFactory;
import com.aliyun.player.IPlayer;
import com.aliyun.player.bean.ErrorInfo;
import com.aliyun.player.nativeclass.PlayerConfig;
import com.aliyun.player.source.UrlSource;
import com.cicada.player.utils.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* 直播拉流界面
*/
public class PlayerActivity extends AppCompatActivity implements SurfaceHolder.Callback, ButtonClickListener {
private static final String TAG = "PlayerActivity";
private PlayButtonListView mButtonListView;
private SurfaceView mSurfaceView;
private String mPullUrl = "";
private AliPlayer mAliPlayer;
private EditText mPullUrlET;//拉流地址
private Button mPullStartBtn;//开始拉流btn
private Button mScanBtn;//扫码
private boolean isStopPullFlag = false;//是否点击过停止播放
private boolean isPulling = false;
private StringBuilder mSeiStringBuilder = new StringBuilder();
private CommonDialog mDialog;
private AutoScrollMessagesView mSeiMessageView;
static {
try {
if (BuildConfig.MTL_BUILD_FOR_AIO) {
System.loadLibrary("all_in_one");
} else {
System.loadLibrary("RtsSDK");
}
} catch (Throwable ignore) {
}
}
private View mPageVg;
private ImageView mBackBtn;
private View mInputRl;
private TextView mTitleTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
StatusBarUtil.translucent(this, Color.TRANSPARENT);
setContentView(R.layout.activity_player);
initPlayer();
initView();
String initUrl = PushDemoTestConstants.getTestPullUrl();
if (!initUrl.isEmpty()) {
mPullUrlET.setText(initUrl);
mPullUrl = initUrl;
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// 当前屏幕为横屏
} else {
// 当前屏幕为竖屏
}
}
private void initPlayer() {
Logger.getInstance(this).enableConsoleLog(true);
Logger.getInstance(this).setLogLevel(Logger.LogLevel.AF_LOG_LEVEL_TRACE);
mAliPlayer = AliPlayerFactory.createAliPlayer(this.getApplicationContext());
mAliPlayer.setAutoPlay(true);
mAliPlayer.setOnRenderingStartListener(new IPlayer.OnRenderingStartListener() {
@Override
public void onRenderingStart() {
setViewState(true);
}
});
mAliPlayer.setOnErrorListener(new IPlayer.OnErrorListener() {
@Override
public void onError(ErrorInfo errorInfo) {
if (mAliPlayer != null) {
mAliPlayer.reload();
}
if (mDialog == null || !mDialog.isShowing()) {
mDialog = new CommonDialog(PlayerActivity.this);
mDialog.setDialogTitle("Error");
mDialog.setDialogContent(errorInfo.getMsg());
mDialog.setConfirmButton(TextFormatUtil.getTextFormat(PlayerActivity.this, R.string.pull_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
mDialog.setCancelButton(TextFormatUtil.getTextFormat(PlayerActivity.this, R.string.pull_restart), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (mAliPlayer == null) {
initPlayer();
mSurfaceView = new SurfaceView(PlayerActivity.this);
mSurfaceView.getHolder().addCallback(PlayerActivity.this);
}
UrlSource source = new UrlSource();
String url = mPullUrlET.getText().toString();
if (TextUtils.isEmpty(url)) {
return;
}
source.setUri(url);
if (mAliPlayer != null) {
PlayerConfig cfg = mAliPlayer.getConfig();
if (url.startsWith("artc://")) {
cfg.mMaxDelayTime = 1000;
cfg.mHighBufferDuration = 10;
cfg.mStartBufferDuration = 10;
}
mAliPlayer.setConfig(cfg);
mAliPlayer.setDataSource(source);
mAliPlayer.prepare();
}
}
});
mDialog.show();
}
}
});
// TODO keria: Remove the SEI function of the player first, as it will cause bytecode conflicts between the player SDK and the push SDK.
// mAliPlayer.setOnSeiDataListener((payload, uuid, data) -> {
// String msg = new String(data, StandardCharsets.UTF_8);
// String str = "[cdn]: [" + payload + "], " + msg;
// mSeiMessageView.appendMessage(str);
// Log.i(TAG, str);
//
// if (payload == 5) {
// // implementation externalGSON
// Gson gson = new Gson();
// RMSPeriodicBean rmsPeriodicBean = null;
// try {
// // The sei message may end with \0, if we want to parse the json, we need to trim the string
// rmsPeriodicBean = gson.fromJson(msg.trim(), RMSPeriodicBean.class);
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// Log.i(TAG, "rms periodic bean: " + rmsPeriodicBean);
// }
// }
// });
}
private void initView() {
mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
mPageVg = findViewById(R.id.page_bg);
mInputRl = findViewById(R.id.input_rl);
mTitleTv = findViewById(R.id.title);
mButtonListView = (PlayButtonListView) findViewById(R.id.live_buttonlistview);
mSeiMessageView = findViewById(R.id.sei_receive_view);
List<String> data = new ArrayList<>();
data.addAll(Constants.getPlayActivityButtonList());
mButtonListView.setData(data);
mButtonListView.setClickListener(this);
mButtonListView.setVisibility(View.GONE);
mSurfaceView.getHolder().addCallback(this);
mScanBtn = (Button) findViewById(R.id.player_scan_image);
mScanBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startCaptureActivityForResult();
}
});
mBackBtn = findViewById(R.id.pull_common_btn_close);
mBackBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mPageVg.getVisibility() == View.GONE) {
onButtonClick("暂停播放", 0);
} else {
finish();
}
}
});
mPullUrlET = (EditText) findViewById(R.id.pull_common_push_url);
mPullStartBtn = (Button) findViewById(R.id.pull_common_start_btn);
mPullStartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isPulling = true;
startPull(mPullUrlET.getText().toString());
}
});
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mAliPlayer != null) {
mAliPlayer.setSurface(holder.getSurface());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mAliPlayer != null) {
mAliPlayer.surfaceChanged();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mAliPlayer != null) {
mAliPlayer.setSurface(null);
}
}
private void stopPull() {
stopPlay();
}
private void startPull(String url) {
if (TextUtils.isEmpty(url)) {
ToastUtils.show(getBaseContext().getResources().getString(R.string.live_pull_addr_error));
} else {
ToastUtils.show("pulling...");
startPlay();
}
}
private void startCaptureActivityForResult() {
Intent intent = new Intent(PlayerActivity.this, CaptureActivity.class);
startActivityForResult(intent, CaptureActivity.REQ_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CaptureActivity.REQ_CODE:
switch (resultCode) {
case RESULT_OK:
String pullUrl = data.getStringExtra(CaptureActivity.EXTRA_SCAN_RESULT);
mPullUrlET.setText(pullUrl);
break;
case RESULT_CANCELED:
break;
default:
break;
}
default:
break;
}
}
public void startPlay() {
isPulling = true;
mSurfaceView.setVisibility(View.VISIBLE);
if (TextUtils.isEmpty(mPullUrl) && TextUtils.isEmpty(mPullUrlET.getText().toString())) {
Toast.makeText(this, "拉流地址为空", Toast.LENGTH_SHORT).show();
return;
}
if (!TextUtils.isEmpty(mPullUrlET.getText().toString())) {
mPullUrl = mPullUrlET.getText().toString();
}
UrlSource source = new UrlSource();
String pullUrl = mPullUrlET.getText().toString();
source.setUri(pullUrl);
if (mAliPlayer != null) {
PlayerConfig cfg = mAliPlayer.getConfig();
cfg.mEnableSEI = true;
if (pullUrl.startsWith("artc://")) {
cfg.mMaxDelayTime = 1000;
cfg.mHighBufferDuration = 10;
cfg.mStartBufferDuration = 10;
}
mAliPlayer.setConfig(cfg);
mAliPlayer.setDataSource(source);
mAliPlayer.prepare();
}
mButtonListView.setVisibility(View.VISIBLE);
}
/**
* 停止播放
*/
public void stopPlay() {
if (mAliPlayer != null) {
mAliPlayer.stop();
}
}
@Override
protected void onDestroy() {
if (mAliPlayer != null) {
stopPlay();
mAliPlayer.setSurface(null);
mAliPlayer.release();
mAliPlayer = null;
}
mSeiStringBuilder.delete(0, mSeiStringBuilder.length());
super.onDestroy();
}
@Override
public void onButtonClick(String message, int position) {
switch (position) {
case 0:
if (isPulling) {
stopPull();
isPulling = false;
setViewState(false);
} else {
startPull(mPullUrlET.getText().toString());
isPulling = true;
}
break;
default:
break;
}
}
private void setViewState(boolean isPlaying) {
if (isPlaying) {
mPageVg.setVisibility(View.GONE);
mButtonListView.setVisibility(View.VISIBLE);
mInputRl.setVisibility(View.GONE);
mTitleTv.setTextColor(Color.WHITE);
mBackBtn.setImageResource(R.drawable.ic_av_live_actionbar_close);
} else {
mPageVg.setVisibility(View.VISIBLE);
mButtonListView.setVisibility(View.GONE);
mInputRl.setVisibility(View.VISIBLE);
mTitleTv.setTextColor(ContextCompat.getColor(this, R.color.border_infrared));
mBackBtn.setImageResource(R.drawable.ic_av_live_action_bar_black_back);
}
}
}

View File

@@ -0,0 +1,71 @@
package com.alivc.live.baselive_pull.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.alivc.live.baselive_pull.R;
import com.alivc.live.commonutils.DensityUtil;
/**
* 设置最大高度的Layout
*/
public class MaxHeightLayout extends LinearLayout {
private float mMaxRatio = 0.75f;
private float mMaxHeight;
private float mMinHeight;
public MaxHeightLayout(Context context) {
super(context);
init();
}
public MaxHeightLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initAtts(context, attrs);
init();
}
public MaxHeightLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAtts(context, attrs);
init();
}
private void initAtts(Context context, AttributeSet attrs){
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.mMaxRatio);
if (attributes != null) {
mMaxRatio = attributes.getFloat(R.styleable.mMaxRatio_linear_max_ratio, 0.75f);
attributes.recycle();
}
}
private void init() {
mMaxHeight = mMaxRatio * DensityUtil.getDisplayMetrics(getContext()).heightPixels;
mMinHeight = DensityUtil.dip2px(getContext(), 125);
mMaxHeight = mMaxHeight < mMinHeight ? mMinHeight : mMaxHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode == MeasureSpec.EXACTLY) {
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
}
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
}
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = heightSize <= mMaxHeight ? heightSize : (int) mMaxHeight;
}
int maxHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
super.onMeasure(widthMeasureSpec, maxHeightMeasureSpec);
}
}

View File

@@ -0,0 +1,105 @@
package com.alivc.live.baselive_pull.ui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.alivc.live.baselive_pull.R;
import com.alivc.live.baselive_pull.adapter.PlayButtonListAdapter;
import com.alivc.live.baselive_pull.listener.ButtonClickListener;
import java.util.List;
/**
* 底部按钮
*
* @author xlx
*/
public class PlayButtonListView extends FrameLayout {
private RecyclerView mRecyclerView;
private PlayButtonListAdapter mButtonListAdapter;
private ButtonClickListener clickListener;
private boolean isItemsHide = false;
public void setClickListener(ButtonClickListener clickListener) {
this.clickListener = clickListener;
}
public PlayButtonListView(@NonNull Context context) {
this(context, null);
}
public PlayButtonListView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PlayButtonListView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
public void setData(List<String> data) {
mButtonListAdapter.setData(data);
}
public void hideItems(boolean isItemHide) {
this.isItemsHide = isItemHide;
mButtonListAdapter.hideItems(isItemHide);
if (isItemHide) {
this.setVisibility(INVISIBLE);
} else {
this.setVisibility(VISIBLE);
}
}
public boolean isItemsHide() {
return isItemsHide;
}
private void initView(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.live_button_list, this, true);
initRecyclerView(view);
}
private void initRecyclerView(View view) {
mRecyclerView = view.findViewById(R.id.live_button_recycle);
mButtonListAdapter = new PlayButtonListAdapter();
LinearLayoutManager manager = new LinearLayoutManager(PlayButtonListView.this.getContext());
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mButtonListAdapter);
mRecyclerView.addItemDecoration(new SpaceItemDecortation(dip2px(getContext(), 28), getContext()));
mRecyclerView.setItemAnimator(null);
mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
mButtonListAdapter.setClickListener(new ButtonClickListener() {
@Override
public void onButtonClick(String message, int position) {
if (clickListener != null) {
clickListener.onButtonClick(message, position);
}
}
});
}
/**
* 将dip或dp值转换为px值保证尺寸大小不变
*
* @param dipValue
* @param dipValue DisplayMetrics类中属性density
* @return
*/
private static int dip2px(Context context, float dipValue) {
if (context == null || context.getResources() == null)
return 1;
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}

View File

@@ -0,0 +1,41 @@
package com.alivc.live.baselive_pull.ui.widget;
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
class SpaceItemDecortation extends RecyclerView.ItemDecoration {
private int space;//声明间距 //使用构造函数定义间距
private Context mContext;
public SpaceItemDecortation(int space, Context context) {
this.space = space;
this.mContext = context;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
//获得当前item的位置
int position = parent.getChildAdapterPosition(view);
if (position == 0) {
outRect.left = dip2px(mContext, 28);
}
outRect.right = this.space;
}
/**
* 将dip或dp值转换为px值保证尺寸大小不变
*
* @param dipValue
* @param dipValue DisplayMetrics类中属性density
* @return
*/
private static int dip2px(Context context, float dipValue) {
if (context == null || context.getResources() == null)
return 1;
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="20dp"/>
<stroke android:color="#4DCFE1"
android:width="1px"/>
<solid android:color="#4DCFE1"/>
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="20dp"/>
<stroke android:color="@color/color_background_black_alpha_30"
android:width="1px"/>
<solid android:color="@color/color_background_black_alpha_30"/>
</shape>

View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<ImageView
android:id="@+id/page_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/colour_bg" />
<ImageView
android:id="@+id/pull_common_btn_close"
android:layout_width="26dp"
android:layout_height="44dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="33dp"
android:contentDescription="@null"
android:scaleType="centerInside"
android:src="@drawable/ic_av_live_action_bar_black_back" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="33dp"
android:gravity="center"
android:text="@string/pull_rtc_enter_name_tv"
android:textColor="#23262F"
android:textSize="17sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginTop="77dp"
android:background="#23262F" />
<RelativeLayout
android:id="@+id/input_rl"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_size_36"
android:layout_marginLeft="20dp"
android:layout_marginTop="107dp"
android:layout_marginRight="20dp"
android:background="@drawable/shape_bg_search">
<Button
android:id="@+id/player_scan_image"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/view_margin_18"
android:background="@drawable/ic_live_scan" />
<View
android:id="@+id/pull_common_slipt_line"
android:layout_width="1px"
android:layout_height="19dp"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginEnd="10dp"
android:layout_toRightOf="@id/player_scan_image"
android:background="#40ffffff" />
<EditText
android:id="@+id/pull_common_push_url"
android:layout_width="match_parent"
android:layout_height="@dimen/view_margin_22"
android:layout_centerVertical="true"
android:layout_marginEnd="80dp"
android:layout_toRightOf="@id/pull_common_slipt_line"
android:background="@null"
android:hint="@string/view_string_hint_pull_url"
android:singleLine="true"
android:textColor="@color/wheel_white"
android:textColorHint="@color/wheel_white"
android:textSize="@dimen/view_size_text_17" />
<Button
android:id="@+id/pull_common_start_btn"
android:layout_width="@dimen/view_width_size_64"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="@drawable/shape_bg_btn_green"
android:text="@string/live_pull"
android:textColor="@color/color_title_text_black"
android:textSize="@dimen/view_size_text_17" />
</RelativeLayout>
<com.alivc.live.baselive_pull.ui.widget.PlayButtonListView
android:id="@+id/live_buttonlistview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="36dp" />
<com.alivc.live.commonui.messageview.AutoScrollMessagesView
android:id="@+id/sei_receive_view"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="100dp"
android:padding="10dp" />
</FrameLayout>

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:background="#80000000">
<com.alivc.live.baselive_pull.ui.widget.MaxHeightLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:layout_weight="1"
android:background="@drawable/live_dialog_bg"
android:minHeight="125dp"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="20dp" />
<TextView
android:id="@+id/dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="#FCFCFD"
android:textSize="18sp"
android:visibility="gone"
tools:text="18dp大标题"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/dialog_content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="9dp"
android:layout_marginRight="30dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<FrameLayout
android:id="@+id/dialog_content_container2"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/dialog_content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:scrollbars="none">
<!-- 解决内部滑动问题 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/dialog_tip_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:includeFontPadding="false"
android:lineSpacingExtra="3dp"
android:textColor="#FCFCFD"
android:textSize="14sp"
tools:text="14dp提示内容" />
</LinearLayout>
</ScrollView>
</FrameLayout>
<FrameLayout
android:id="@+id/dialog_expand_content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
<View
android:id="@+id/dialog_btn_top_line"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="30dp"
android:background="#3A3D48"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/dialog_cancel_btn"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:includeFontPadding="false"
android:singleLine="true"
android:text="取消"
android:textColor="#4DCFE1"
android:textSize="18sp"
android:visibility="gone"
tools:visibility="visible" />
<View
android:id="@+id/dialog_btn_line"
android:layout_width="0.5dp"
android:layout_height="52dp"
android:background="#3A3D48"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/dialog_confirm_btn"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:includeFontPadding="false"
android:singleLine="true"
android:text="确定"
android:textColor="#4DCFE1"
android:textSize="18sp"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>
<!-- 解决弹窗中心点与屏幕高度45%的位置重合 -->
<View
android:id="@+id/dialog_bottom_space"
android:layout_width="match_parent"
android:layout_height="30dp" />
</com.alivc.live.baselive_pull.ui.widget.MaxHeightLayout>
</FrameLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/live_button_recycle"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/iv_anchor"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_gravity="center"
android:src="@drawable/live_carmer"/>
<TextView
android:id="@+id/tv_anchor_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:textColor="@color/color_text_white"
android:textSize="10sp"
android:layout_gravity="center"
android:text="1212"
android:gravity="center"
/>
</LinearLayout>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_rtc_enter_name_tv">Live Streaming</string>
<string name="view_string_hint_pull_url">Enter the source URL.</string>
<string name="pull_restart">Retry</string>
</resources>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_rtc_enter_name_tv">拉流播放</string>
<string name="pull_rtc_enter_name_desc">支持常见协议如FLV、RTMP、HLS、RTS等</string>
<string name="view_string_hint_pull_url">请输入拉流url</string>
<string name="pull_restart">重试</string>
<string name="live_pull">拉流</string>
<string name="live_pull_addr_error">拉流地址错误,请检查后重新输入</string>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pull_rtc_enter_name_tv">Live Streaming</string>
<string name="pull_rtc_enter_name_desc">Common protocols are supported, such as FLV, RTMP, HLS, and RTS.</string>
<string name="view_string_hint_pull_url">Enter the source URL.</string>
<string name="pull_restart">Retry</string>
<string name="live_pull">Pull</string>
<string name="live_pull_addr_error"> Pull address error, please check and re-enter </string>
</resources>