1/*
2 * Copyright (C) 2012 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27
28#if USE(COREMEDIA)
29
30#import "PlatformClockCM.h"
31
32#import "MediaTimeMac.h"
33#import "SoftLinking.h"
34#if PLATFORM(IOS)
35#import <CoreMedia/CMAudioClock.h>
36#else
37#import <CoreMedia/CMAudioDeviceClock.h>
38#endif
39
40SOFT_LINK_FRAMEWORK_OPTIONAL(CoreMedia)
41
42#if PLATFORM(IOS)
43SOFT_LINK(CoreMedia, CMAudioClockCreate, OSStatus, (CFAllocatorRef allocator, CMClockRef *clockOut), (allocator, clockOut))
44#else
45SOFT_LINK(CoreMedia, CMAudioDeviceClockCreate, OSStatus, (CFAllocatorRef allocator, CFStringRef deviceUID, CMClockRef *clockOut), (allocator, deviceUID, clockOut))
46#endif
47SOFT_LINK(CoreMedia, CMTimebaseCreateWithMasterClock, OSStatus, (CFAllocatorRef allocator, CMClockRef masterClock, CMTimebaseRef *timebaseOut), (allocator, masterClock, timebaseOut))
48SOFT_LINK(CoreMedia, CMTimebaseSetTime, OSStatus, (CMTimebaseRef timebase, CMTime time), (timebase, time))
49SOFT_LINK(CoreMedia, CMTimebaseGetTime, CMTime, (CMTimebaseRef timebase), (timebase))
50SOFT_LINK(CoreMedia, CMTimebaseSetRate, OSStatus, (CMTimebaseRef timebase, Float64 rate), (timebase, rate))
51SOFT_LINK(CoreMedia, CMTimeMakeWithSeconds, CMTime, (Float64 seconds, int32_t preferredTimeScale), (seconds, preferredTimeScale))
52SOFT_LINK(CoreMedia, CMTimeGetSeconds, Float64, (CMTime time), (time))
53
54using namespace WebCore;
55
56// A default time scale of 1000 allows milli-second CMTime precision without scaling the timebase.
57static const int32_t DefaultTimeScale = 1000;
58
59PlatformClockCM::PlatformClockCM()
60    : m_timebase(0)
61    , m_rate(1)
62    , m_running(false)
63{
64    CMClockRef rawClockPtr = 0;
65#if PLATFORM(IOS)
66    CMAudioClockCreate(kCFAllocatorDefault, &rawClockPtr);
67#else
68    CMAudioDeviceClockCreate(kCFAllocatorDefault, NULL, &rawClockPtr);
69#endif
70    RetainPtr<CMClockRef> clock = adoptCF(rawClockPtr);
71    initializeWithTimingSource(clock.get());
72}
73
74PlatformClockCM::PlatformClockCM(CMClockRef clock)
75    : m_timebase(0)
76    , m_running(false)
77{
78    initializeWithTimingSource(clock);
79}
80
81void PlatformClockCM::initializeWithTimingSource(CMClockRef clock)
82{
83    CMTimebaseRef rawTimebasePtr = 0;
84    CMTimebaseCreateWithMasterClock(kCFAllocatorDefault, clock, &rawTimebasePtr);
85    m_timebase = adoptCF(rawTimebasePtr);
86}
87
88void PlatformClockCM::setCurrentTime(double time)
89{
90    CMTime cmTime = CMTimeMakeWithSeconds(time, DefaultTimeScale);
91    CMTimebaseSetTime(m_timebase.get(), cmTime);
92}
93
94double PlatformClockCM::currentTime() const
95{
96    CMTime cmTime = CMTimebaseGetTime(m_timebase.get());
97    return CMTimeGetSeconds(cmTime);
98}
99
100void PlatformClockCM::setCurrentMediaTime(const MediaTime& time)
101{
102    CMTimebaseSetTime(m_timebase.get(), toCMTime(time));
103}
104
105MediaTime PlatformClockCM::currentMediaTime() const
106{
107    return toMediaTime(CMTimebaseGetTime(m_timebase.get()));
108}
109
110void PlatformClockCM::setPlayRate(double rate)
111{
112    if (m_rate == rate)
113        return;
114
115    m_rate = rate;
116    if (m_running)
117        CMTimebaseSetRate(m_timebase.get(), rate);
118}
119
120void PlatformClockCM::start()
121{
122    if (m_running)
123        return;
124    m_running = true;
125    CMTimebaseSetRate(m_timebase.get(), m_rate);
126}
127
128void PlatformClockCM::stop()
129{
130    if (!m_running)
131        return;
132    m_running = false;
133    CMTimebaseSetRate(m_timebase.get(), 0);
134}
135
136#endif
137