修改名称。

This commit is contained in:
2025-11-07 09:22:39 +08:00
parent d9cf55b053
commit a8dcfbb6a7
2203 changed files with 3 additions and 4 deletions

View File

@@ -0,0 +1,13 @@
package com.xscm.moduleutil.rtc;
import lombok.Data;
/**
*@author qx
*@data 2025/9/18
*@description: 加入声网返回
*/
@Data
public class AgoraIsOPen {
private boolean isOpen;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,353 @@
package com.xscm.moduleutil.rtc;
import android.content.Context;
import android.util.Log;
import android.view.SurfaceView;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.xscm.moduleutil.base.CommonAppContext;
import com.xscm.moduleutil.event.ColoseCardEvent;
import com.xscm.moduleutil.event.SurfaceEvent;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import com.xscm.moduleutil.utils.SpUtil;
import org.greenrobot.eventbus.EventBus;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import io.agora.musiccontentcenter.IAgoraMusicContentCenter;
import io.agora.musiccontentcenter.IAgoraMusicPlayer;
import io.agora.musiccontentcenter.Music;
import io.agora.musiccontentcenter.MusicContentCenterConfiguration;
import io.agora.rtc2.ChannelMediaOptions;
import io.agora.rtc2.Constants;
import io.agora.rtc2.IRtcEngineEventHandler;
import io.agora.rtc2.RtcConnection;
import io.agora.rtc2.RtcEngineEx;
import io.agora.rtc2.video.VideoCanvas;
/**
* com.xscm.moduleutil.rtc
* qx
* 2025/10/29
*/
public class AgoraManagerEx {
private static volatile AgoraManagerEx instance;
private static RtcEngineEx rtcEngineEx;
// private RtcEngineEx rtcEngineEx;
private static Context context;
private boolean isLocalAudioEnabled = true; // 默认开启麦克风
// private final List<IRtcEngineEventHandler> eventHandlers = new ArrayList<>();
private static IAgoraMusicContentCenter musicContentCenter;
private static IAgoraMusicPlayer musicPlayer;
private static MusicContentCenterConfiguration contentCenterConfiguration;
private static String mRoomId = "";
private static long mSongCode;
private static List<Music> musicList;
private static boolean isBjMusic = false;
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private static ChannelMediaOptions options;
private static RtcConnection connection;
private String pkRoomId = "";
private static String lastRoomId;
public int pkUserId;
public int getPkUserId() {
return pkUserId;
}
public void setPkUserId(int pkUserId) {
this.pkUserId = pkUserId;
}
private static boolean isOnJoin = false;
public void setLastRoomId(String value) {
lastRoomId = value;
}
public String getLastRoomId() {
LogUtils.e("上次的房间id:" + lastRoomId);
return lastRoomId;
}
private AgoraManagerEx() {
}
public static AgoraManagerEx getInstance(Context con) {
if (instance == null) {
synchronized (AgoraManagerEx.class) {
if (instance == null) {
instance = new AgoraManagerEx();
context = con.getApplicationContext(); // 使用ApplicationContext避免内存泄漏
}
}
}
// 确保引擎已初始化
if (rtcEngineEx == null) {
synchronized (AgoraManagerEx.class) {
if (rtcEngineEx == null) {
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
}
}
}
return instance;
}
public static void init(String appId) {
if (rtcEngineEx != null) {
return;
};
synchronized (AgoraManager.class) {
if (rtcEngineEx != null) {
return;
}
rtcEngineEx =AgoraManager.getInstance( context).rtcEngine;
// try {
// RtcEngineConfig config = new RtcEngineConfig();
// config.mContext = context;
// config.mAppId = appId;
// config.mEventHandler = getDefaultEventHandler();
// config.mChannelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
// config.mAudioScenario = Constants.AUDIO_SCENARIO_CHORUS;
// config.mAreaCode = 1;
//
// rtcEngineEx = (RtcEngineEx) RtcEngineEx.create(config);
// } catch (Exception e) {
// Log.e("AgoraManager", "Failed to create RtcEngine", e);
// return;
// }
//
// if (rtcEngineEx != null) {
// try {
// rtcEngineEx.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
// Constants.AUDIO_SCENARIO_GAME_STREAMING);
// rtcEngineEx.enableAudioVolumeIndication(200, 3, true);
// rtcEngineEx.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
// rtcEngineEx.muteLocalAudioStream(true); // 默认静音
// rtcEngineEx.muteAllRemoteAudioStreams(false); // 监听远端的音频
//
// // 设置参数时添加异常处理
// try {
// rtcEngineEx.setParameters("{\"che.audio.custom_payload_type\":73}");
// rtcEngineEx.setParameters("{\"che.audio.custom_bitrate\":128000}");
// rtcEngineEx.setParameters("{\"rtc.enable_nasa2\": true}");
// rtcEngineEx.setParameters("{\"rtc.use_audio4\": true}");
// rtcEngineEx.setParameters("{" +
// "\"rtc.report_app_scenario\":" +
// "{" +
// "\"appScenario\":" + 100 + "," +
// "\"serviceType\":" + 11 + "," +
// "\"appVersion\":\"" + rtcEngineEx.getSdkVersion() + "\"" +
// "}" +
// "}");
// rtcEngineEx.setParameters("{\"che.video.mobile_1080p\":true}");
// } catch (Exception e) {
// Log.w("AgoraManager", "Failed to set parameters", e);
// }
// /*Enable video module*/
// rtcEngineEx.enableVideo();
// /*Set up to play remote sound with receiver*/
// rtcEngineEx.setDefaultAudioRoutetoSpeakerphone(true);
//
// } catch (Exception e) {
// Log.e("AgoraManager", "Failed to configure rtcEngineEx", e);
// }
// }
}
}
private static IRtcEngineEventHandler getDefaultEventHandler() {
return new IRtcEngineEventHandler() {
@Override
public void onRemoteAudioStateChanged(int uid, int state, int reason, int elapsed) {
super.onRemoteAudioStateChanged(uid, state, reason, elapsed);
LogUtils.e("onRemoteAudioStateChanged", "uid------>" + uid, "state------>" + state, "reason------>" + reason, "elapsed------>" + elapsed);
}
@Override
public void onUserMuteAudio(int uid, boolean muted) {
super.onUserMuteAudio(uid, muted);
LogUtils.e("onUserMuteAudio", "uid------>" + uid, "muted------>" + muted);
}
@Override
public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
LogUtils.e("onJoinChannelSuccess", "channel------>" + channel, "uid------>" + uid, "elapsed------>" + elapsed);
if (!isOnJoin) {
AgoraIsOPen isOPen = new AgoraIsOPen();
isOPen.setOpen(true);
EventBus.getDefault().post(isOPen);
isOnJoin = true;
}
}
@Override
public void onUserJoined(int uid, int elapsed) {//远端用户加入频道
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
ThreadUtils.runOnUiThread(() -> {
// 远程用户音量变化
listener.userJoined(uid, elapsed);
// }
});
}
}
}
@Override
public void onUserOffline(int uid, int reason) {//远端用户离开频道
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
ThreadUtils.runOnUiThread(() -> {
// 远程用户音量变化
listener.userOffline(uid, reason);
// }
});
}
// }
}
}
@Override
public void onAudioVolumeIndication(AudioVolumeInfo[] speakers, int totalVolume) {
super.onAudioVolumeIndication(speakers, totalVolume);
if (speakers == null || speakers.length == 0) return;
for (final AudioVolumeInfo info : speakers) {
final int uid = info.uid;
final int volume = info.volume;
// 回调所有监听器
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
ThreadUtils.runOnUiThread(() -> {
// 远程用户音量变化
listener.onRemoteSoundLevelUpdate(uid > 0 ? String.valueOf(uid) : SpUtil.getUserId() + "", volume);
// }
});
}
}
}
}
@Override
public void onLocalVideoStateChanged(Constants.VideoSourceType source, int state, int reason) {
super.onLocalVideoStateChanged(source, state, reason);
if (state == Constants.LOCAL_VIDEO_STREAM_STATE_CAPTURING && source.getValue() == Constants.VIDEO_SOURCE_SCREEN_PRIMARY) {
options.publishScreenCaptureAudio = true;
options.publishScreenCaptureVideo = true;
options.publishCameraTrack = false;
rtcEngineEx.updateChannelMediaOptions(options);
}
}
@Override
public void onFirstRemoteAudioFrame(int uid, int elapsed) {
super.onFirstRemoteAudioFrame(uid, elapsed);
Log.i("RoomCabinFragment", "onFirstRemoteAudioFrame: uid->" + uid);
}
// 可继续扩展其他回调...
@Override
public void onFirstRemoteVideoFrame(int uid, int width, int height, int elapsed) {
super.onFirstRemoteVideoFrame(uid, width, height, elapsed);
SurfaceView renderView = new SurfaceView(context);
SurfaceEvent surfaceEvent = new SurfaceEvent();
surfaceEvent.setSurfaceView(renderView);
surfaceEvent.setType(2);
rtcEngineEx.setupRemoteVideo(new VideoCanvas(renderView, Constants.RENDER_MODE_FIT, uid));
EventBus.getDefault().post(surfaceEvent);
}
@Override
public void onRemoteVideoStateChanged(int uid, int state, int reason, int elapsed) {
super.onRemoteVideoStateChanged(uid, state, reason, elapsed);
Log.i("RoomCabinFragment", "onRemoteVideoStateChanged:uid->" + uid + ", state->" + state);
if (state == Constants.REMOTE_AUDIO_STATE_STOPPED) {
ColoseCardEvent renderView = new ColoseCardEvent();
EventBus.getDefault().post(renderView);
} else if (state == Constants.REMOTE_AUDIO_STATE_STARTING) {
SurfaceView renderView = new SurfaceView(context);
rtcEngineEx.setupRemoteVideo(new VideoCanvas(renderView, Constants.RENDER_MODE_FIT, uid));
SurfaceEvent surfaceEvent = new SurfaceEvent();
surfaceEvent.setSurfaceView(renderView);
surfaceEvent.setType(2);
EventBus.getDefault().post(surfaceEvent);
}
}
@Override
public void onError(int err) {
super.onError(err);
}
};
}
public void joinChannelEx(String token, String channelId, String pkUserIds) {
if (rtcEngineEx != null) {
options = new ChannelMediaOptions();
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
options.publishMicrophoneTrack = true; // 是否发布麦克风音频
options.enableAudioRecordingOrPlayout = true;
options.autoSubscribeAudio = true;
connection = new RtcConnection();
connection.channelId = channelId;
connection.localUid = SpUtil.getUserId();
pkRoomId = channelId;
pkUserId = Integer.parseInt(pkUserIds);
rtcEngineEx.joinChannelEx(token, connection, options, getDefaultEventHandler());
muteAllRemoteAudioStreamsEx(true);
muteAllRemoteAudioStreamsExUserId(false);
}
}
public void muteAllRemoteAudioStreamsEx(boolean enabled) {
if (rtcEngineEx == null) {
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
}
if (rtcEngineEx != null) {
rtcEngineEx.muteAllRemoteAudioStreamsEx(enabled, connection);
}
}
public void muteLocalAudioStreamEx(boolean enabled) {
if (rtcEngineEx == null) {
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
}
// 正确做法
rtcEngineEx.muteLocalAudioStreamEx(enabled, connection);
}
public void muteAllRemoteAudioStreamsExUserId(boolean enabled){
if (rtcEngineEx != null){
rtcEngineEx.muteRemoteAudioStreamEx(pkUserId,enabled,connection);
}
}
public void leaveChannelEx(String mRoomId, int uid) {
if (rtcEngineEx != null) {
RtcConnection connection = new RtcConnection();
connection.channelId = mRoomId;
connection.localUid = uid;
rtcEngineEx.leaveChannelEx(connection);
}
}
}

