blob: 86863a41102a5b6b84480b4cbd11368aee8c2a25 [file] [log] [blame]
// Copyright 2022 The Cobalt Authors. 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.
#ifndef STARBOARD_SHARED_UWP_WASAPI_AUDIO_SINK_H_
#define STARBOARD_SHARED_UWP_WASAPI_AUDIO_SINK_H_
#include <Audioclient.h>
#include <endpointvolume.h>
#include <mmdeviceapi.h>
#include <wrl\client.h>
#include <atomic>
#include <functional>
#include <queue>
#include "starboard/common/atomic.h"
#include "starboard/common/log.h"
#include "starboard/common/mutex.h"
#include "starboard/common/ref_counted.h"
#include "starboard/shared/internal_only.h"
#include "starboard/shared/starboard/player/decoded_audio_internal.h"
#include "starboard/shared/starboard/player/job_thread.h"
#include "starboard/shared/starboard/thread_checker.h"
#include "starboard/shared/win32/wasapi_include.h"
#include "starboard/time.h"
namespace starboard {
namespace shared {
namespace uwp {
typedef enum __MIDL___MIDL_itf_mmdeviceapi_0000_0000_0001 {
eRender = 0,
eCapture,
eAll,
EDataFlow_enum_count
} EDataFlow;
typedef enum __MIDL___MIDL_itf_mmdeviceapi_0000_0000_0002 {
eConsole = 0,
eMultimedia,
eCommunications,
ERole_enum_count
} ERole;
MIDL_INTERFACE("D666063F-1587-4E43-81F1-B948E807363F")
IMMDevice : public IUnknown {
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Activate(
/* [annotation][in] */
_In_ REFIID iid,
/* [annotation][in] */
_In_ DWORD dwClsCtx,
/* [annotation][unique][in] */
_In_opt_ PROPVARIANT * pActivationParams,
/* [annotation][iid_is][out] */
_Out_ void** ppInterface) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OpenPropertyStore(
/* [annotation][in] */
_In_ DWORD stgmAccess,
/* [annotation][out] */
_Out_ IPropertyStore * *ppProperties) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetId(
/* [annotation][out] */
_Outptr_ LPWSTR * ppstrId) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetState(
/* [annotation][out] */
_Out_ DWORD * pdwState) = 0;
};
MIDL_INTERFACE("A95664D2-9614-4F35-A746-DE8DB63617E6")
IMMDeviceEnumerator : public IUnknown {
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ DWORD dwStateMask,
/* [annotation][out] */
_Out_ IMMDeviceCollection * *ppDevices) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE
GetDefaultAudioEndpoint(
/* [annotation][in] */
_In_ EDataFlow dataFlow,
/* [annotation][in] */
_In_ ERole role,
/* [annotation][out] */
_Out_ IMMDevice * *ppEndpoint) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDevice(
/* [annotation][in] */
_In_ LPCWSTR pwstrId,
/* [annotation][out] */
_Out_ IMMDevice * *ppDevice) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE
RegisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient * pClient) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE
UnregisterEndpointNotificationCallback(
/* [annotation][in] */
_In_ IMMNotificationClient * pClient) = 0;
};
const IID IID_IAudioClock = __uuidof(IAudioClock);
const IID IID_IAudioEndpointVolume = __uuidof(IAudioEndpointVolume);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_ISimpleAudioVolume = __uuidof(ISimpleAudioVolume);
class DECLSPEC_UUID("BCDE0395-E52F-467C-8E3D-C4579291692E") MMDeviceEnumerator;
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
using ::starboard::shared::starboard::player::DecodedAudio;
using ::starboard::shared::starboard::player::JobQueue;
using ::starboard::shared::starboard::player::JobThread;
class WASAPIAudioSink {
public:
WASAPIAudioSink();
~WASAPIAudioSink() {}
bool Initialize(int channels, int sample_rate, SbMediaAudioCodec audio_codec);
bool WriteBuffer(scoped_refptr<DecodedAudio> decoded_audio);
void Reset();
void Pause();
void Play();
void SetVolume(double volume);
void SetPlaybackRate(double playback_rate);
// GetCurrentPlaybackTime() can be called from any thread.
double GetCurrentPlaybackTime(uint64_t* updated_at);
bool playing() { return !paused_.load() && playback_rate_.load() > 0.0; }
private:
void OutputFrames();
void UpdatePlaybackState();
const int kMaxDecodedAudios = 16;
// The size of one (E)AC3 sync frame in IEC 61937 frames.
const int kAc3BufferSizeInFrames = 1536;
const int kEac3BufferSizeInFrames = 6144;
atomic_bool paused_{false};
atomic_double playback_rate_{0.0};
atomic_double volume_{0.0};
double current_volume_ = 0.0;
bool was_playing_ = false;
Microsoft::WRL::ComPtr<IMMDevice> device_;
Microsoft::WRL::ComPtr<IAudioClient3> audio_client_;
Microsoft::WRL::ComPtr<IAudioRenderClient> render_client_;
Microsoft::WRL::ComPtr<IAudioEndpointVolume> audio_endpoint_volume_;
Mutex audio_clock_mutex_;
Microsoft::WRL::ComPtr<IAudioClock> audio_clock_;
uint64_t audio_clock_frequency_;
uint32_t client_buffer_size_in_frames_ = 0;
int frames_per_audio_buffer_;
Mutex output_frames_mutex_;
std::queue<scoped_refptr<DecodedAudio>> pending_decoded_audios_;
scoped_ptr<JobThread> job_thread_;
starboard::ThreadChecker thread_checker_;
};
} // namespace uwp
} // namespace shared
} // namespace starboard
#endif // STARBOARD_SHARED_UWP_WASAPI_AUDIO_SINK_H_