summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi.h
blob: 54ab00b1f871d557c942b3e4776713384c71c027 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * This file is part of mpv.
 *
 * Original author: Jonathan Yong <10walls@gmail.com>
 *
 * mpv is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * mpv is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with mpv.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MP_AO_WASAPI_H_
#define MP_AO_WASAPI_H_

#include <stdbool.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include <avrt.h>

#include "osdep/atomics.h"

typedef struct change_notify {
    IMMNotificationClient client; /* this must be first in the structure! */
    LPWSTR monitored; /* Monitored device */
    bool is_hotplug;
    struct ao *ao;
} change_notify;

HRESULT wasapi_change_init(struct ao* ao, bool is_hotplug);
void wasapi_change_uninit(struct ao* ao);

#define EXIT_ON_ERROR(hres)  \
              do { if (FAILED(hres)) { goto exit_label; } } while(0)
#define SAFE_RELEASE(unk, release) \
              do { if ((unk) != NULL) { release; (unk) = NULL; } } while(0)

enum wasapi_thread_state {
    WASAPI_THREAD_FEED = 0,
    WASAPI_THREAD_RESUME,
    WASAPI_THREAD_RESET,
    WASAPI_THREAD_SHUTDOWN
};

typedef struct wasapi_state {
    struct mp_log *log;

    // Thread handles
    HRESULT init_ret;        // status of init phase
    HANDLE hInitDone;        // set when init is complete in audio thread
    HANDLE hAudioThread;     // the audio thread itself
    HANDLE hWake;            // thread wakeup event
    atomic_int thread_state; // enum wasapi_thread_state (what to do on wakeup)

    // for setting the audio thread priority
    HANDLE hTask;

    // WASAPI object handles owned and used by audio thread
    IMMDevice *pDevice;
    IAudioClient *pAudioClient;
    IAudioRenderClient *pRenderClient;
    IMMDeviceEnumerator *pEnumerator;

    // WASAPI internal clock information, for estimating delay
    IAudioClock *pAudioClock;
    atomic_ullong sample_count;  // samples per channel written by GetBuffer
    UINT64 clock_frequency;      // scale for position returned by GetPosition
    LARGE_INTEGER qpc_frequency; // frequency of Windows' high resolution timer

    // WASAPI control (handles owned by audio thread but used by main thread)
    IAudioSessionControl *pSessionControl; // setting the stream title
    IAudioEndpointVolume *pEndpointVolume; // exclusive mode volume/mute
    ISimpleAudioVolume *pAudioVolume;      // shared mode volume/mute
    DWORD vol_hw_support; // is hardware volume supported for exclusive-mode?

    // Streams used to marshal the proxy objects. The thread owning the actual
    // objects needs to marshal proxy objects into these streams, and the thread
    // that wants the proxies unmarshals them from here.
    IStream *sSessionControl;
    IStream *sEndpointVolume;
    IStream *sAudioVolume;

    // WASAPI proxy handles, for Single-Threaded Apartment communication. One is
    // needed for each audio thread object that's accessed from the main thread.
    IAudioSessionControl *pSessionControlProxy;
    IAudioEndpointVolume *pEndpointVolumeProxy;
    ISimpleAudioVolume *pAudioVolumeProxy;

    // ao options
    int opt_exclusive;
    int opt_list;
    char *opt_device;

    // format info
    WAVEFORMATEXTENSIBLE format;
    AUDCLNT_SHAREMODE share_mode; // AUDCLNT_SHAREMODE_EXCLUSIVE / SHARED
    UINT32 bufferFrameCount;      // number of frames in buffer

    change_notify change;
} wasapi_state;

#endif