350 lines
8.1 KiB
C++
350 lines
8.1 KiB
C++
/***************************************************************************************
|
|
*
|
|
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
*
|
|
* By downloading, copying, installing or using the software you agree to this license.
|
|
* If you do not agree to this license, do not download, install,
|
|
* copy or use the software.
|
|
*
|
|
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
|
|
*
|
|
* Redistribution and use in binary forms, with or without modification, are permitted.
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
|
|
* language governing permissions and limitations under the License.
|
|
*
|
|
****************************************************************************************/
|
|
|
|
#include "sys_inc.h"
|
|
#include "audio_play_win.h"
|
|
|
|
/**************************************************************************************/
|
|
|
|
#pragma comment(lib, "dsound.lib")
|
|
|
|
|
|
/**************************************************************************************/
|
|
|
|
CWAudioPlay::CWAudioPlay()
|
|
: CAudioPlay()
|
|
, m_pDSound8(NULL)
|
|
, m_pDSoundBuffer(NULL)
|
|
, m_pMutex(NULL)
|
|
, m_pAudioBuff(NULL)
|
|
, m_nAudioBuffLen(0)
|
|
, m_nLastChunk(0)
|
|
, m_nBufferNums(8)
|
|
, m_nSampleNums(1024)
|
|
, m_nSpecSize(0)
|
|
{
|
|
m_pMutex = sys_os_create_mutex();
|
|
}
|
|
|
|
CWAudioPlay::~CWAudioPlay(void)
|
|
{
|
|
stopPlay();
|
|
|
|
sys_os_destroy_sig_mutex(m_pMutex);
|
|
|
|
m_pMutex = NULL;
|
|
}
|
|
|
|
BOOL CWAudioPlay::startPlay(int samplerate, int channels)
|
|
{
|
|
HRESULT ret = DirectSoundCreate8(NULL, &m_pDSound8, NULL);
|
|
if (FAILED(ret))
|
|
{
|
|
log_print(HT_LOG_ERR, "%s, DirectSoundCreate8 failed\r\n", __FUNCTION__);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = m_pDSound8->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL);
|
|
if (FAILED(ret))
|
|
{
|
|
stopPlay();
|
|
log_print(HT_LOG_ERR, "%s, SetCooperativeLevel failed\r\n", __FUNCTION__);
|
|
return FALSE;
|
|
}
|
|
|
|
WAVEFORMATEX format;
|
|
memset(&format, 0, sizeof(WAVEFORMATEX));
|
|
|
|
format.wFormatTag = WAVE_FORMAT_PCM;
|
|
format.nChannels = channels;
|
|
format.wBitsPerSample = 16;
|
|
format.nSamplesPerSec = samplerate;
|
|
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
|
|
format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec;
|
|
format.cbSize = 0;
|
|
|
|
DSBUFFERDESC buf_desc;
|
|
memset(&buf_desc, 0, sizeof(DSBUFFERDESC));
|
|
|
|
m_nSpecSize = m_nSampleNums * channels * 2;
|
|
|
|
buf_desc.dwSize = sizeof(buf_desc);
|
|
buf_desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;
|
|
buf_desc.dwBufferBytes = m_nBufferNums * m_nSpecSize;
|
|
buf_desc.dwReserved = 0;
|
|
buf_desc.lpwfxFormat = &format;
|
|
|
|
ret = m_pDSound8->CreateSoundBuffer(&buf_desc, &m_pDSoundBuffer, NULL);
|
|
if (FAILED(ret))
|
|
{
|
|
stopPlay();
|
|
log_print(HT_LOG_ERR, "%s, CreateSoundBuffer failed\r\n", __FUNCTION__);
|
|
return FALSE;
|
|
}
|
|
|
|
m_pDSoundBuffer->SetFormat(&format);
|
|
|
|
void * buf1 = NULL;
|
|
DWORD len1 = 0;
|
|
void * buf2 = NULL;
|
|
DWORD len2 = 0;
|
|
|
|
/* Silence the initial audio buffer */
|
|
ret = m_pDSoundBuffer->Lock(0, buf_desc.dwBufferBytes, &buf1, &len1, &buf2, &len2, DSBLOCK_ENTIREBUFFER);
|
|
if (ret == DS_OK)
|
|
{
|
|
memset(buf1, 0, len1);
|
|
|
|
m_pDSoundBuffer->Unlock(buf1, len1, buf2, len2);
|
|
}
|
|
|
|
m_pAudioBuff = (uint8 *) malloc(m_nSpecSize);
|
|
if (NULL == m_pAudioBuff)
|
|
{
|
|
stopPlay();
|
|
log_print(HT_LOG_ERR, "%s, memory malloc failed\r\n", __FUNCTION__);
|
|
return FALSE;
|
|
}
|
|
|
|
m_nSamplerate = samplerate;
|
|
m_nChannels = channels;
|
|
m_bInited = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CWAudioPlay::stopPlay()
|
|
{
|
|
m_bInited = FALSE;
|
|
|
|
sys_os_mutex_enter(m_pMutex);
|
|
|
|
if (m_pDSoundBuffer)
|
|
{
|
|
m_pDSoundBuffer->Stop();
|
|
m_pDSoundBuffer->Release();
|
|
m_pDSoundBuffer = NULL;
|
|
}
|
|
|
|
if (m_pDSound8)
|
|
{
|
|
m_pDSound8->Release();
|
|
m_pDSound8 = NULL;
|
|
}
|
|
|
|
if (m_pAudioBuff)
|
|
{
|
|
free(m_pAudioBuff);
|
|
m_pAudioBuff = NULL;
|
|
}
|
|
|
|
sys_os_mutex_leave(m_pMutex);
|
|
|
|
m_nAudioBuffLen = 0;
|
|
}
|
|
|
|
BOOL CWAudioPlay::setVolume(int volume)
|
|
{
|
|
if (m_pDSoundBuffer)
|
|
{
|
|
double db = (double) volume / (HTVOLUME_MAX - HTVOLUME_MIN);
|
|
if (db < 0)
|
|
{
|
|
db = -db;
|
|
}
|
|
|
|
int nv = (DSBVOLUME_MAX - DSBVOLUME_MIN) * db + DSBVOLUME_MIN;
|
|
|
|
HRESULT hr = m_pDSoundBuffer->SetVolume(nv);
|
|
if (DS_OK == hr)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int CWAudioPlay::getVolume()
|
|
{
|
|
if (m_pDSoundBuffer)
|
|
{
|
|
long volume = 0;
|
|
|
|
HRESULT ret = m_pDSoundBuffer->GetVolume(&volume);
|
|
if (SUCCEEDED(ret))
|
|
{
|
|
double db = (double) volume / (DSBVOLUME_MAX - DSBVOLUME_MIN);
|
|
if (db < 0)
|
|
{
|
|
db = -db;
|
|
}
|
|
|
|
int nv = (HTVOLUME_MAX - HTVOLUME_MIN) * db + HTVOLUME_MIN;
|
|
|
|
return nv;
|
|
}
|
|
}
|
|
|
|
return HTVOLUME_MIN;
|
|
}
|
|
|
|
void CWAudioPlay::playAudio1(uint8 * data, int size)
|
|
{
|
|
DWORD cursor = 0;
|
|
DWORD junk = 0;
|
|
HRESULT result = DS_OK;
|
|
DWORD rawlen = 0;
|
|
void * bufptr = NULL;
|
|
|
|
/* Figure out which blocks to fill next */
|
|
result = m_pDSoundBuffer->GetCurrentPosition(&junk, &cursor);
|
|
if (result == DSERR_BUFFERLOST)
|
|
{
|
|
m_pDSoundBuffer->Restore();
|
|
result = m_pDSoundBuffer->GetCurrentPosition(&junk, &cursor);
|
|
}
|
|
|
|
if (result != DS_OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cursor /= m_nSpecSize;
|
|
|
|
m_nLastChunk = cursor;
|
|
cursor = (cursor + 1) % m_nBufferNums;
|
|
cursor *= m_nSpecSize;
|
|
|
|
/* Lock the audio buffer */
|
|
result = m_pDSoundBuffer->Lock(cursor, m_nSpecSize, &bufptr, &rawlen, NULL, &junk, 0);
|
|
if (result == DSERR_BUFFERLOST)
|
|
{
|
|
m_pDSoundBuffer->Restore();
|
|
result = m_pDSoundBuffer->Lock(cursor, m_nSpecSize, &bufptr, &rawlen, NULL, &junk, 0);
|
|
}
|
|
|
|
if (result != DS_OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (bufptr && rawlen > 0)
|
|
{
|
|
memcpy(bufptr, data, rawlen);
|
|
}
|
|
|
|
m_pDSoundBuffer->Unlock(bufptr, rawlen, NULL, 0);
|
|
|
|
waitDevice();
|
|
}
|
|
|
|
void CWAudioPlay::playAudio(uint8 * data, int size)
|
|
{
|
|
if (!m_bInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
sys_os_mutex_enter(m_pMutex);
|
|
|
|
if (NULL == m_pDSoundBuffer)
|
|
{
|
|
sys_os_mutex_leave(m_pMutex);
|
|
return;
|
|
}
|
|
|
|
while (m_nAudioBuffLen + size >= (uint32)m_nSpecSize)
|
|
{
|
|
memcpy(m_pAudioBuff + m_nAudioBuffLen, data, m_nSpecSize - m_nAudioBuffLen);
|
|
|
|
playAudio1(m_pAudioBuff, m_nSpecSize);
|
|
|
|
size -= m_nSpecSize - m_nAudioBuffLen;
|
|
data += m_nSpecSize - m_nAudioBuffLen;
|
|
|
|
m_nAudioBuffLen = 0;
|
|
}
|
|
|
|
if (size > 0)
|
|
{
|
|
memcpy(m_pAudioBuff + m_nAudioBuffLen, data, size);
|
|
m_nAudioBuffLen += size;
|
|
}
|
|
|
|
sys_os_mutex_leave(m_pMutex);
|
|
}
|
|
|
|
void CWAudioPlay::waitDevice()
|
|
{
|
|
DWORD status = 0;
|
|
DWORD cursor = 0;
|
|
DWORD junk = 0;
|
|
HRESULT result = DS_OK;
|
|
|
|
result = m_pDSoundBuffer->GetCurrentPosition(&junk, &cursor);
|
|
if (result != DS_OK)
|
|
{
|
|
if (result == DSERR_BUFFERLOST)
|
|
{
|
|
m_pDSoundBuffer->Restore();
|
|
}
|
|
return;
|
|
}
|
|
|
|
while ((cursor / m_nSpecSize) == m_nLastChunk)
|
|
{
|
|
usleep(1000);
|
|
|
|
/* Try to restore a lost sound buffer */
|
|
m_pDSoundBuffer->GetStatus(&status);
|
|
|
|
if (status & DSBSTATUS_BUFFERLOST)
|
|
{
|
|
m_pDSoundBuffer->Restore();
|
|
m_pDSoundBuffer->GetStatus(&status);
|
|
|
|
if ((status & DSBSTATUS_BUFFERLOST))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!(status & DSBSTATUS_PLAYING))
|
|
{
|
|
result = m_pDSoundBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
|
if (result == DS_OK)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* Find out where we are playing */
|
|
result = m_pDSoundBuffer->GetCurrentPosition(&junk, &cursor);
|
|
if (result != DS_OK)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|