View File

@@ -0,0 +1,22 @@
package com.xscm.moduleutil.rtc;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.Nullable;
/**
* @Author lxj$
* @Time $ $
* @Description $
*/
public class MeForegroundService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View File

@@ -0,0 +1,12 @@
package com.xscm.moduleutil.rtc;
import java.util.List;
import io.agora.musiccontentcenter.Music;
import lombok.Data;
@Data
public class MusicBean {
private List<Music> musicList;
private int page;
}

View File

@@ -0,0 +1,8 @@
package com.xscm.moduleutil.rtc;
import lombok.Data;
@Data
public class MusicFileBean {
private byte[] fileData ;
}

View File

@@ -0,0 +1,8 @@
package com.xscm.moduleutil.rtc;
import lombok.Data;
@Data
public class MusicPlayBean {
private long position;
}

View File

@@ -0,0 +1,111 @@
package com.xscm.moduleutil.rtc;
import com.blankj.utilcode.util.ObjectUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import com.xscm.moduleutil.utils.SpUtil;
import java.util.List;
import io.agora.rtc2.Constants;
import io.agora.rtc2.IRtcEngineEventHandler;
public class MyIRtcEngineEventHandler extends IRtcEngineEventHandler {
private RtcEventListener mRtcEventListener;
private List<SoundLevelUpdateListener> soundLevelUpdateListeners;
public MyIRtcEngineEventHandler(RtcEventListener mRtcEventListener) {
this.mRtcEventListener = mRtcEventListener;
}
public MyIRtcEngineEventHandler(RtcEventListener mRtcEventListener,List<SoundLevelUpdateListener> soundLevelUpdateListeners) {
this.soundLevelUpdateListeners = soundLevelUpdateListeners;
this.mRtcEventListener = mRtcEventListener;
}
/**
* 连接状态
*
* @param state
* @param reason
*/
@Override
public void onConnectionStateChanged(final int state, int reason) {
try {
if (mRtcEventListener != null) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
switch (state) {
case Constants.CONNECTION_STATE_CONNECTED:
mRtcEventListener.onRoomConnected();
break;
case Constants.CONNECTION_STATE_DISCONNECTED:
mRtcEventListener.onRoomDisConnect();
break;
case Constants.CONNECTION_STATE_CONNECTING:
mRtcEventListener.onRoomconnecting();
break;
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 声浪
*
* @param speakers
* @param totalVolume
*/
@Override
public void onAudioVolumeIndication(AudioVolumeInfo[] speakers, int totalVolume) {
for (final AudioVolumeInfo info : speakers) {
if (mRtcEventListener != null)
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mRtcEventListener.onRemoteSoundLevelUpdate(String.valueOf(info.uid), info.volume);
}
});
if (!ObjectUtils.isEmpty(soundLevelUpdateListeners)) {
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) {
listener.onRemoteSoundLevelUpdate(info.uid > 0 ? String.valueOf(info.uid) : SpUtil.getUserId()+"", info.volume);
}
}
}
}
}
@Override
public void onAudioMixingStateChanged(final int state, int errorCode) {
if (mRtcEventListener != null) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
switch (state) {
case 3:
mRtcEventListener.playIng();
break;
case 1:
mRtcEventListener.pausIng();
break;
case 2:
mRtcEventListener.playEnded();
break;
}
}
});
}
}
}

