summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi.h
blob: 5ba2aa325c81252a9a21dc38aa8b2bab85bb4779 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * 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 <stdlib.h>
#include <stdbool.h>
#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <endpointvolume.h>

#include "common/msg.h"
#include "osdep/atomics.h"
#include "osdep/windows_utils.h"
#include "internal.h"
#include "ao.h"

typedef struct change_notify {
    IMMNotificationClient client; // this must be first in the structure!
    IMMDeviceEnumerator *pEnumerator; // object where client is registered
    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;

    // ID of the device to use
    LPWSTR deviceID;
    // WASAPI object handles owned and used by audio thread
    IMMDevice *pDevice;
    IAudioClient *pAudioClient;
    IAudioRenderClient *pRenderClient;

    // 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;

char *mp_PKEY_to_str_buf(char *buf, size_t buf_size, const PROPERTYKEY *pkey);
#define mp_PKEY_to_str(pkey) mp_PKEY_to_str_buf((char[42]){0}, 42, (pkey))

void wasapi_list_devs(struct ao *ao, struct ao_device_list *list);
LPWSTR find_deviceID(struct ao *ao);

void wasapi_dispatch(struct ao *ao);
HRESULT wasapi_thread_init(struct ao *ao);
void wasapi_thread_uninit(struct ao *ao);

void wasapi_receive_proxies(wasapi_state *state);
void wasapi_release_proxies(wasapi_state *state);

#endif