axmol/cocos/audio/winrt/AudioSourceReader.cpp

199 lines
4.6 KiB
C++

/*
* cocos2d-x http://www.cocos2d-x.org
*
* Copyright (c) 2010-2011 - cocos2d-x community
*
* Portions Copyright (c) Microsoft Open Technologies, Inc.
* All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 "platform/CCPlatformConfig.h"
#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
#include "AudioSourceReader.h"
using namespace cocos2d;
using namespace cocos2d::experimental;
// AudioFileReader
AudioSourceReader::AudioSourceReader() :
_isStreaming(false)
, _filePath("")
, _audioSize(0)
{
}
AudioSourceReader::~AudioSourceReader()
{
}
// WAVFileReader
WAVReader::WAVReader() :
_bytesRead(0)
, _isDirty(false)
, _streamer(nullptr)
{
}
WAVReader::~WAVReader()
{
flushChunks();
}
bool WAVReader::initialize(const std::string& filePath)
{
bool ret = false;
_isStreaming = false;
_filePath = filePath;
do {
auto fileSize = FileUtils::getInstance()->getFileSize(_filePath);
if (fileSize <= 0)
break;
flushChunks();
_rwMutex.lock();
_streamer = ref new MediaStreamer;
_streamer->Initialize(std::wstring(_filePath.begin(), _filePath.end()).c_str(), true);
_rwMutex.unlock();
_wfx = _streamer->GetOutputWaveFormatEx();
UINT32 dataSize = _streamer->GetMaxStreamLengthInBytes();
if (dataSize <= 0)
break;
_audioSize = dataSize;
if (_audioSize <= PCMDATA_CACHEMAXSIZE) {
produceChunk();
}
else {
_isStreaming = true;
for (int i = 0; i < QUEUEBUFFER_NUM; i++) {
produceChunk();
}
}
ret = true;
} while (false);
return ret;
}
bool WAVReader::consumeChunk(AudioDataChunk& chunk)
{
bool ret = false;
_isDirty = true;
_rwMutex.lock();
if (_chnkQ.size() > 0) {
chunk = _chnkQ.front();
if (_isStreaming) {
_chnkQ.pop();
}
else{
// copy for future requests
auto cpy = new (std::nothrow) unsigned char[chunk._dataSize];
memcpy(cpy, chunk._data, chunk._dataSize);
_chnkQ.front()._data = cpy;
}
ret = true;
}
_rwMutex.unlock();
return ret;
}
void WAVReader::produceChunk()
{
_rwMutex.lock();
int chunkSize = _audioSize;
do {
if (!_isStreaming && _chnkQ.size() || _chnkQ.size() >= QUEUEBUFFER_NUM) {
break;
}
if (_isStreaming) {
chunkSize = std::min(CHUNK_SIZE_MAX, _audioSize - _bytesRead);
}
if (!chunkSize && !_chnkQ.size()) {
auto alignment = _wfx.nChannels * _wfx.nBlockAlign;
_bytesRead -= alignment;
chunkSize = alignment;
}
UINT retSize = 0;
AudioDataChunk chunk = { 0 };
chunk._data = new (std::nothrow) unsigned char[chunkSize];
_streamer->ReadChunk(chunk._data, _bytesRead, chunkSize, &retSize);
if (retSize <= 0) {
delete[] chunk._data;
chunk._data = nullptr;
break;
}
_bytesRead += retSize;
chunk._dataSize = retSize;
chunk._seqNo = ((float)_bytesRead / _audioSize) * ((float)_audioSize / CHUNK_SIZE_MAX);
chunk._endOfStream = (_bytesRead >= _audioSize);
_chnkQ.push(chunk);
} while (false);
_rwMutex.unlock();
}
void WAVReader::seekTo(const float ratio)
{
if (_isStreaming) {
_bytesRead = ratio * _audioSize;
if (!_bytesRead && !_isDirty && _chnkQ.size()) // already in 0.0 position
return;
flushChunks();
switch (_wfx.wFormatTag)
{
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_ADPCM: {
auto alignment = _wfx.nChannels * _wfx.nBlockAlign;
_bytesRead = _bytesRead >= _audioSize ? (_audioSize - alignment) : _bytesRead - (_bytesRead % alignment);
} break;
default:
break;
}
for (int i = 0; i < QUEUEBUFFER_NUM; i++) {
produceChunk();
}
}
}
void WAVReader::flushChunks()
{
_rwMutex.lock();
while (!_chnkQ.empty()) {
delete[] _chnkQ.front()._data;
_chnkQ.pop();
}
_rwMutex.unlock();
}
#endif