View File

@@ -0,0 +1,114 @@
package com.xscm.moduleutil.rtc;
import com.xscm.moduleutil.bean.room.Config;
public interface Rtc {
/**
* 初始化
*
* @param rtcType rtc类型
* @param scenariosType 应用场景
*/
void init(int rtcType, int scenariosType, Config config);
/**
* 进入房间
*
* @param roomId
* @param userId
* @param userName
* @param token
*/
void loginRoom(String roomId, String userId, String userName, String token);
/**
* 离开房间
*/
void leaveChannel(String roomId);
/**
* 设置变声
*
* @param type
*/
// void setTone(int type);
/**
* 是否开启耳返
*
* @param b
*/
void enableHeadphoneMonitor(boolean b);
/**
* 设置耳返音量
*
* @param volume
*/
void setHeadphoneMonitorVolume(int volume);
/**
* 设置音乐播放音量
* @param volume
*/
void setAudioMixingVolume(int volume);
/**
* 播放音乐
*
* @param url
*/
void startAudioMixing(String url);
/**
* 停止播放音乐
*/
void stopAudioMixing();
/**
* 暂停音乐播放
*/
void pauseAudioMixing();
/**
* 恢复播放
*/
void resumeAudioMixing();
/**
* 上麦
*
* @param streamID
*/
void applyWheat(String streamID);
/**
* 下麦
*/
void downWheat();
/**
* 开麦,闭麦
*
* @param b
*/
void muteLocalAudioStream(boolean b);
/**
* 设备静音
*/
void muteSpeaker(boolean b);
}

