1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "SampleSink.h"
8 #include "AudioSinkFilter.h"
9 #include "AudioSinkInputPin.h"
10 #include "VideoUtils.h"
11 #include "mozilla/Logging.h"
12 
13 
14 #include <initguid.h>
15 #include <wmsdkidl.h>
16 
17 #define DELETE_RESET(p) { delete (p) ; (p) = nullptr ;}
18 
19 DEFINE_GUID(CLSID_MozAudioSinkFilter, 0x1872d8c8, 0xea8d, 0x4c34, 0xae, 0x96, 0x69, 0xde,
20             0xf1, 0x33, 0x7b, 0x33);
21 
22 using namespace mozilla::media;
23 
24 namespace mozilla {
25 
26 static LazyLogModule gDirectShowLog("DirectShowDecoder");
27 #define LOG(...) MOZ_LOG(gDirectShowLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
28 
AudioSinkFilter(const wchar_t * aObjectName,HRESULT * aOutResult)29 AudioSinkFilter::AudioSinkFilter(const wchar_t* aObjectName, HRESULT* aOutResult)
30   : BaseFilter(aObjectName, CLSID_MozAudioSinkFilter),
31     mFilterCritSec("AudioSinkFilter::mFilterCritSec")
32 {
33   (*aOutResult) = S_OK;
34   mInputPin = new AudioSinkInputPin(L"AudioSinkInputPin",
35                                     this,
36                                     &mFilterCritSec,
37                                     aOutResult);
38 }
39 
~AudioSinkFilter()40 AudioSinkFilter::~AudioSinkFilter()
41 {
42 }
43 
44 int
GetPinCount()45 AudioSinkFilter::GetPinCount()
46 {
47   return 1;
48 }
49 
50 BasePin*
GetPin(int aIndex)51 AudioSinkFilter::GetPin(int aIndex)
52 {
53   CriticalSectionAutoEnter lockFilter(mFilterCritSec);
54   return (aIndex == 0) ? static_cast<BasePin*>(mInputPin) : nullptr;
55 }
56 
57 HRESULT
Pause()58 AudioSinkFilter::Pause()
59 {
60   CriticalSectionAutoEnter lockFilter(mFilterCritSec);
61   if (mState == State_Stopped) {
62     //  Change the state, THEN activate the input pin.
63     mState = State_Paused;
64     if (mInputPin && mInputPin->IsConnected()) {
65       mInputPin->Active();
66     }
67   } else if (mState == State_Running) {
68     mState = State_Paused;
69   }
70   return S_OK;
71 }
72 
73 HRESULT
Stop()74 AudioSinkFilter::Stop()
75 {
76   CriticalSectionAutoEnter lockFilter(mFilterCritSec);
77   mState = State_Stopped;
78   if (mInputPin) {
79     mInputPin->Inactive();
80   }
81 
82   GetSampleSink()->Flush();
83 
84   return S_OK;
85 }
86 
87 HRESULT
Run(REFERENCE_TIME tStart)88 AudioSinkFilter::Run(REFERENCE_TIME tStart)
89 {
90   LOG("AudioSinkFilter::Run(%lld) [%4.2lf]",
91       RefTimeToUsecs(tStart),
92       double(RefTimeToUsecs(tStart)) / USECS_PER_S);
93   return media::BaseFilter::Run(tStart);
94 }
95 
96 HRESULT
GetClassID(OUT CLSID * pCLSID)97 AudioSinkFilter::GetClassID( OUT CLSID * pCLSID )
98 {
99   (* pCLSID) = CLSID_MozAudioSinkFilter;
100   return S_OK;
101 }
102 
103 HRESULT
QueryInterface(REFIID aIId,void ** aInterface)104 AudioSinkFilter::QueryInterface(REFIID aIId, void **aInterface)
105 {
106   if (aIId == IID_IMediaSeeking) {
107     *aInterface = static_cast<IMediaSeeking*>(this);
108     AddRef();
109     return S_OK;
110   }
111   return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface);
112 }
113 
114 ULONG
AddRef()115 AudioSinkFilter::AddRef()
116 {
117   return ::InterlockedIncrement(&mRefCnt);
118 }
119 
120 ULONG
Release()121 AudioSinkFilter::Release()
122 {
123   unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
124   if (!newRefCnt) {
125     delete this;
126   }
127   return newRefCnt;
128 }
129 
130 SampleSink*
GetSampleSink()131 AudioSinkFilter::GetSampleSink()
132 {
133   return mInputPin->GetSampleSink();
134 }
135 
136 
137 // IMediaSeeking implementation.
138 //
139 // Calls to IMediaSeeking are forwarded to the output pin that the
140 // AudioSinkInputPin is connected to, i.e. upstream towards the parser and
141 // source filters, which actually implement seeking.
142 #define ENSURE_CONNECTED_PIN_SEEKING \
143   if (!mInputPin) { \
144     return E_NOTIMPL; \
145   } \
146   RefPtr<IMediaSeeking> pinSeeking = mInputPin->GetConnectedPinSeeking(); \
147   if (!pinSeeking) { \
148     return E_NOTIMPL; \
149   }
150 
151 HRESULT
GetCapabilities(DWORD * aCapabilities)152 AudioSinkFilter::GetCapabilities(DWORD* aCapabilities)
153 {
154   ENSURE_CONNECTED_PIN_SEEKING
155   return pinSeeking->GetCapabilities(aCapabilities);
156 }
157 
158 HRESULT
CheckCapabilities(DWORD * aCapabilities)159 AudioSinkFilter::CheckCapabilities(DWORD* aCapabilities)
160 {
161   ENSURE_CONNECTED_PIN_SEEKING
162   return pinSeeking->CheckCapabilities(aCapabilities);
163 }
164 
165 HRESULT
IsFormatSupported(const GUID * aFormat)166 AudioSinkFilter::IsFormatSupported(const GUID* aFormat)
167 {
168   ENSURE_CONNECTED_PIN_SEEKING
169   return pinSeeking->IsFormatSupported(aFormat);
170 }
171 
172 HRESULT
QueryPreferredFormat(GUID * aFormat)173 AudioSinkFilter::QueryPreferredFormat(GUID* aFormat)
174 {
175   ENSURE_CONNECTED_PIN_SEEKING
176   return pinSeeking->QueryPreferredFormat(aFormat);
177 }
178 
179 HRESULT
GetTimeFormat(GUID * aFormat)180 AudioSinkFilter::GetTimeFormat(GUID* aFormat)
181 {
182   ENSURE_CONNECTED_PIN_SEEKING
183   return pinSeeking->GetTimeFormat(aFormat);
184 }
185 
186 HRESULT
IsUsingTimeFormat(const GUID * aFormat)187 AudioSinkFilter::IsUsingTimeFormat(const GUID* aFormat)
188 {
189   ENSURE_CONNECTED_PIN_SEEKING
190   return pinSeeking->IsUsingTimeFormat(aFormat);
191 }
192 
193 HRESULT
SetTimeFormat(const GUID * aFormat)194 AudioSinkFilter::SetTimeFormat(const GUID* aFormat)
195 {
196   ENSURE_CONNECTED_PIN_SEEKING
197   return pinSeeking->SetTimeFormat(aFormat);
198 }
199 
200 HRESULT
GetDuration(LONGLONG * aDuration)201 AudioSinkFilter::GetDuration(LONGLONG* aDuration)
202 {
203   ENSURE_CONNECTED_PIN_SEEKING
204   return pinSeeking->GetDuration(aDuration);
205 }
206 
207 HRESULT
GetStopPosition(LONGLONG * aStop)208 AudioSinkFilter::GetStopPosition(LONGLONG* aStop)
209 {
210   ENSURE_CONNECTED_PIN_SEEKING
211   return pinSeeking->GetStopPosition(aStop);
212 }
213 
214 HRESULT
GetCurrentPosition(LONGLONG * aCurrent)215 AudioSinkFilter::GetCurrentPosition(LONGLONG* aCurrent)
216 {
217   ENSURE_CONNECTED_PIN_SEEKING
218   return pinSeeking->GetCurrentPosition(aCurrent);
219 }
220 
221 HRESULT
ConvertTimeFormat(LONGLONG * aTarget,const GUID * aTargetFormat,LONGLONG aSource,const GUID * aSourceFormat)222 AudioSinkFilter::ConvertTimeFormat(LONGLONG* aTarget,
223                                    const GUID* aTargetFormat,
224                                    LONGLONG aSource,
225                                    const GUID* aSourceFormat)
226 {
227   ENSURE_CONNECTED_PIN_SEEKING
228   return pinSeeking->ConvertTimeFormat(aTarget,
229                                        aTargetFormat,
230                                        aSource,
231                                        aSourceFormat);
232 }
233 
234 HRESULT
SetPositions(LONGLONG * aCurrent,DWORD aCurrentFlags,LONGLONG * aStop,DWORD aStopFlags)235 AudioSinkFilter::SetPositions(LONGLONG* aCurrent,
236                               DWORD aCurrentFlags,
237                               LONGLONG* aStop,
238                               DWORD aStopFlags)
239 {
240   ENSURE_CONNECTED_PIN_SEEKING
241   return pinSeeking->SetPositions(aCurrent,
242                                   aCurrentFlags,
243                                   aStop,
244                                   aStopFlags);
245 }
246 
247 HRESULT
GetPositions(LONGLONG * aCurrent,LONGLONG * aStop)248 AudioSinkFilter::GetPositions(LONGLONG* aCurrent,
249                               LONGLONG* aStop)
250 {
251   ENSURE_CONNECTED_PIN_SEEKING
252   return pinSeeking->GetPositions(aCurrent, aStop);
253 }
254 
255 HRESULT
GetAvailable(LONGLONG * aEarliest,LONGLONG * aLatest)256 AudioSinkFilter::GetAvailable(LONGLONG* aEarliest,
257                               LONGLONG* aLatest)
258 {
259   ENSURE_CONNECTED_PIN_SEEKING
260   return pinSeeking->GetAvailable(aEarliest, aLatest);
261 }
262 
263 HRESULT
SetRate(double aRate)264 AudioSinkFilter::SetRate(double aRate)
265 {
266   ENSURE_CONNECTED_PIN_SEEKING
267   return pinSeeking->SetRate(aRate);
268 }
269 
270 HRESULT
GetRate(double * aRate)271 AudioSinkFilter::GetRate(double* aRate)
272 {
273   ENSURE_CONNECTED_PIN_SEEKING
274   return pinSeeking->GetRate(aRate);
275 }
276 
277 HRESULT
GetPreroll(LONGLONG * aPreroll)278 AudioSinkFilter::GetPreroll(LONGLONG* aPreroll)
279 {
280   ENSURE_CONNECTED_PIN_SEEKING
281   return pinSeeking->GetPreroll(aPreroll);
282 }
283 
284 } // namespace mozilla
285 
286