Skip to content

Commit fa9eab4

Browse files
HugoChaanalienzhchenparkCYG
authored
Release/4.0.0 (#17)
* update renew token * fix renewtoken bug * fix error * update ktvapi * update ktvapi * Develop/4.0 ios (#14) * fix error * update ktvapi * update ktvapi * update v4.0.0 KTVAPI Android (#16) * update v4.0.0 KTVAPI Android * renew ktvapi --------- Co-authored-by: CYG <[email protected]> * optimize readme (#19) Co-authored-by: CYG <[email protected]> * optimize demo (#20) Co-authored-by: CYG <[email protected]> * update logic * Dev/4.0.0 android demo (#22) * optimize demo * optimize demo * Update README.md --------- Co-authored-by: CYG <[email protected]> * Update README.md * [Android]optimize readme * Update README.md * Update README.md * [Android]repalce song * Update README.md * Update README.md * update ktvapi * [Android]update ktvapi (#24) Co-authored-by: CYG <[email protected]> * update ktvapi --------- Co-authored-by: zhangwei <[email protected]> Co-authored-by: chenpark <[email protected]> Co-authored-by: CYG <[email protected]>
1 parent fc154f1 commit fa9eab4

File tree

26 files changed

+1238
-558
lines changed

26 files changed

+1238
-558
lines changed

KTVAPI/Android/README.md

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
# KTV场景化Api sample demo
22

33
> 本文档主要介绍如何快速跑通 <mark>KTV场景化Api</mark> 示例工程,支持通过声网内容中心版权音乐和本地文件两种方式。
4-
>
5-
> k 歌流程
6-
> ![ktvapi_liucheng.png](image%2Fktvapi_liucheng.png)
7-
> Demo 效果:
8-
![Screenshot_20230814-114931.png](image/Screenshot_20230814-114931.png)
9-
![Screenshot_20230814-115006.png](image/Screenshot_20230814-115006.png)
4+
>
5+
> **Demo 效果:**
6+
>
7+
> <img src="https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/github_readme/ktv/ktvapi_demo1.png" width="300" height="640"><img src="https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/github_readme/ktv/ktvapi_demo2.png" width="300" height="640">
108
---
119

1210
## 1. 环境准备
1311

14-
- <mark>最低兼容 Android 7.0</mark>(SDK API Level 24
12+
- <mark>最低兼容 Android 5.0</mark>(SDK API Level 21
1513
- Android Studio 3.5及以上版本。
16-
- Android 7.0 及以上的手机设备。
14+
- Android 5.0 及以上的手机设备。
1715

1816
---
1917

@@ -36,17 +34,28 @@
3634

3735
- <mark>联系销售给 AppID 开通 K 歌权限</mark>(如果您没有销售人员的联系方式可通过智能客服联系销售人员 [Agora 支持](https://agora-ticket.agora.io/))
3836

39-
- 注: 拉取榜单、歌单、歌词等功能是需要开通权限的
37+
```json
38+
注: 拉取榜单、歌单、歌词等功能是需要开通权限的
39+
```
4040

41-
- 在项目的 [**local.properties**](../../local.properties) 里填写需要的声网 App ID 和 App 证书,服务器地址可以联系销售人员获取
42-
-
43-
![local_config.png](image%2Flocal_config.png)
41+
- 在项目的 [**gradle.properties**](gradle.properties) 里填写需要的声网 App ID 和 App 证书
4442

4543
```
46-
TOOLBOX_SERVER_HOST:获取 rtc token,rtm token
44+
# RTM RTC SDK key Config
4745
AGORA_APP_ID:声网appid
4846
AGORA_APP_CERTIFICATE:声网Certificate
4947
```
5048
- 用 Android Studio 运行项目即可开始您的体验
5149
52-
---
50+
---
51+
52+
### 集成遇到困难,该如何联系声网获取协助
53+
54+
> 方案1:如果您已经在使用声网服务或者在对接中,可以直接联系对接的销售或服务;
55+
>
56+
> 方案2:发送邮件给 [[email protected]](mailto:[email protected]) 咨询
57+
>
58+
> 方案3:扫码加入我们的微信交流群提问
59+
>
60+
> <img src="https://download.agora.io/demo/release/SDHY_QA.jpg" width="360" height="360">
61+
---

KTVAPI/Android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
Properties properties = new Properties()
7-
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream()
7+
InputStream inputStream = project.rootProject.file('gradle.properties').newDataInputStream()
88
properties.load(inputStream)
99

1010
android {

KTVAPI/Android/app/src/main/java/io/agora/ktvdemo/ui/LivingFragment.kt

Lines changed: 171 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ package io.agora.ktvdemo.ui
22

33
import android.os.Bundle
44
import android.text.TextUtils
5+
import android.util.Log
56
import android.view.LayoutInflater
67
import android.view.View
78
import android.view.ViewGroup
9+
import android.widget.Toast
810
import androidx.navigation.fragment.findNavController
911
import io.agora.karaoke_view.v11.KaraokeView
1012
import io.agora.ktvapi.*
1113
import io.agora.ktvdemo.BuildConfig
12-
import io.agora.ktvdemo.rtc.RtcEngineController
13-
import io.agora.ktvdemo.databinding.FragmentLivingBinding
14+
import io.agora.ktvdemo.MyApplication
1415
import io.agora.ktvdemo.R
16+
import io.agora.ktvdemo.databinding.FragmentLivingBinding
17+
import io.agora.ktvdemo.rtc.RtcEngineController
1518
import io.agora.ktvdemo.utils.DownloadUtils
1619
import io.agora.ktvdemo.utils.KeyCenter
1720
import io.agora.ktvdemo.utils.ZipUtils
@@ -38,6 +41,10 @@ class LivingFragment : BaseFragment<FragmentLivingBinding>() {
3841
initView()
3942
initKTVApi()
4043
joinChannel()
44+
45+
if (KeyCenter.isLeadSinger() || KeyCenter.isCoSinger()) {
46+
ktvApi.muteMic(false)
47+
}
4148
}
4249

4350
override fun onDestroy() {
@@ -51,6 +58,8 @@ class LivingFragment : BaseFragment<FragmentLivingBinding>() {
5158
private fun initView() {
5259
binding?.apply {
5360
karaokeView = KaraokeView(lyricsView,null)
61+
62+
// 退出场景
5463
btnClose.setOnClickListener {
5564
ktvApi.switchSingerRole(KTVSingRole.Audience, null)
5665
ktvApi.removeEventHandler(ktvApiEventHandler)
@@ -65,6 +74,162 @@ class LivingFragment : BaseFragment<FragmentLivingBinding>() {
6574
} else {
6675
tvSinger.text = getString(R.string.app_audience)
6776
}
77+
78+
// 加入合唱
79+
btJoinChorus.setOnClickListener {
80+
if (KeyCenter.isLeadSinger()) {
81+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
82+
} else {
83+
ktvApi.switchSingerRole(KTVSingRole.CoSinger, null)
84+
}
85+
}
86+
87+
// 退出合唱
88+
btLeaveChorus.setOnClickListener {
89+
if (KeyCenter.isLeadSinger()) {
90+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
91+
} else {
92+
ktvApi.switchSingerRole(KTVSingRole.Audience, null)
93+
}
94+
}
95+
96+
// 开原唱:仅领唱和合唱者可以做这项操作
97+
btOriginal.setOnClickListener {
98+
if (KeyCenter.isLeadSinger()) {
99+
ktvApi.getMediaPlayer().selectMultiAudioTrack(0, 0)
100+
} else if (KeyCenter.isCoSinger()) {
101+
ktvApi.getMediaPlayer().selectAudioTrack(0)
102+
} else {
103+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
104+
}
105+
}
106+
107+
// 开伴奏:仅领唱和合唱者可以做这项操作
108+
btAcc.setOnClickListener {
109+
if (KeyCenter.isLeadSinger()) {
110+
ktvApi.getMediaPlayer().selectMultiAudioTrack(1, 1)
111+
} else if (KeyCenter.isCoSinger()) {
112+
ktvApi.getMediaPlayer().selectAudioTrack(1)
113+
} else {
114+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
115+
}
116+
}
117+
118+
// 开导唱:仅领唱可以做这项操作,开启后领唱本地听到歌曲原唱,但观众听到仍为伴奏
119+
btDaoChang.setOnClickListener {
120+
if (KeyCenter.isLeadSinger()) {
121+
ktvApi.getMediaPlayer().selectMultiAudioTrack(0, 1)
122+
} else if (KeyCenter.isCoSinger()) {
123+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
124+
} else {
125+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
126+
}
127+
}
128+
129+
// 加载音乐
130+
btLoadMusic.setOnClickListener {
131+
if (KeyCenter.isMcc) {
132+
// 使用声网版权中心歌单
133+
val musicConfiguration = KTVLoadMusicConfiguration(
134+
KeyCenter.songCode.toString(), false, KeyCenter.LeadSingerUid,
135+
if (KeyCenter.isAudience()) KTVLoadMusicMode.LOAD_LRC_ONLY else KTVLoadMusicMode.LOAD_MUSIC_AND_LRC
136+
)
137+
ktvApi.loadMusic(KeyCenter.songCode, musicConfiguration, object : IMusicLoadStateListener {
138+
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
139+
Log.d("Music", "onMusicLoadSuccess, songCode: $songCode, lyricUrl: $lyricUrl")
140+
if (KeyCenter.isLeadSinger()) {
141+
ktvApi.switchSingerRole(KTVSingRole.LeadSinger, object : ISwitchRoleStateListener {
142+
override fun onSwitchRoleSuccess() {
143+
// 加载成功开始播放音乐
144+
ktvApi.startSing(KeyCenter.songCode, 0)
145+
}
146+
147+
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
148+
149+
}
150+
})
151+
} else if (KeyCenter.isCoSinger()) {
152+
ktvApi.switchSingerRole(KTVSingRole.CoSinger, object : ISwitchRoleStateListener {
153+
override fun onSwitchRoleSuccess() {
154+
155+
}
156+
157+
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
158+
159+
}
160+
})
161+
}
162+
}
163+
164+
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
165+
Log.d("Music", "onMusicLoadFail, songCode: $songCode, reason: $reason")
166+
}
167+
168+
override fun onMusicLoadProgress(
169+
songCode: Long,
170+
percent: Int,
171+
status: MusicLoadStatus,
172+
msg: String?,
173+
lyricUrl: String?
174+
) {
175+
lyricsView.setLabelShownWhenNoLyrics("$percent%")
176+
Log.d("Music", "onMusicLoadProgress, songCode: $songCode, percent: $percent")
177+
}
178+
})
179+
} else {
180+
// 使用本地音乐文件
181+
val musicConfiguration = KTVLoadMusicConfiguration(
182+
KeyCenter.songCode.toString(), false, KeyCenter.LeadSingerUid, KTVLoadMusicMode.LOAD_NONE
183+
)
184+
val songPath = requireActivity().filesDir.absolutePath + File.separator
185+
val songName = "成都"
186+
ktvApi.loadMusic("$songPath$songName.mp3", musicConfiguration)
187+
val fileLrc = File("$songPath$songName.xml")
188+
val lyricsModel = KaraokeView.parseLyricsData(fileLrc)
189+
karaokeView?.lyricsData = lyricsModel
190+
if (KeyCenter.isLeadSinger()) {
191+
ktvApi.switchSingerRole(KTVSingRole.LeadSinger, object : ISwitchRoleStateListener {
192+
override fun onSwitchRoleSuccess() {
193+
ktvApi.startSing("$songPath$songName.mp3", 0)
194+
}
195+
196+
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
197+
198+
}
199+
})
200+
} else if (KeyCenter.isCoSinger()) {
201+
ktvApi.switchSingerRole(KTVSingRole.CoSinger, object : ISwitchRoleStateListener {
202+
override fun onSwitchRoleSuccess() {
203+
204+
}
205+
206+
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
207+
208+
}
209+
})
210+
}
211+
}
212+
}
213+
214+
// 取消加载歌曲并删除本地歌曲缓存
215+
btRemoveMusic.setOnClickListener {
216+
if (KeyCenter.isMcc) {
217+
ktvApi.removeMusic(KeyCenter.songCode)
218+
lyricsView.reset()
219+
} else {
220+
Toast.makeText(MyApplication.app(), R.string.app_no_premission, Toast.LENGTH_SHORT).show()
221+
}
222+
}
223+
224+
// 开麦
225+
btMicOn.setOnClickListener {
226+
ktvApi.muteMic(false)
227+
}
228+
229+
// 关麦
230+
btMicOff.setOnClickListener {
231+
ktvApi.muteMic(true)
232+
}
68233
}
69234
}
70235

@@ -101,102 +266,25 @@ class LivingFragment : BaseFragment<FragmentLivingBinding>() {
101266
)
102267
ktvApi.initialize(ktvApiConfig)
103268
ktvApi.addEventHandler(ktvApiEventHandler)
104-
ktvApi.renewInnerDataStreamId()
105269
ktvApi.setLrcView(object : ILrcView {
106270
override fun onUpdatePitch(pitch: Float?) {
107271
}
108272

109273
override fun onUpdateProgress(progress: Long?) {
110-
if (progress != null) {
111-
karaokeView?.setProgress(progress)
274+
progress?.let {
275+
karaokeView?.setProgress(it)
112276
}
113277
}
114278

115279
override fun onDownloadLrcData(url: String?) {
116-
if (url != null) {
117-
dealDownloadLrc(url)
280+
url?.let {
281+
dealDownloadLrc(it)
118282
}
119283
}
120284

121285
override fun onHighPartTime(highStartTime: Long, highEndTime: Long) {
122286
}
123287
})
124-
if (KeyCenter.isMcc) {
125-
val musicConfiguration = KTVLoadMusicConfiguration(
126-
KeyCenter.songCode.toString(), false, KeyCenter.LeadSingerUid,
127-
if (KeyCenter.isAudience()) KTVLoadMusicMode.LOAD_LRC_ONLY else KTVLoadMusicMode.LOAD_MUSIC_AND_LRC
128-
)
129-
ktvApi.loadMusic(KeyCenter.songCode, musicConfiguration, object : IMusicLoadStateListener {
130-
override fun onMusicLoadSuccess(songCode: Long, lyricUrl: String) {
131-
if (KeyCenter.isLeadSinger()) {
132-
ktvApi.switchSingerRole(KTVSingRole.LeadSinger, object : ISwitchRoleStateListener {
133-
override fun onSwitchRoleSuccess() {
134-
ktvApi.startSing(KeyCenter.songCode, 0)
135-
}
136-
137-
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
138-
139-
}
140-
})
141-
} else if (KeyCenter.isCoSinger()) {
142-
ktvApi.switchSingerRole(KTVSingRole.CoSinger, object : ISwitchRoleStateListener {
143-
override fun onSwitchRoleSuccess() {
144-
145-
}
146-
147-
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
148-
149-
}
150-
})
151-
}
152-
}
153-
154-
override fun onMusicLoadFail(songCode: Long, reason: KTVLoadSongFailReason) {
155-
156-
}
157-
158-
override fun onMusicLoadProgress(
159-
songCode: Long,
160-
percent: Int,
161-
status: MusicLoadStatus,
162-
msg: String?,
163-
lyricUrl: String?
164-
) {
165-
166-
}
167-
})
168-
} else {
169-
val musicConfiguration = KTVLoadMusicConfiguration(
170-
KeyCenter.songCode.toString(), false, KeyCenter.LeadSingerUid, KTVLoadMusicMode.LOAD_NONE
171-
)
172-
val songPath = requireActivity().filesDir.absolutePath + File.separator
173-
val songName = "成都"
174-
ktvApi.loadMusic("$songPath$songName.mp3", musicConfiguration)
175-
val fileLrc = File("$songPath$songName.xml")
176-
val lyricsModel = KaraokeView.parseLyricsData(fileLrc)
177-
karaokeView?.lyricsData = lyricsModel
178-
if (KeyCenter.isLeadSinger()) {
179-
ktvApi.switchSingerRole(KTVSingRole.LeadSinger, object : ISwitchRoleStateListener {
180-
override fun onSwitchRoleSuccess() {
181-
ktvApi.startSing("$songPath$songName.mp3", 0)
182-
}
183-
184-
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
185-
186-
}
187-
})
188-
} else if (KeyCenter.isCoSinger()) {
189-
ktvApi.switchSingerRole(KTVSingRole.CoSinger, object : ISwitchRoleStateListener {
190-
override fun onSwitchRoleSuccess() {
191-
192-
}
193-
194-
override fun onSwitchRoleFail(reason: SwitchRoleFailReason) {
195-
196-
}
197-
})
198-
}
199-
}
200288
}
201289

202290
private fun dealDownloadLrc(url: String) {

KTVAPI/Android/app/src/main/java/io/agora/ktvdemo/utils/KeyCenter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package io.agora.ktvdemo.utils
22

33
object KeyCenter {
44

5-
const val LeadSingerUid = 1000
5+
const val LeadSingerUid = 10003213
66
const val CoSingerUid = 2000
77
const val AudienceUid = 3000
88

9-
const val songCode: Long = 6805795303139450
9+
const val songCode: Long = 6625526607662280
1010

1111
var localUid: Int = LeadSingerUid
1212

0 commit comments

Comments
 (0)