View File

@@ -0,0 +1,30 @@
package com.xscm.moduleutil.rtc;
public class RtcConstants {
public static final int RtcType_AGORA = 1;//声网
public static final int RtcType_ZEGO = 2;//zego
public static final int RtcType_CURR = 2;//当前使用的SDK类型
public static final int SCENARIOSTYPE_TALKING = 1;//语聊
public static final int SCENARIOSTYPE_SING = 2;//唱歌
public static final int SCENARIOSTYPE_GAME = 0;//游戏
public static final int SOUNDEFFECTTYPE_NONE = 0; //默认原声
public static final int AUDIO_EFFECT_OFF = 1;//原唱
public static final int AUDIO_EFFECT_CPJ = 2;//唱片机
public static final int AUDIO_EFFECT_3W = 3;//3维声音
public static final int AUDIO_EFFECT_XN = 4;//虚拟环绕
public static final int AUDIO_EFFECT_KTV = 5;//ktv
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE1 = 6;//萝莉
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE2 = 7;//大叔
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE3 = 8;//绿巨人
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE4 = 9;//大堂
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE5 = 10;//山谷
public static final int SOUNDEFFECTTYPE_CHANGE_VOICE6 = 6;//山谷
}

View File

@@ -0,0 +1,345 @@
package com.xscm.moduleutil.rtc;
import android.content.Context;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import com.xscm.moduleutil.utils.SpUtil;
import com.tencent.liteav.base.Log;
import com.tencent.liteav.base.ThreadUtils;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import io.agora.karaoke_view.v11.downloader.LyricsFileDownloader;
import io.agora.mediaplayer.IMediaPlayerObserver;
import io.agora.mediaplayer.data.CacheStatistics;
import io.agora.mediaplayer.data.PlayerPlaybackStats;
import io.agora.mediaplayer.data.PlayerUpdatedInfo;
import io.agora.mediaplayer.data.SrcInfo;
import io.agora.musiccontentcenter.IAgoraMusicContentCenter;
import io.agora.musiccontentcenter.IAgoraMusicPlayer;
import io.agora.musiccontentcenter.IMusicContentCenterEventHandler;
import io.agora.musiccontentcenter.Music;
import io.agora.musiccontentcenter.MusicChartInfo;
import io.agora.musiccontentcenter.MusicContentCenterConfiguration;
import io.agora.rtc2.ChannelMediaOptions;
import io.agora.rtc2.Constants;
import io.agora.rtc2.IRtcEngineEventHandler;
import io.agora.rtc2.RtcEngine;
import io.agora.rtc2.RtcEngineConfig;
public class RtcCore {
private static volatile RtcCore instance;
private RtcEngine rtcEngine;
private Context context;
// 音乐相关
private IAgoraMusicContentCenter musicContentCenter;
private IAgoraMusicPlayer musicPlayer;
private long mSongCode;
// 麦克风状态
private boolean isLocalAudioEnabled = true;
// 音量监听器
private final List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private RtcCore(Context context) {
this.context = context.getApplicationContext();
}
public static RtcCore getInstance(Context context) {
if (instance == null) {
synchronized (RtcCore.class) {
if (instance == null) {
instance = new RtcCore(context);
}
}
}
return instance;
}
/**
* 1. 初始化 Agora 引擎
*/
public void initAgora(String appId) {
try {
RtcEngineConfig config = new RtcEngineConfig();
config.mContext = context;
config.mAppId = appId;
config.mEventHandler = getEventHandler();
config.mChannelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
config.mAudioScenario = Constants.AUDIO_SCENARIO_GAME_STREAMING;
rtcEngine = RtcEngine.create(config);
if (rtcEngine != null) {
rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_STANDARD_STEREO, Constants.AUDIO_SCENARIO_GAME_STREAMING);
rtcEngine.enableAudioVolumeIndication(200, 3, true); // 启用声浪检测
rtcEngine.enableLocalAudio(true);
rtcEngine.muteLocalAudioStream(false);
rtcEngine.setParameters("{\"che.audio.custom_payload_type\":73}");
rtcEngine.setParameters("{\"che.audio.custom_bitrate\":128000}");
rtcEngine.setParameters("{\"rtc.enable_nasa2\": true}");
rtcEngine.setParameters("{\"rtc.use_audio4\": true}");
}
} catch (Exception e) {
Log.e("RtcCore", "初始化失败", e);
}
}
/**
* 2. 加入房间
*/
public void joinRoom(String token, String roomId, int uid, boolean isMicrophoneEnabled) {
if (rtcEngine == null) return;
ChannelMediaOptions options = new ChannelMediaOptions();
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
options.publishMicrophoneTrack = isMicrophoneEnabled;
options.autoSubscribeAudio = true;
rtcEngine.joinChannel(token, roomId, uid, options);
setLocalAudioEnabled(isMicrophoneEnabled);
}
/**
* 3. 离开房间
*/
public void leaveRoom() {
if (rtcEngine != null) {
rtcEngine.leaveChannel();
}
}
/**
* 4. 播放背景音乐
*/
public void playBackgroundMusic(long songCode) {
if (musicContentCenter == null) {
musicContentCenter = IAgoraMusicContentCenter.create(rtcEngine);
}
if (musicPlayer == null) {
musicPlayer = musicContentCenter.createMusicPlayer();
}
MusicContentCenterConfiguration config = new MusicContentCenterConfiguration();
config.appId = "your_app_id";
config.mccUid = 123456;
config.token = SpUtil.getRtmToken();
config.eventHandler = getMusicEventHandler();
musicContentCenter.initialize(config);
musicPlayer.registerPlayerObserver(getMediaPlayerObserver());
musicPlayer.open(songCode, 0);
musicPlayer.play();
}
/**
* 5. KTV 功能:预加载歌曲并播放
*/
public void preloadAndPlaySong(long songCode) {
if (musicContentCenter == null || musicPlayer == null) return;
int code = musicContentCenter.isPreloaded(songCode);
if (code < 0) {
new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> {
musicContentCenter.preload(songCode);
preloadAndPlaySong(songCode);
}, 3000);
} else {
musicPlayer.open(songCode, 0);
musicPlayer.play();
}
}
/**
* 6. 声浪检测回调注册
*/
public void addSoundLevelListener(SoundLevelUpdateListener listener) {
if (listener != null && !soundLevelUpdateListeners.contains(listener)) {
soundLevelUpdateListeners.add(listener);
}
}
public void removeSoundLevelListener(SoundLevelUpdateListener listener) {
if (listener != null) {
soundLevelUpdateListeners.remove(listener);
}
}
/**
* 7. 设置麦克风开关
*/
public void setLocalAudioEnabled(boolean enabled) {
if (rtcEngine != null) {
rtcEngine.enableLocalAudio(enabled);
rtcEngine.muteLocalAudioStream(!enabled);
rtcEngine.setClientRole(enabled ? Constants.CLIENT_ROLE_BROADCASTER : Constants.CLIENT_ROLE_AUDIENCE);
isLocalAudioEnabled = enabled;
}
}
/**
* 设置远端音频静音
*/
public void muteRemoteAudio(boolean mute) {
if (rtcEngine != null) {
rtcEngine.muteAllRemoteAudioStreams(mute);
}
}
// -------------------------- 内部辅助方法 --------------------------
private IRtcEngineEventHandler getEventHandler() {
return new IRtcEngineEventHandler() {
@Override
public void onAudioVolumeIndication(AudioVolumeInfo[] speakers, int totalVolume) {
for (AudioVolumeInfo info : speakers) {
int uid = info.uid;
int volume = info.volume;
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
ThreadUtils.runOnUiThread(() -> {
// if (uid <= 0) {
// listener.onLocalSoundLevelUpdate(volume);
// } else {
listener.onRemoteSoundLevelUpdate(String.valueOf(uid), volume);
// }
});
}
}
}
};
}
private IMusicContentCenterEventHandler getMusicEventHandler() {
return new IMusicContentCenterEventHandler() {
@Override
public void onLyricResult(String requestId, long songCode, String lyricUrl, int errorCode) {
if (errorCode == 0 && lyricUrl != null) {
LyricsFileDownloader.getInstance(context).download(lyricUrl);
}
}
@Override
public void onSongSimpleInfoResult(String requestId, long songCode, String simpleInfo, int errorCode) {
}
@Override
public void onPreLoadEvent(String requestId, long songCode, int percent, String lyricUrl, int status, int errorCode) {
if (errorCode == 0 && percent == 100) {
LyricsFileDownloader.getInstance(context).download(lyricUrl);
}
}
@Override
public void onMusicCollectionResult(String requestId, int page, int pageSize, int total, Music[] list, int errorCode) {
}
@Override
public void onMusicChartsResult(String requestId, MusicChartInfo[] list, int errorCode) {
}
};
}
private IMediaPlayerObserver getMediaPlayerObserver() {
return new IMediaPlayerObserver() {
// @Override
// public void onPlayerStateChanged(io.agora.mediaplayer.Constants.MediaPlayerState state, io.agora.mediaplayer.Constants.MediaPlayerError error) {
// if (state == io.agora.mediaplayer.Constants.MediaPlayerState.PLAYER_STATE_OPEN_COMPLETED) {
// musicContentCenter.getLyric(mSongCode, 1);
// }
// }
@Override
public void onPlayerStateChanged(io.agora.mediaplayer.Constants.MediaPlayerState state, io.agora.mediaplayer.Constants.MediaPlayerReason reason) {
if (state == io.agora.mediaplayer.Constants.MediaPlayerState.PLAYER_STATE_OPEN_COMPLETED) {
musicContentCenter.getLyric(mSongCode, 1);
}
}
@Override
public void onPositionChanged(long positionMs, long timestampMs) {
// 可选:发送位置信息到 EventBus 或通知 UI
}
@Override
public void onPlayerEvent(io.agora.mediaplayer.Constants.MediaPlayerEvent eventCode, long elapsedTime, String message) {
}
@Override
public void onMetaData(io.agora.mediaplayer.Constants.MediaPlayerMetadataType type, byte[] data) {
}
@Override
public void onPlayBufferUpdated(long playCachedBuffer) {
}
@Override
public void onPreloadEvent(String src, io.agora.mediaplayer.Constants.MediaPlayerPreloadEvent event) {
}
@Override
public void onAgoraCDNTokenWillExpire() {
}
@Override
public void onPlayerSrcInfoChanged(SrcInfo from, SrcInfo to) {
}
@Override
public void onPlayerInfoUpdated(PlayerUpdatedInfo info) {
}
@Override
public void onPlayerCacheStats(CacheStatistics stats) {
}
@Override
public void onPlayerPlaybackStats(PlayerPlaybackStats stats) {
}
// @Override
// public void onPlayerPlaybackStats(PlayerPlaybackStats stats) {
//
// }
@Override
public void onAudioVolumeIndication(int volume) {
}
};
}
/**
* 销毁引擎
*/
public void destroy() {
if (musicPlayer != null) {
musicPlayer.destroy();
musicPlayer = null;
}
if (musicContentCenter != null) {
musicContentCenter.destroy();
musicContentCenter = null;
}
if (rtcEngine != null) {
rtcEngine.leaveChannel();
rtcEngine.destroy();
rtcEngine = null;
}
}
}

