播放音效或音乐文件
在游戏或 K 歌等实时音视频场景中,为烘托气氛、增添趣味性,用户通常需要播放音效或音乐文件。
本文介绍如何在你的项目中实现播放音效或音乐文件功能。
技术原理
声网提供了以下 API, 帮助你实现播放音效或音乐文件:
- 音效 API:播放持续时间短的氛围音,例如掌声、欢呼声、打斗声、枪击声等,通常可以同时播放多个音效文件。
- 音乐 API:播放比较长的音乐文件,例如,在唱歌时播放伴奏,在聊天时播放背景音乐。同一时间,只能播放一个音乐文件。
这些方法主要包括如下功能:
功能 | 音效 API | 音乐 API |
---|---|---|
播放或停止播放特定的音频文件 |
|
|
暂停或恢复播放音频文件 |
|
|
获取和调整音频文件的播放位置和音量 |
|
|
报告音频文件的播放状态 | onAudioEffectFinished | onAudioMixingStateChanged |
前提条件
在进行操作之前,请确保你已满足以下条件:
- 项目已经实现了基本的实时音视频功能。
- 了解 Media Foundation 中支持的媒体格式。
实现播放音频文件
本节介绍如何调用音效 API 和音乐混音 API,在你的项目中播放音效和音乐混音文件。
实现播放音效
加入频道前,调用 preloadEffect
方法预加载音效文件。加入频道后,调用 playEffect
方法播放指定音效文件。多次调用 playEffect
,设置多个音效 ID,同时播放多个音效文件。音效播放结束后,SDK 触发 onAudioEffectFinished
回调。
在你的声网项目中,打开管理音效播放的文件并添加如下代码:
C++
void CAgoraEffectDlg::OnBnClickedButtonPreload()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
std::string strPath = cs2utf8(strEffect);
// 预加载音效文件
m_rtcEngine->preloadEffect(m_mapEffect[strEffect], strPath.c_str());
CString strInfo;
strInfo.Format(_T("preload effect :path:%s"), strEffect);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonUnloadEffect()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
// 释放预加载的音效文件
m_rtcEngine->unloadEffect(m_mapEffect[strEffect]);
CString strInfo;
strInfo.Format(_T("unload effect :path:%s"), strEffect);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonPauseEffect()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
// 暂停播放指定音效文件
m_rtcEngine->pauseEffect(m_mapEffect[strEffect]);
CString strInfo;
strInfo.Format(_T("pause effect :path:%s"), strEffect);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonResumeEffect()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
// 恢复播放指定音效文件
int ret = m_rtcEngine->resumeEffect(m_mapEffect[strEffect]);
CString strInfo;
strInfo.Format(_T("resume effect ret:%d :path:%s"),ret, strEffect);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonPlayEffect()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
std::string strFile = cs2utf8(strEffect);
CString strLoops;
m_edtLoops.GetWindowText(strLoops);
int loops = _ttol(strLoops);
if (loops == 0) {
m_edtLoops.SetWindowText(_T("1"));
loops = 1;
}
CString strPitch;
m_edtPitch.GetWindowText(strPitch);
double pitch = _ttof(strPitch);
CString strGain;
m_edtGain.GetWindowText(strGain);
int gain = _ttol(strGain);
CString strPan;
m_cmbPan.GetWindowText(strPan);
double pan = _ttof(strPan);
BOOL publish = m_chkPublish.GetCheck();
// 播放音效文件
int ret = m_rtcEngine->playEffect(m_mapEffect[strEffect], strFile.c_str(), loops, pitch, pan, gain, publish);
CString strInfo;
strInfo.Format(_T("play effect :path:%s, ret:%d"), strEffect, ret);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
strInfo.Format(_T("loops:%d,pitch:%.1f,pan:%.0f,gain:%d,publish:%d"),
loops, pitch, pan, gain, publish);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonStopEffect()
{
if (m_cmbEffect.GetCurSel() < 0)
{
return;
}
CString strEffect;
m_cmbEffect.GetWindowText(strEffect);
// 停止播放指定音效文件
m_rtcEngine->stopEffect(m_mapEffect[strEffect]);
CString strInfo;
strInfo.Format(_T("stop effect :path:%s"), strEffect);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
void CAgoraEffectDlg::OnBnClickedButtonPauseAllEffect()
{
if (!m_pauseAll)
{
// 暂停播放所有音效文件
m_rtcEngine->pauseAllEffects();
CString strInfo;
strInfo.Format(_T("pause All Effects"));
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
m_btnPauseAll.SetWindowText(AudioEffectCtrlResumeEffect);
}
else {
// 恢复播放所有音效文件
m_rtcEngine->resumeAllEffects();
CString strInfo;
strInfo.Format(_T("resume All Effects"));
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
m_btnPauseAll.SetWindowText(AudioEffectCtrlPauseAllEffect);
}
m_pauseAll = !m_pauseAll;
}
void CAgoraEffectDlg::OnBnClickedButtonStopAllEffect2()
{
// 停止播放所有音效文件
m_rtcEngine->stopAllEffects();
CString strInfo;
strInfo.Format(_T("stop All Effects"));
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
}
播放音乐
入频道之前或之后,调用 startAudioMixing
方法播放音乐文件。成功调用该方法后,音乐混音状态发生变化时,SDK 触发 onAudioMixingStateChanged
回调。该回调也报告音乐混音状态变化的原因。
在你的声网项目中,打开管理音效播放的文件夹添加以下代码:
C++
void CAgoraAudioMixingDlg::OnBnClickedButtonSetAudioMix()
{
CString strPath;
m_edtAudioMix.GetWindowText(strPath);
strPath.Replace(_T("file\/files"), _T("file\/api\/download"));
std::string strAudioPath = cs2utf8(strPath);
strAudioPath = UrlANSI(strAudioPath.c_str());
BOOL bOnlyLocal = FALSE;
BOOL bReplaceMicroPhone = TRUE;
int iRepeatTimes = 1;
if (!m_audioMixing)
{
if (strAudioPath.empty())
{
AfxMessageBox(_T("audio path can not empty."));
return;
}
bOnlyLocal = m_chkOnlyLocal.GetCheck() ? TRUE : FALSE;
bReplaceMicroPhone = m_chkMicroPhone.GetCheck() ? TRUE : FALSE;
CString strTimes;
CString strInfo;
m_edtRepatTimes.GetWindowText(strTimes);
iRepeatTimes = _ttoi(strTimes);
if (iRepeatTimes == 0) {
iRepeatTimes = 1;
m_edtRepatTimes.SetWindowText(_T("1"));
}
// 开始播放音乐文件
int nRet = m_rtcEngine->startAudioMixing(strAudioPath.c_str(),
bOnlyLocal,
bReplaceMicroPhone,
iRepeatTimes
);
strInfo.Format(_T("path:%s,\nonlyLocal:%s,\nReplaceMicroPhone:%s,\nRepeatTimes:%d"), strPath,
bOnlyLocal?_T("TRUE"):_T("FALSE"), bReplaceMicroPhone?_T("TRUE"):_T("FALSE"),
iRepeatTimes);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
strInfo.Format(_T("startAudioMixing,ret=%d"), nRet);
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
m_btnSetAudioMix.SetWindowText(audioMixingCtrlUnSetAudioMixing);
m_chkMicroPhone.EnableWindow(FALSE);
m_chkOnlyLocal.EnableWindow(FALSE);
}
else {
// 停止播放音乐文件
m_rtcEngine->stopAudioMixing();
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("cancel audio mixing"));
m_btnSetAudioMix.SetWindowText(audioMixingCtrlSetAudioMixing);
m_chkOnlyLocal.EnableWindow(TRUE);
m_chkMicroPhone.EnableWindow(TRUE);
}
m_audioMixing = !m_audioMixing;
}
// 监听 onAudioMixingStateChanged 回调
void CAudioMixingEventHandler::onAudioMixingStateChanged(AUDIO_MIXING_STATE_TYPE state, AUDIO_MIXING_ERROR_TYPE errorCode)
{
if (m_hMsgHanlder) {
PAudioMixingState stateChanged = new AudioMixingState;
stateChanged->error = errorCode;
stateChanged->state = state;
::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_AUDIO_MIXING_STATE_CHANED), (WPARAM)stateChanged, 0);
}
}
相关文档
本节提供了在实现播放音效或音乐功能时可能需要的相关文档。
示例项目
声网在 GitHub 上提供如下开源的示例项目。你可以前往下载或查看其中的源代码。