Diff
Modified: trunk/Source/WebCore/ChangeLog (211538 => 211539)
--- trunk/Source/WebCore/ChangeLog 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/ChangeLog 2017-02-01 23:38:04 UTC (rev 211539)
@@ -1,3 +1,43 @@
+2017-02-01 Eric Carlson <eric.carl...@apple.com>
+
+ [Mac] Update CARingBuffer class
+ https://bugs.webkit.org/show_bug.cgi?id=167656
+
+ Reviewed by Jer Noble.
+
+ API test CARingBufferTest added.
+
+ * WebCore.xcodeproj/project.pbxproj: Add headers to framework so they can be used from the API test.
+
+ * platform/audio/AudioStreamDescription.h: Add Int32.
+
+ * platform/audio/mac/CAAudioStreamDescription.cpp:
+ (WebCore::CAAudioStreamDescription::CAAudioStreamDescription):
+ (WebCore::CAAudioStreamDescription::~CAAudioStreamDescription):
+ (WebCore::CAAudioStreamDescription::format): Support Int32.
+ (WebCore::CAAudioStreamDescription::operator==): Make inline.
+ * platform/audio/mac/CAAudioStreamDescription.h:
+
+ * platform/audio/mac/CARingBuffer.cpp:
+ (WebCore::CARingBuffer::CARingBuffer): Move initializers into class declaration.
+ (WebCore::CARingBuffer::allocate): Use flush method, get allocation info from a CAAudioStreamDescription.
+ (WebCore::FetchABL): Add a mode parameter to allow samples to replace or mix into destination.
+ (WebCore::CARingBuffer::flush): New.
+ (WebCore::CARingBuffer::fetch): Add mode parameter.
+ (WebCore::CARingBuffer::~CARingBuffer): Deleted.
+ * platform/audio/mac/CARingBuffer.h:
+ (WebCore::CARingBuffer::~CARingBuffer):
+
+ * platform/graphics/avfoundation/AudioSourceProviderAVFObjC.mm:
+ (WebCore::AudioSourceProviderAVFObjC::prepare): Use new CARingBuffer constructor.
+ (WebCore::operator==): Deleted.
+ (WebCore::operator!=): Deleted.
+
+ * platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm:
+ (WebCore::WebAudioSourceProviderAVFObjC::prepare): Use new CARingBuffer constructor
+ (WebCore::operator==): Deleted.
+ (WebCore::operator!=): Deleted.
+
2017-02-01 Zalan Bujtas <za...@apple.com>
Simple line layout: Move TextFragmentIterator::runWidth to ::textWidth.
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (211538 => 211539)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-02-01 23:38:04 UTC (rev 211539)
@@ -278,6 +278,11 @@
07B7116D1D899E63009F0FFB /* CaptureDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116A1D899E63009F0FFB /* CaptureDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
07B7116E1D899E63009F0FFB /* CaptureDeviceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B7116B1D899E63009F0FFB /* CaptureDeviceManager.cpp */; };
07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */; };
+ 07C046C31E42508B007201E7 /* CAAudioStreamDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */; };
+ 07C046C41E42508B007201E7 /* CAAudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 07C046C71E425155007201E7 /* AudioTrackPrivateMediaStreamCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C046C51E42512F007201E7 /* AudioTrackPrivateMediaStreamCocoa.cpp */; };
+ 07C046C81E425155007201E7 /* AudioTrackPrivateMediaStreamCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C046C61E42512F007201E7 /* AudioTrackPrivateMediaStreamCocoa.h */; };
+ 07C046CB1E426413007201E7 /* AudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87561E40DCE50071C0EC /* AudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
07C1C0E21BFB600100BD2256 /* MediaTrackSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E01BFB600100BD2256 /* MediaTrackSupportedConstraints.h */; };
07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E41BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h */; settings = {ATTRIBUTES = (Private, ); }; };
07CE77D516712A6A00C55A47 /* InbandTextTrackPrivateClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5897,7 +5902,7 @@
CDC69DDA16371FD4007C38DF /* WebCoreFullScreenPlaceholderView.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC69DD816371FD3007C38DF /* WebCoreFullScreenPlaceholderView.h */; settings = {ATTRIBUTES = (Private, ); }; };
CDC69DDB16371FD4007C38DF /* WebCoreFullScreenPlaceholderView.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDC69DD916371FD3007C38DF /* WebCoreFullScreenPlaceholderView.mm */; };
CDC734141977896C0046BFC5 /* CARingBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDC734121977896C0046BFC5 /* CARingBuffer.cpp */; };
- CDC734151977896D0046BFC5 /* CARingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC734131977896C0046BFC5 /* CARingBuffer.h */; };
+ CDC734151977896D0046BFC5 /* CARingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC734131977896C0046BFC5 /* CARingBuffer.h */; settings = {ATTRIBUTES = (Private, ); }; };
CDC8B5A2180463470016E685 /* MediaPlayerPrivateMediaSourceAVFObjC.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDC8B5A0180463470016E685 /* MediaPlayerPrivateMediaSourceAVFObjC.mm */; };
CDC8B5A3180463470016E685 /* MediaPlayerPrivateMediaSourceAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = CDC8B5A1180463470016E685 /* MediaPlayerPrivateMediaSourceAVFObjC.h */; };
CDC8B5A6180474F70016E685 /* MediaSourcePrivateAVFObjC.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDC8B5A4180474F70016E685 /* MediaSourcePrivateAVFObjC.mm */; };
@@ -15351,6 +15356,8 @@
children = (
07707CB11E20649C00005BF7 /* AudioCaptureSourceProviderObjC.h */,
07707CAF1E205EC400005BF7 /* AudioSourceObserverObjC.h */,
+ 07C046C51E42512F007201E7 /* AudioTrackPrivateMediaStreamCocoa.cpp */,
+ 07C046C61E42512F007201E7 /* AudioTrackPrivateMediaStreamCocoa.h */,
070363D8181A1CDC00C074A5 /* AVAudioCaptureSource.h */,
070363D9181A1CDC00C074A5 /* AVAudioCaptureSource.mm */,
070363DA181A1CDC00C074A5 /* AVCaptureDeviceManager.h */,
@@ -24889,8 +24896,6 @@
FD3160B012B0270700C1A359 /* mac */ = {
isa = PBXGroup;
children = (
- 073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */,
- 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */,
FD3160B512B0272A00C1A359 /* AudioBusMac.mm */,
FD3160B612B0272A00C1A359 /* AudioDestinationMac.cpp */,
FD3160B712B0272A00C1A359 /* AudioDestinationMac.h */,
@@ -24901,6 +24906,8 @@
CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */,
CDC734121977896C0046BFC5 /* CARingBuffer.cpp */,
CDC734131977896C0046BFC5 /* CARingBuffer.h */,
+ 073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */,
+ 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */,
FD3160BA12B0272A00C1A359 /* FFTFrameMac.cpp */,
CD669D671D232E10004D1866 /* MediaSessionManagerMac.h */,
07EDC3ED1AACB75D00983EB5 /* MediaSessionManagerMac.mm */,
@@ -26571,6 +26578,7 @@
E107400E0E77BDC00033AF24 /* JSMessageChannel.h in Headers */,
75793EC90D0CE72D007FC0AC /* JSMessageEvent.h in Headers */,
E1ADEDDA0E76BD93004A1A5E /* JSMessagePort.h in Headers */,
+ 07C046CB1E426413007201E7 /* AudioStreamDescription.h in Headers */,
CDF4B7301E03CA4A00E235A2 /* JSMockCDMFactory.h in Headers */,
2D6F3E951C1F85550061DBD4 /* JSMockPageOverlay.h in Headers */,
A86629D109DA2B48009633A5 /* JSMouseEvent.h in Headers */,
@@ -27695,6 +27703,7 @@
A79BADA4161E7F3F00C2E652 /* RuleSet.h in Headers */,
2D76BB821945632400CFD29A /* RunLoopObserver.h in Headers */,
1A569D1F0D7E2B82007C3983 /* runtime_array.h in Headers */,
+ 07C046C41E42508B007201E7 /* CAAudioStreamDescription.h in Headers */,
1A569D210D7E2B82007C3983 /* runtime_method.h in Headers */,
1A569D230D7E2B82007C3983 /* runtime_object.h in Headers */,
1A569D250D7E2B82007C3983 /* runtime_root.h in Headers */,
@@ -27760,6 +27769,7 @@
1AAADDE414DC8C8F00AF64B3 /* ScrollingTreeNode.h in Headers */,
0FEA3E80191B3169000F1B55 /* ScrollingTreeOverflowScrollingNode.h in Headers */,
9391A99D1629D70000297330 /* ScrollingTreeScrollingNode.h in Headers */,
+ 07C046C81E425155007201E7 /* AudioTrackPrivateMediaStreamCocoa.h in Headers */,
0FB8890A167D2FA10010CDA5 /* ScrollingTreeStickyNode.h in Headers */,
7AAFE8D019CB8672000F56D8 /* ScrollLatchingState.h in Headers */,
F478755419983AFF0024A287 /* ScrollSnapAnimatorState.h in Headers */,
@@ -28315,6 +28325,7 @@
BE913D80181EF92400DCB09E /* TrackPrivateBase.h in Headers */,
FFAC30FE184FB145008C4F1E /* TrailingObjects.h in Headers */,
516071321BD8308B00DBC4F2 /* TransactionOperation.h in Headers */,
+ 07C046C21E425022007201E7 /* AudioSampleDataSource.h in Headers */,
49E911C40EF86D47009D0CAF /* TransformationMatrix.h in Headers */,
FB484F4D171F821E00040755 /* TransformFunctions.h in Headers */,
49E911CE0EF86D47009D0CAF /* TransformOperation.h in Headers */,
@@ -30422,6 +30433,7 @@
E1284BB210449FFA00EAEB52 /* JSPageTransitionEvent.cpp in Sources */,
FDA15EB112B03EE1003A583A /* JSPannerNode.cpp in Sources */,
E51A81DF17298D7700BFCA61 /* JSPerformance.cpp in Sources */,
+ 07C046C11E425022007201E7 /* AudioSampleDataSource.cpp in Sources */,
CB38FD511CCF938900592A3F /* JSPerformanceEntry.cpp in Sources */,
CB38FD571CD21E2A00592A3F /* JSPerformanceEntryCustom.cpp in Sources */,
A58C59D01E382EAC0047859C /* JSPerformanceMark.cpp in Sources */,
@@ -30767,6 +30779,7 @@
517A63C41B74318B00E7DCDC /* KeyedEncoderCF.cpp in Sources */,
A513B3D8114B166A001C429B /* KeyEventCocoa.mm in Sources */,
2655413A1489811C000DFC5D /* KeyEventIOS.mm in Sources */,
+ 07C046C31E42508B007201E7 /* CAAudioStreamDescription.cpp in Sources */,
935C477009AC4D7300A6AAB4 /* KeyEventMac.mm in Sources */,
316FE1190E6E1DA700BF6088 /* KeyframeAnimation.cpp in Sources */,
12A253DB1C8FF7DC00C22295 /* KeyframeEffect.cpp in Sources */,
@@ -32013,6 +32026,7 @@
49C7B9E51042D32F0009D447 /* WebGLTexture.cpp in Sources */,
6F995A231A7078B100A735F4 /* WebGLTransformFeedback.cpp in Sources */,
0C3F1F5A10C8871200D72CE1 /* WebGLUniformLocation.cpp in Sources */,
+ 07C046C71E425155007201E7 /* AudioTrackPrivateMediaStreamCocoa.cpp in Sources */,
6F995A251A7078B100A735F4 /* WebGLVertexArrayObject.cpp in Sources */,
6F222B761AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp in Sources */,
77A17A7712F28642004E02F6 /* WebGLVertexArrayObjectOES.cpp in Sources */,
Modified: trunk/Source/WebCore/platform/audio/AudioStreamDescription.h (211538 => 211539)
--- trunk/Source/WebCore/platform/audio/AudioStreamDescription.h 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/audio/AudioStreamDescription.h 2017-02-01 23:38:04 UTC (rev 211539)
@@ -48,6 +48,7 @@
enum PCMFormat {
None,
Int16,
+ Int32,
Float32,
Float64
};
Modified: trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.cpp (211538 => 211539)
--- trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.cpp 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.cpp 2017-02-01 23:38:04 UTC (rev 211539)
@@ -28,6 +28,15 @@
namespace WebCore {
+CAAudioStreamDescription::CAAudioStreamDescription()
+ : m_streamDescription({ })
+{
+}
+
+CAAudioStreamDescription::~CAAudioStreamDescription()
+{
+}
+
CAAudioStreamDescription::CAAudioStreamDescription(const AudioStreamBasicDescription &desc)
: m_streamDescription(desc)
{
@@ -46,6 +55,14 @@
int wordsize;
switch (format) {
+ case Int16:
+ wordsize = 2;
+ m_streamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
+ break;
+ case Int32:
+ wordsize = 4;
+ m_streamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
+ break;
case Float32:
wordsize = 4;
m_streamDescription.mFormatFlags |= kAudioFormatFlagIsFloat;
@@ -54,10 +71,6 @@
wordsize = 8;
m_streamDescription.mFormatFlags |= kAudioFormatFlagIsFloat;
break;
- case Int16:
- wordsize = 2;
- m_streamDescription.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
- break;
case None:
ASSERT_NOT_REACHED();
}
@@ -109,7 +122,7 @@
if (wordsize == sizeof(float))
return m_format = Float32;
- else if (wordsize == sizeof(double))
+ if (wordsize == sizeof(double))
return m_format = Float64;
return None;
@@ -117,8 +130,12 @@
if (m_streamDescription.mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) {
unsigned fractionBits = (m_streamDescription.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
- if (wordsize == 2 && !fractionBits)
- return m_format = Int16;
+ if (!fractionBits) {
+ if (wordsize == sizeof(int16_t))
+ return m_format = Int16;
+ if (wordsize == sizeof(int32_t))
+ return m_format = Int32;
+ }
}
}
@@ -125,14 +142,6 @@
return None;
}
-bool CAAudioStreamDescription::operator==(const AudioStreamDescription& other)
-{
- if (other.platformDescription().type != PlatformDescription::CAAudioStreamBasicType)
- return false;
-
- return operator==(*WTF::get<const AudioStreamBasicDescription*>(other.platformDescription().description));
-}
-
bool operator==(const AudioStreamBasicDescription& a, const AudioStreamBasicDescription& b)
{
return a.mSampleRate == b.mSampleRate
Modified: trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.h (211538 => 211539)
--- trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.h 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/audio/mac/CAAudioStreamDescription.h 2017-02-01 23:38:04 UTC (rev 211539)
@@ -35,15 +35,18 @@
class CAAudioStreamDescription final : public AudioStreamDescription {
public:
- CAAudioStreamDescription(const AudioStreamBasicDescription&);
- CAAudioStreamDescription(double, uint32_t, PCMFormat, bool);
+ WEBCORE_EXPORT CAAudioStreamDescription();
+ WEBCORE_EXPORT CAAudioStreamDescription(const AudioStreamBasicDescription&);
+ WEBCORE_EXPORT CAAudioStreamDescription(double, uint32_t, PCMFormat, bool);
+ WEBCORE_EXPORT ~CAAudioStreamDescription();
+
const PlatformDescription& platformDescription() const final;
PCMFormat format() const final;
double sampleRate() const final { return m_streamDescription.mSampleRate; }
-
+ bool isPCM() const final { return m_streamDescription.mFormatID == kAudioFormatLinearPCM; }
bool isInterleaved() const final { return !(m_streamDescription.mFormatFlags & kAudioFormatFlagIsNonInterleaved); }
bool isSignedInteger() const final { return isPCM() && (m_streamDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger); }
bool isFloat() const final { return isPCM() && (m_streamDescription.mFormatFlags & kAudioFormatFlagIsFloat); }
@@ -61,7 +64,13 @@
bool operator==(const AudioStreamBasicDescription& other) { return m_streamDescription == other; }
bool operator!=(const AudioStreamBasicDescription& other) { return !operator == (other); }
- bool operator==(const AudioStreamDescription&);
+ bool operator==(const AudioStreamDescription& other)
+ {
+ if (other.platformDescription().type != PlatformDescription::CAAudioStreamBasicType)
+ return false;
+
+ return operator==(*WTF::get<const AudioStreamBasicDescription*>(other.platformDescription().description));
+ }
bool operator!=(const AudioStreamDescription& other) { return !operator == (other); }
const AudioStreamBasicDescription& streamDescription() { return m_streamDescription; }
Modified: trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp (211538 => 211539)
--- trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp 2017-02-01 23:38:04 UTC (rev 211539)
@@ -28,6 +28,8 @@
#if ENABLE(WEB_AUDIO) && USE(MEDIATOOLBOX)
+#include "CAAudioStreamDescription.h"
+#include <Accelerate/Accelerate.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <wtf/MathExtras.h>
@@ -37,17 +39,14 @@
namespace WebCore {
CARingBuffer::CARingBuffer()
- : m_channelCount(0)
- , m_frameCount(0)
- , m_capacityBytes(0)
- , m_timeBoundsQueue(kGeneralRingTimeBoundsQueueSize)
- , m_timeBoundsQueuePtr(0)
+ : m_timeBoundsQueue(kGeneralRingTimeBoundsQueueSize)
{
}
-CARingBuffer::~CARingBuffer()
+void CARingBuffer::allocate(const CAAudioStreamDescription& format, size_t frameCount)
{
- deallocate();
+ m_description = format;
+ allocate(format.numberOfChannelStreams(), format.bytesPerFrame(), frameCount);
}
void CARingBuffer::allocate(uint32_t channelCount, size_t bytesPerFrame, size_t frameCount)
@@ -74,12 +73,7 @@
channelData += m_capacityBytes;
}
- for (auto timeBounds : m_timeBoundsQueue) {
- timeBounds.m_startFrame = 0;
- timeBounds.m_endFrame = 0;
- timeBounds.m_updateCounter = 0;
- }
- m_timeBoundsQueuePtr = 0;
+ flush();
}
void CARingBuffer::deallocate()
@@ -113,7 +107,7 @@
}
}
-static void FetchABL(AudioBufferList* list, size_t destOffset, Byte** buffers, size_t srcOffset, size_t nbytes)
+static void FetchABL(AudioBufferList* list, size_t destOffset, Byte** buffers, size_t srcOffset, size_t nbytes, AudioStreamDescription::PCMFormat format, CARingBuffer::FetchMode mode)
{
int channelCount = list->mNumberBuffers;
AudioBuffer* dest = list->mBuffers;
@@ -120,7 +114,39 @@
while (--channelCount >= 0) {
if (destOffset > dest->mDataByteSize)
continue;
- memcpy(static_cast<Byte*>(dest->mData) + destOffset, *buffers + srcOffset, std::min<size_t>(nbytes, dest->mDataByteSize - destOffset));
+
+ nbytes = std::min<size_t>(nbytes, dest->mDataByteSize - destOffset);
+ if (mode == CARingBuffer::Copy)
+ memcpy(static_cast<Byte*>(dest->mData) + destOffset, *buffers + srcOffset, nbytes);
+ else {
+ switch (format) {
+ case AudioStreamDescription::Int16: {
+ int16_t* destination = static_cast<int16_t*>(dest->mData);
+ int16_t* source = reinterpret_cast<int16_t*>(*buffers + srcOffset);
+ for (size_t i = 0; i < nbytes / sizeof(int16_t); i++)
+ destination[i] += source[i];
+ break;
+ }
+ case AudioStreamDescription::Int32: {
+ int32_t* destination = static_cast<int32_t*>(dest->mData);
+ vDSP_vaddi(destination, 1, reinterpret_cast<int32_t*>(*buffers + srcOffset), 1, destination, 1, nbytes / sizeof(int32_t));
+ break;
+ }
+ case AudioStreamDescription::Float32: {
+ float* destination = static_cast<float*>(dest->mData);
+ vDSP_vadd(destination, 1, reinterpret_cast<float*>(*buffers + srcOffset), 1, destination, 1, nbytes / sizeof(float));
+ break;
+ }
+ case AudioStreamDescription::Float64: {
+ double* destination = static_cast<double*>(dest->mData);
+ vDSP_vaddD(destination, 1, reinterpret_cast<double*>(*buffers + srcOffset), 1, destination, 1, nbytes / sizeof(double));
+ break;
+ }
+ case AudioStreamDescription::None:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
++buffers;
++dest;
}
@@ -138,6 +164,17 @@
}
}
+void CARingBuffer::flush()
+{
+ LockHolder locker(m_currentFrameBoundsLock);
+ for (auto& timeBounds : m_timeBoundsQueue) {
+ timeBounds.m_startFrame = 0;
+ timeBounds.m_endFrame = 0;
+ timeBounds.m_updateCounter = 0;
+ }
+ m_timeBoundsQueuePtr = 0;
+}
+
CARingBuffer::Error CARingBuffer::store(const AudioBufferList* list, size_t framesToWrite, uint64_t startFrame)
{
if (!framesToWrite)
@@ -249,7 +286,7 @@
return m_timeBoundsQueue[index].m_endFrame;
}
-CARingBuffer::Error CARingBuffer::fetch(AudioBufferList* list, size_t nFrames, uint64_t startRead)
+CARingBuffer::Error CARingBuffer::fetch(AudioBufferList* list, size_t nFrames, uint64_t startRead, FetchMode mode)
{
if (!nFrames)
return Ok;
@@ -286,11 +323,12 @@
if (offset0 < offset1) {
nbytes = offset1 - offset0;
- FetchABL(list, destStartByteOffset, buffers, offset0, nbytes);
+ FetchABL(list, destStartByteOffset, buffers, offset0, nbytes, m_description.format(), mode);
} else {
nbytes = m_capacityBytes - offset0;
- FetchABL(list, destStartByteOffset, buffers, offset0, nbytes);
- FetchABL(list, destStartByteOffset + nbytes, buffers, 0, offset1);
+ FetchABL(list, destStartByteOffset, buffers, offset0, nbytes, m_description.format(), mode);
+ if (offset1)
+ FetchABL(list, destStartByteOffset + nbytes, buffers, 0, offset1, m_description.format(), mode);
nbytes += offset1;
}
Modified: trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h (211538 => 211539)
--- trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h 2017-02-01 23:38:04 UTC (rev 211539)
@@ -23,11 +23,12 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CARingBuffer_h
-#define CARingBuffer_h
+#pragma once
#if ENABLE(WEB_AUDIO) && USE(MEDIATOOLBOX)
+#include "AudioStreamDescription.h"
+#include "CAAudioStreamDescription.h"
#include <runtime/ArrayBuffer.h>
#include <wtf/Lock.h>
#include <wtf/Vector.h>
@@ -38,24 +39,33 @@
class CARingBuffer {
public:
- CARingBuffer();
- ~CARingBuffer();
+ WEBCORE_EXPORT CARingBuffer();
+ WEBCORE_EXPORT ~CARingBuffer()
+ {
+ deallocate();
+ }
enum Error {
Ok,
TooMuch, // fetch start time is earlier than buffer start time and fetch end time is later than buffer end time
- CPUOverload, // the reader is unable to get enough CPU cycles to capture a consistent snapshot of the time bounds
};
- void allocate(uint32_t m_channelCount, size_t bytesPerFrame, size_t frameCount);
- void deallocate();
- Error store(const AudioBufferList*, size_t frameCount, uint64_t startFrame);
- Error fetch(AudioBufferList*, size_t frameCount, uint64_t startFrame);
- void getCurrentFrameBounds(uint64_t &startTime, uint64_t &endTime);
+ WEBCORE_EXPORT void allocate(const CAAudioStreamDescription&, size_t);
+ WEBCORE_EXPORT void deallocate();
+ WEBCORE_EXPORT Error store(const AudioBufferList*, size_t frameCount, uint64_t startFrame);
+
+ enum FetchMode { Copy, Mix };
+ WEBCORE_EXPORT Error fetch(AudioBufferList*, size_t frameCount, uint64_t startFrame, FetchMode mode = Copy);
+
+ WEBCORE_EXPORT void flush();
+
+ WEBCORE_EXPORT void getCurrentFrameBounds(uint64_t &startTime, uint64_t &endTime);
+
uint32_t channelCount() const { return m_channelCount; }
private:
+ void allocate(uint32_t m_channelCount, size_t bytesPerFrame, size_t frameCount);
size_t frameOffset(uint64_t frameNumber) { return (frameNumber & m_frameCountMask) * m_bytesPerFrame; }
void clipTimeBounds(uint64_t& startRead, uint64_t& endRead);
@@ -65,11 +75,11 @@
void setCurrentFrameBounds(uint64_t startFrame, uint64_t endFrame);
RefPtr<ArrayBuffer> m_buffers;
- uint32_t m_channelCount;
- size_t m_bytesPerFrame;
- uint32_t m_frameCount;
- uint32_t m_frameCountMask;
- size_t m_capacityBytes;
+ uint32_t m_channelCount { 0 };
+ size_t m_bytesPerFrame { 0 };
+ uint32_t m_frameCount { 0 };
+ uint32_t m_frameCountMask { 0 };
+ size_t m_capacityBytes { 0 };
struct TimeBounds {
TimeBounds()
@@ -82,14 +92,13 @@
volatile uint64_t m_endFrame;
volatile uint32_t m_updateCounter;
};
-
+
+ CAAudioStreamDescription m_description;
Vector<TimeBounds> m_timeBoundsQueue;
Lock m_currentFrameBoundsLock;
- std::atomic<int32_t> m_timeBoundsQueuePtr;
+ std::atomic<int32_t> m_timeBoundsQueuePtr { 0 };
};
}
#endif // ENABLE(WEB_AUDIO) && USE(MEDIATOOLBOX)
-
-#endif // CARingBuffer_h
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/AudioSourceProviderAVFObjC.mm (211538 => 211539)
--- trunk/Source/WebCore/platform/graphics/avfoundation/AudioSourceProviderAVFObjC.mm 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/AudioSourceProviderAVFObjC.mm 2017-02-01 23:38:04 UTC (rev 211539)
@@ -264,23 +264,6 @@
{
}
-static bool operator==(const AudioStreamBasicDescription& a, const AudioStreamBasicDescription& b)
-{
- return a.mSampleRate == b.mSampleRate
- && a.mFormatID == b.mFormatID
- && a.mFormatFlags == b.mFormatFlags
- && a.mBytesPerPacket == b.mBytesPerPacket
- && a.mFramesPerPacket == b.mFramesPerPacket
- && a.mBytesPerFrame == b.mBytesPerFrame
- && a.mChannelsPerFrame == b.mChannelsPerFrame
- && a.mBitsPerChannel == b.mBitsPerChannel;
-}
-
-static bool operator!=(const AudioStreamBasicDescription& a, const AudioStreamBasicDescription& b)
-{
- return !(a == b);
-}
-
void AudioSourceProviderAVFObjC::prepare(CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat)
{
ASSERT(maxFrames >= 0);
@@ -289,7 +272,6 @@
m_tapDescription = std::make_unique<AudioStreamBasicDescription>(*processingFormat);
int numberOfChannels = processingFormat->mChannelsPerFrame;
- size_t bytesPerFrame = processingFormat->mBytesPerFrame;
double sampleRate = processingFormat->mSampleRate;
ASSERT(sampleRate >= 0);
@@ -314,7 +296,7 @@
size_t capacity = std::max(static_cast<size_t>(2 * maxFrames), static_cast<size_t>(kRingBufferDuration * sampleRate));
m_ringBuffer = std::make_unique<CARingBuffer>();
- m_ringBuffer->allocate(numberOfChannels, bytesPerFrame, capacity);
+ m_ringBuffer->allocate(CAAudioStreamDescription(*processingFormat), capacity);
// AudioBufferList is a variable-length struct, so create on the heap with a generic new() operator
// with a custom size, and initialize the struct manually.
Modified: trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm (211538 => 211539)
--- trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Source/WebCore/platform/mediastream/mac/WebAudioSourceProviderAVFObjC.mm 2017-02-01 23:38:04 UTC (rev 211539)
@@ -134,23 +134,6 @@
}
}
-static bool operator==(const AudioStreamBasicDescription& a, const AudioStreamBasicDescription& b)
-{
- return a.mSampleRate == b.mSampleRate
- && a.mFormatID == b.mFormatID
- && a.mFormatFlags == b.mFormatFlags
- && a.mBytesPerPacket == b.mBytesPerPacket
- && a.mFramesPerPacket == b.mFramesPerPacket
- && a.mBytesPerFrame == b.mBytesPerFrame
- && a.mChannelsPerFrame == b.mChannelsPerFrame
- && a.mBitsPerChannel == b.mBitsPerChannel;
-}
-
-static bool operator!=(const AudioStreamBasicDescription& a, const AudioStreamBasicDescription& b)
-{
- return !(a == b);
-}
-
void WebAudioSourceProviderAVFObjC::prepare(const AudioStreamBasicDescription* format)
{
LOG(Media, "WebAudioSourceProviderAVFObjC::prepare(%p)", this);
@@ -201,7 +184,7 @@
return;
m_ringBuffer = std::make_unique<CARingBuffer>();
- m_ringBuffer->allocate(numberOfChannels, format->mBytesPerFrame, static_cast<size_t>(capacity));
+ m_ringBuffer->allocate(CAAudioStreamDescription(*format), static_cast<size_t>(capacity));
m_listBufferSize = static_cast<size_t>(bufferListSize);
m_list = std::unique_ptr<AudioBufferList>(static_cast<AudioBufferList*>(::operator new (m_listBufferSize)));
Modified: trunk/Tools/ChangeLog (211538 => 211539)
--- trunk/Tools/ChangeLog 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Tools/ChangeLog 2017-02-01 23:38:04 UTC (rev 211539)
@@ -1,3 +1,24 @@
+2017-02-01 Eric Carlson <eric.carl...@apple.com>
+
+ [Mac] Update CARingBuffer class
+ https://bugs.webkit.org/show_bug.cgi?id=167656
+
+ Reviewed by Jer Noble.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp: Added.
+ (TestWebKitAPI::CARingBufferTest::SetUp):
+ (TestWebKitAPI::CARingBufferTest::setup):
+ (TestWebKitAPI::CARingBufferTest::setListDataBuffer):
+ (TestWebKitAPI::CARingBufferTest::description):
+ (TestWebKitAPI::CARingBufferTest::bufferList):
+ (TestWebKitAPI::CARingBufferTest::ringBuffer):
+ (TestWebKitAPI::CARingBufferTest::capacity):
+ (TestWebKitAPI::CARingBufferTest::audioBufferListSizeForStream):
+ (TestWebKitAPI::CARingBufferTest::configureBufferListForStream):
+ (TestWebKitAPI::TEST_F):
+ (TestWebKitAPI::MixingTest::run):
+
2017-02-01 Alexey Proskuryakov <a...@apple.com>
[Mac] TestWebKitAPI includes system frameworks incorrectly
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (211538 => 211539)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-02-01 23:25:15 UTC (rev 211538)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2017-02-01 23:38:04 UTC (rev 211539)
@@ -24,6 +24,7 @@
/* Begin PBXBuildFile section */
07492B3B1DF8B14C00633DE1 /* EnumerateMediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07492B3A1DF8AE2D00633DE1 /* EnumerateMediaDevices.cpp */; };
07492B3C1DF8B86600633DE1 /* enumerateMediaDevices.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 07492B391DF8ADA400633DE1 /* enumerateMediaDevices.html */; };
+ 07C046CA1E4262A8007201E7 /* CARingBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C046C91E42573E007201E7 /* CARingBuffer.cpp */; };
0F139E771A423A5B00F590F5 /* WeakObjCPtr.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E751A423A5300F590F5 /* WeakObjCPtr.mm */; };
0F139E781A423A6B00F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
0F139E791A42457000F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
@@ -785,6 +786,7 @@
07492B391DF8ADA400633DE1 /* enumerateMediaDevices.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = enumerateMediaDevices.html; sourceTree = "<group>"; };
07492B3A1DF8AE2D00633DE1 /* EnumerateMediaDevices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EnumerateMediaDevices.cpp; sourceTree = "<group>"; };
0766DD1F1A5AD5200023E3BB /* PendingAPIRequestURL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PendingAPIRequestURL.cpp; sourceTree = "<group>"; };
+ 07C046C91E42573E007201E7 /* CARingBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CARingBuffer.cpp; sourceTree = "<group>"; };
0BCD833414857CE400EA2003 /* HashMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMap.cpp; sourceTree = "<group>"; };
0BCD85691485C98B00EA2003 /* SetForScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetForScope.cpp; sourceTree = "<group>"; };
0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformUtilitiesCocoa.mm; path = cocoa/PlatformUtilitiesCocoa.mm; sourceTree = "<group>"; };
@@ -1590,6 +1592,7 @@
8E4A85361E1D1AA100F53B0F /* GridPosition.cpp */,
CD89D0371C4EDB1300040A04 /* cocoa */,
7A909A6F1D877475007E10F8 /* AffineTransform.cpp */,
+ 07C046C91E42573E007201E7 /* CARingBuffer.cpp */,
7A909A701D877475007E10F8 /* FloatPoint.cpp */,
7A909A711D877475007E10F8 /* FloatRect.cpp */,
7A909A721D877475007E10F8 /* FloatSize.cpp */,
@@ -2671,6 +2674,7 @@
7CCE7F0D1A411AE600447C4C /* ReloadPageAfterCrash.cpp in Sources */,
7C83E0C31D0A653A00FEBCF3 /* RemoteObjectRegistry.mm in Sources */,
7CCE7EC91A411A7E00447C4C /* RenderedImageFromDOMNode.mm in Sources */,
+ 07C046CA1E4262A8007201E7 /* CARingBuffer.cpp in Sources */,
7A909A7D1D877480007E10F8 /* AffineTransform.cpp in Sources */,
7CCE7ECA1A411A7E00447C4C /* RenderedImageFromDOMRange.mm in Sources */,
7C83E0C41D0A654200FEBCF3 /* RequiresUserActionForPlayback.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp (0 => 211539)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/CARingBuffer.cpp 2017-02-01 23:38:04 UTC (rev 211539)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if PLATFORM(MAC)
+
+#include "Test.h"
+#include <WebCore/CARingBuffer.h>
+#include <wtf/MainThread.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class CARingBufferTest : public testing::Test {
+public:
+
+ virtual void SetUp()
+ {
+ WTF::initializeMainThread();
+ m_ringBuffer = std::make_unique<CARingBuffer>();
+ }
+
+ // CAAudioStreamDescription(double sampleRate, UInt32 numChannels, PCMFormat format, bool isInterleaved, size_t capacity)
+ void setup(double sampleRate, UInt32 numChannels, CAAudioStreamDescription::PCMFormat format, bool isInterleaved, size_t capacity)
+ {
+ m_description = CAAudioStreamDescription(sampleRate, numChannels, format, isInterleaved);
+ m_capacity = capacity;
+ size_t listSize = offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * std::max<uint32_t>(1, m_description.numberOfChannelStreams()));
+ m_bufferList = std::unique_ptr<AudioBufferList>(static_cast<AudioBufferList*>(::operator new (listSize)));
+ m_ringBuffer->allocate(m_description, capacity);
+ }
+
+ void setListDataBuffer(uint8_t* bufferData, size_t sampleCount)
+ {
+ size_t bufferCount = m_description.numberOfChannelStreams();
+ size_t channelCount = m_description.numberOfInterleavedChannels();
+ size_t bytesPerChannel = sampleCount * m_description.bytesPerFrame();
+
+ m_bufferList->mNumberBuffers = bufferCount;
+ for (unsigned i = 0; i < bufferCount; ++i) {
+ m_bufferList->mBuffers[i].mNumberChannels = channelCount;
+ m_bufferList->mBuffers[i].mDataByteSize = bytesPerChannel;
+ m_bufferList->mBuffers[i].mData = bufferData;
+ if (bufferData)
+ bufferData = bufferData + bytesPerChannel;
+ }
+ }
+
+ const CAAudioStreamDescription& description() const { return m_description; }
+ AudioBufferList& bufferList() const { return *m_bufferList.get(); }
+ CARingBuffer& ringBuffer() const { return *m_ringBuffer.get(); }
+ size_t capacity() const { return m_capacity; }
+
+private:
+ size_t audioBufferListSizeForStream(const CAAudioStreamDescription& format)
+ {
+ return offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * std::max<uint32_t>(1, format.numberOfChannelStreams()));
+ }
+
+ void configureBufferListForStream(AudioBufferList& bufferList, const CAAudioStreamDescription& format, uint8_t* bufferData, size_t sampleCount)
+ {
+ size_t bufferCount = format.numberOfChannelStreams();
+ size_t channelCount = format.numberOfInterleavedChannels();
+ size_t bytesPerChannel = sampleCount * format.bytesPerFrame();
+
+ bufferList.mNumberBuffers = bufferCount;
+ for (unsigned i = 0; i < bufferCount; ++i) {
+ bufferList.mBuffers[i].mNumberChannels = channelCount;
+ bufferList.mBuffers[i].mDataByteSize = bytesPerChannel;
+ bufferList.mBuffers[i].mData = bufferData;
+ if (bufferData)
+ bufferData = bufferData + bytesPerChannel;
+ }
+ }
+
+ std::unique_ptr<AudioBufferList> m_bufferList;
+ std::unique_ptr<CARingBuffer> m_ringBuffer;
+ CAAudioStreamDescription m_description = { };
+ size_t m_capacity = { 0 };
+};
+
+TEST_F(CARingBufferTest, Basics)
+{
+ const int capacity = 32;
+
+ setup(44100, 1, CAAudioStreamDescription::PCMFormat::Float32, true, capacity);
+
+ float sourceBuffer[capacity];
+ for (int i = 0; i < capacity; i++)
+ sourceBuffer[i] = i + 0.5;
+
+ setListDataBuffer(reinterpret_cast<uint8_t*>(sourceBuffer), capacity);
+
+ // Fill the first half of the buffer ...
+ int sampleCount = capacity / 2;
+ CARingBuffer::Error err = ringBuffer().store(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ uint64_t startTime;
+ uint64_t endTime;
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ((int)sampleCount, (int)endTime);
+
+ float scratchBuffer[capacity];
+ setListDataBuffer(reinterpret_cast<uint8_t*>(scratchBuffer), capacity);
+
+ err = ringBuffer().fetch(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ EXPECT_TRUE(!memcmp(sourceBuffer, scratchBuffer, sampleCount * description().sampleWordSize()));
+
+ // ... and the second half.
+ err = ringBuffer().store(&bufferList(), capacity / 2, capacity / 2);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ(capacity, (int)endTime);
+
+ memset(scratchBuffer, 0, sampleCount * description().sampleWordSize());
+ err = ringBuffer().fetch(&bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ EXPECT_TRUE(!memcmp(sourceBuffer, scratchBuffer, sampleCount * description().sampleWordSize()));
+
+ // Force the buffer to wrap around
+ err = ringBuffer().store(&bufferList(), capacity, capacity - 1);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ((int)capacity - 1, (int)startTime);
+ EXPECT_EQ(capacity - 1 + capacity, (int)endTime);
+
+ // Make sure it returns an error when asked to store too much ...
+ err = ringBuffer().store(&bufferList(), capacity * 3, capacity / 2);
+ EXPECT_EQ(err, CARingBuffer::Error::TooMuch);
+
+ // ... and doesn't modify the buffer
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ((int)capacity - 1, (int)startTime);
+ EXPECT_EQ(capacity - 1 + capacity, (int)endTime);
+
+ ringBuffer().flush();
+ ringBuffer().getCurrentFrameBounds(startTime, endTime);
+ EXPECT_EQ(0, (int)startTime);
+ EXPECT_EQ(0, (int)endTime);
+}
+
+template <typename type>
+class MixingTest {
+public:
+ static void run(CARingBufferTest& test)
+ {
+ const int sampleCount = 64;
+
+ CAAudioStreamDescription::PCMFormat format;
+ if (std::is_same<type, float>::value)
+ format = CAAudioStreamDescription::PCMFormat::Float32;
+ else if (std::is_same<type, double>::value)
+ format = CAAudioStreamDescription::PCMFormat::Float64;
+ else if (std::is_same<type, int32_t>::value)
+ format = CAAudioStreamDescription::PCMFormat::Int32;
+ else if (std::is_same<type, int16_t>::value)
+ format = CAAudioStreamDescription::PCMFormat::Int16;
+ else
+ ASSERT_NOT_REACHED();
+
+ test.setup(44100, 1, format, true, sampleCount);
+
+ type referenceBuffer[sampleCount];
+ type sourceBuffer[sampleCount];
+ type readBuffer[sampleCount];
+
+ for (int i = 0; i < sampleCount; i++) {
+ sourceBuffer[i] = i * 0.5;
+ referenceBuffer[i] = sourceBuffer[i];
+ }
+
+ test.setListDataBuffer(reinterpret_cast<uint8_t*>(sourceBuffer), sampleCount);
+ CARingBuffer::Error err = test.ringBuffer().store(&test.bufferList(), sampleCount, 0);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ memset(readBuffer, 0, sampleCount * test.description().sampleWordSize());
+ test.setListDataBuffer(reinterpret_cast<uint8_t*>(readBuffer), sampleCount);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ for (int i = 0; i < sampleCount; i++)
+ EXPECT_EQ(readBuffer[i], referenceBuffer[i]) << "Ring buffer value differs at index " << i;
+
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+ err = test.ringBuffer().fetch(&test.bufferList(), sampleCount, 0, CARingBuffer::FetchMode::Mix);
+ EXPECT_EQ(err, CARingBuffer::Error::Ok);
+
+ for (int i = 0; i < sampleCount; i++)
+ referenceBuffer[i] += sourceBuffer[i] * 3;
+
+ for (int i = 0; i < sampleCount; i++)
+ EXPECT_EQ(readBuffer[i], referenceBuffer[i]) << "Ring buffer value differs at index " << i;
+ }
+};
+
+TEST_F(CARingBufferTest, FloatMixing)
+{
+ MixingTest<float>::run(*this);
+}
+
+TEST_F(CARingBufferTest, DoubleMixing)
+{
+ MixingTest<double>::run(*this);
+}
+
+TEST_F(CARingBufferTest, Int32Mixing)
+{
+ MixingTest<int32_t>::run(*this);
+}
+
+TEST_F(CARingBufferTest, Int16Mixing)
+{
+ MixingTest<int16_t>::run(*this);
+}
+
+}
+
+#endif