View File

@@ -0,0 +1,11 @@
package com.xscm.moduleutil.rtc;
/**
* @author xf
*/
public interface RtcDestroyCallback {
void onDestroySuccess();
}

View File

@@ -0,0 +1,50 @@
package com.xscm.moduleutil.rtc;
public interface RtcEventListener {
/**
* 断开连接
*/
void onRoomDisConnect();
/**
* 已连接
*/
void onRoomConnected();
/**
* 连接中
*/
void onRoomconnecting();
/**
* 远端拉流音频声浪回调
*/
void onRemoteSoundLevelUpdate(String streamID, int soundLevel);
/**
* 不在播放中
*/
void noPlay();
/**
* 暂停播放
*/
void pausIng();
/**
* 播放中
*/
void playIng();
/**
* 播放结束
*/
void playEnded();
void destroy();
}

View File

@@ -0,0 +1,413 @@
package com.xscm.moduleutil.rtc;
import static com.xscm.moduleutil.rtc.RtcConstants.SCENARIOSTYPE_GAME;
import android.app.Application;
import android.text.TextUtils;
import com.xscm.moduleutil.bean.room.Config;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import io.agora.rtc2.Constants;
import io.agora.rtc2.RtcEngine;
/**
* @author xf
*/
public class RtcManager implements Rtc {
private final static String TAG = "RTC";
// private String agoraAppId = CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId();
private Application mApplication;
private static RtcManager instance;
private static RtcEventListener mRtcEventListener;
private int mRtcType = -1;
private static RtcEngine mRtcEngine;
private int mScenariosType = -1;
private Config mConfig;
String mRoomId;
String mUserId;
String mUserName;
String mToken;
String mStreamID;
private boolean isGame;//是否游戏语音
private boolean muteMic = true;//麦克风状态,默认关闭
private String audioUrl;
private List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
public RtcManager(Application application) {
this.mApplication = application;
}
public void addRtcEventListener(RtcEventListener rtcEventListener) {
mRtcEventListener = rtcEventListener;
}
public static RtcManager instance(Application application) {
if (instance == null) {
synchronized (RtcManager.class) {
if (instance == null) {
instance = new RtcManager(application);
}
}
}
return instance;
}
public static RtcManager getInstance() {
return instance;
}
@Override
public void init(int rtcType, int scenariosType, Config config) {
this.mRtcType = rtcType;
if (rtcType == RtcConstants.RtcType_AGORA) {
initAgora(scenariosType);
}
mScenariosType = scenariosType;
mConfig = config;
}
@Override
public void loginRoom(String roomId, String userId, String userName, String token) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
//mRtcEngine.joinChannel(token, roomId, "Extra Optional Data", Integer.parseInt(userId));
mRtcEngine.joinChannel(token, roomId, "OpenVCall", Integer.parseInt(userId));
}
}
mRoomId = roomId;
mUserName = userName;
mUserId = userId;
mToken = token;
}
@Override
public void leaveChannel(String roomId) {
downWheat();
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.leaveChannel();
}
}
mRoomId = null;
setGame(false);
}
@Override
public void enableHeadphoneMonitor(boolean b) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.enableInEarMonitoring(b);
}
}
}
@Override
public void setHeadphoneMonitorVolume(int volume) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.setInEarMonitoringVolume(volume);
}
}
}
@Override
public void setAudioMixingVolume(int volume) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.adjustAudioMixingVolume(volume);
}
}
}
@Override
public void startAudioMixing(String url) {
this.audioUrl = url;
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.startAudioMixing(url, false, 1, 1);
}
}
}
@Override
public void stopAudioMixing() {
this.audioUrl = null;
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.stopAudioMixing();
}
}
}
@Override
public void pauseAudioMixing() {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.pauseAudioMixing();
}
}
}
@Override
public void resumeAudioMixing() {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.resumeAudioMixing();
}
}
}
@Override
public void applyWheat(String streamID) {
mStreamID = streamID;
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
mRtcEngine.enableLocalAudio(true);
mRtcEngine.muteLocalAudioStream(muteMic);
mRtcEngine.enableAudioVolumeIndication(1000, 3,true);//监听远端说话
}
}
}
@Override
public void downWheat() {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.setClientRole(Constants.CLIENT_ROLE_AUDIENCE);
mRtcEngine.enableLocalAudio(false);
mRtcEngine.muteLocalAudioStream(true);
}
}
mStreamID = "";
}
public void startPublishingStream() {
if (!TextUtils.isEmpty(mStreamID)) {
}
}
public void stopPublishingStream() {
}
@Override
public void muteLocalAudioStream(boolean b) {
this.muteMic = b;
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.muteLocalAudioStream(b);
}
}
}
public void muteMicWithNoNetwork(boolean b) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.muteLocalAudioStream(b);
}
}
}
@Override
public void muteSpeaker(boolean b) {
if (mRtcType == RtcConstants.RtcType_AGORA) {
if (mRtcEngine != null) {
mRtcEngine.muteAllRemoteAudioStreams(b);
}
}
}
private void initAgora(int scenariosType) {
try {
mRtcEngine = RtcEngine.create(mApplication, "4a521d6f1c6343998b1c8fd425dea02a", new MyIRtcEngineEventHandler(mRtcEventListener,soundLevelUpdateListeners));
} catch (Exception e) {
e.printStackTrace();
}
switch (scenariosType) {
case RtcConstants.SCENARIOSTYPE_SING:
mRtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO, Constants.AUDIO_SCENARIO_GAME_STREAMING);
break;
default:
mRtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_STANDARD_STEREO,
Constants.AUDIO_SCENARIO_GAME_STREAMING);
break;
}
mRtcEngine.enableLocalAudio(false);
mRtcEngine.muteLocalAudioStream(true);
}
public void destroy(final RtcDestroyCallback callback) {
if (mRtcEngine != null) {
RtcEngine.destroy();
mRtcEngine = null;
if (callback != null) {
callback.onDestroySuccess();
}
}
if (mRtcEngine == null ) {
if (callback != null) {
callback.onDestroySuccess();
}
}
}
/**
* 停止/开启声浪检测
*
* @param atWheat 停止 true 开启
*/
public void setSoundLevelMonitor(boolean atWheat) {
}
/**
* 上传即构日志
*/
public void uploadLog() {
}
public void removeRtcEventListener() {
mRtcEventListener = null;
}
/**
* 退出房閒
*/
public void leaveChannel() {
if (isGame && mRoomId != null) {
leaveChannel(mRoomId);
setAudioUrl(null);
}
}
public void loginRoom(final int rtcType, final int scenariosType, final Config config, final String roomId, final String userId, final String userName, final String token, RtcDestroyCallback rtcDestroyCallback) {
if (mRoomId != null && !mRoomId.equals(roomId)) {
destroyAndLogin(rtcType, scenariosType, config, roomId, userId, userName, token, rtcDestroyCallback);
return;
}
if (rtcType == mRtcType) {//sdk没切换
if (rtcType == RtcConstants.RtcType_AGORA) {
if (scenariosType == mScenariosType && mRtcEngine != null) {//场景没切换
//mRtcEngine.joinChannel(token, roomId, "Extra Optional Data", Integer.parseInt(userId));
mRtcEngine.joinChannel(token, roomId, "OpenVCall", Integer.parseInt(userId));
//加入房间先下麦操作 处理进入房间就开始音频推流问题
downWheat();
if (rtcDestroyCallback != null) {
rtcDestroyCallback.onDestroySuccess();
}
} else {//场景切换了
destroyAndLogin(rtcType, scenariosType, config, roomId, userId, userName, token, rtcDestroyCallback);
return;
}
}
} else {
destroyAndLogin(rtcType, scenariosType, config, roomId, userId, userName, token, rtcDestroyCallback);
return;
}
mRtcType = rtcType;
mScenariosType = scenariosType;
mConfig = config;
mRoomId = roomId;
mUserId = userId;
mUserName = userName;
mToken = token;
}
/**
* 销毁并加入房间
*
* @param rtcType
* @param scenariosType
* @param config
* @param roomId
* @param userId
* @param userName
* @param token
* @param rtcDestroyCallback
*/
public void destroyAndLogin(final int rtcType, final int scenariosType, final Config config, final String roomId, final String userId, final String userName, final String token, final RtcDestroyCallback rtcDestroyCallback) {
destroy(new RtcDestroyCallback() {
@Override
public void onDestroySuccess() {
init(rtcType, scenariosType, config);
loginRoom(roomId, userId, userName, token);
if (rtcDestroyCallback != null) {
rtcDestroyCallback.onDestroySuccess();
}
}
});
}
public void setGame(boolean game) {
isGame = game;
}
/**
* 登录H5小游戏
*
* @param roomId
* @param userId
* @param userName
* @param token
*/
public void loginRoomGame(String roomId, String userId, String userName, String token) {
if (mRtcEngine != null ) {
loginRoom(roomId, userId, userName, token);
} else {
destroyAndLogin(RtcConstants.RtcType_CURR, SCENARIOSTYPE_GAME, null, roomId, userId, userName, token, null);
}
setGame(true);
}
/**
* 恢复麦克风状态
*/
public void resumeMic() {
muteLocalAudioStream(muteMic);
}
public void resumeAudio() {
if (!TextUtils.isEmpty(audioUrl)) {
startAudioMixing(audioUrl);
}
}
public void setAudioUrl(String audioUrl) {
this.audioUrl = audioUrl;
}
public boolean isMuteMic() {
return muteMic;
}
public void addSoundLevelListener(SoundLevelUpdateListener listener) {
if (soundLevelUpdateListeners != null) {
soundLevelUpdateListeners.add(listener);
}
}
public void removeSoundLevelListener(SoundLevelUpdateListener listener) {
if (soundLevelUpdateListeners != null) {
soundLevelUpdateListeners.remove(listener);
}
}
}

View File

@@ -0,0 +1,37 @@
package com.xscm.moduleutil.rtc;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import java.util.List;
import io.agora.musiccontentcenter.Music;
public class SharedViewModel extends AndroidViewModel {
private MutableLiveData<List<Music>> musicList = new MutableLiveData<>();
private MusicBean musicBean=new MusicBean();
public SharedViewModel(@NonNull Application application) {
super(application);
}
public LiveData<List<Music>> getMusicList() {
return musicList;
}
public void setMusicList(List<Music> list) {
musicList.postValue(list);
}
public MusicBean getMusicBean() {
return musicBean;
}
public void setMusicBean(MusicBean musicBean) {
this.musicBean = musicBean;
}
}

View File

@@ -0,0 +1,77 @@
package com.xscm.moduleutil.rtc;
import java.util.HashMap;
import java.util.Map;
/**
* com.xscm.moduleutil.rtc
* qx
* 2025/11/3
* 声网声音管理类
*/
public class VolumeManager {
private static VolumeManager instance;
private Map<String, Integer> userMusicVolumeMap = new HashMap<>();
private Map<String, Integer> userPlayoutVolumeMap = new HashMap<>();
private Map<String, Boolean> userPlayoutBzMap = new HashMap<>();
private String currentUserId;
private VolumeManager() {}
public static VolumeManager getInstance() {
if (instance == null) {
synchronized (VolumeManager.class) {
if (instance == null) {
instance = new VolumeManager();
}
}
}
return instance;
}
public void setCurrentUserId(String userId) {
this.currentUserId = userId;
}
public void saveCurrentVolumes(int musicVolume, int playoutVolume) {
if (currentUserId != null) {
userMusicVolumeMap.put(currentUserId, musicVolume);
userPlayoutVolumeMap.put(currentUserId, playoutVolume);
}
}
public void clearCurrentVolumes() {
if (currentUserId != null) {
userMusicVolumeMap.remove(currentUserId);
userPlayoutVolumeMap.remove(currentUserId);
}
userPlayoutBzMap.clear();
}
public void saveBz(String userId, boolean bz){
userPlayoutBzMap.clear();
userPlayoutBzMap.put(userId, bz);
}
public boolean getBz(String userId){
Boolean bz = userPlayoutBzMap.get(userId);
if (bz == null) {
bz = true; // 默认值原唱 false 伴奏
}
return bz;
}
public int[] getUserVolumes(String userId) {
Integer musicVolume = userMusicVolumeMap.get(userId);
Integer playoutVolume = userPlayoutVolumeMap.get(userId);
if (musicVolume == null) {
musicVolume = 100; // 默认值
}
if (playoutVolume == null) {
playoutVolume = 50; // 默认值
}
return new int[]{musicVolume, playoutVolume};
}
}