summaryrefslogtreecommitdiff
path: root/src/lib/ecore_audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ecore_audio')
-rw-r--r--src/lib/ecore_audio/Ecore_Audio.h50
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj.h22
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_in.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_in_tone.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_pulse.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h23
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_wasapi.c609
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_wasapi.h22
-rw-r--r--src/lib/ecore_audio/ecore_audio_out_wasapi.eo18
11 files changed, 685 insertions, 174 deletions
diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h
index 0cc7bec..e508c9a 100644
--- a/src/lib/ecore_audio/Ecore_Audio.h
+++ b/src/lib/ecore_audio/Ecore_Audio.h
@@ -8,15 +8,27 @@
8#undef EAPI 8#undef EAPI
9#endif 9#endif
10 10
11#ifdef __GNUC__ 11#ifdef _WIN32
12#if __GNUC__ >= 4 12# ifdef EFL_ECORE_AUDIO_BUILD
13#define EAPI __attribute__ ((visibility("default"))) 13# ifdef DLL_EXPORT
14# define EAPI __declspec(dllexport)
15# else
16# define EAPI
17# endif /* ! DLL_EXPORT */
18# else
19# define EAPI __declspec(dllimport)
20# endif /* ! EFL_ECORE_AUDIO_BUILD */
14#else 21#else
15#define EAPI 22# ifdef __GNUC__
16#endif 23# if __GNUC__ >= 4
17#else 24# define EAPI __attribute__ ((visibility("default")))
18#define EAPI 25# else
19#endif 26# define EAPI
27# endif
28# else
29# define EAPI
30# endif
31#endif /* ! _WIN32 */
20 32
21/** 33/**
22 * @file Ecore_Audio.h 34 * @file Ecore_Audio.h
@@ -46,6 +58,7 @@ enum _Ecore_Audio_Type {
46 ECORE_AUDIO_TYPE_TONE, /**< Use tone module */ 58 ECORE_AUDIO_TYPE_TONE, /**< Use tone module */
47 ECORE_AUDIO_TYPE_CORE_AUDIO, /**< Use Core Audio module (Apple) - DEPRECATED */ 59 ECORE_AUDIO_TYPE_CORE_AUDIO, /**< Use Core Audio module (Apple) - DEPRECATED */
48 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */ 60 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */
61 ECORE_AUDIO_TYPE_WASAPI, /**< Use Wasapi module @since 1.21*/
49 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */ 62 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */
50}; 63};
51 64
@@ -179,11 +192,6 @@ EAPI int ecore_audio_init(void);
179 */ 192 */
180EAPI int ecore_audio_shutdown(void); 193EAPI int ecore_audio_shutdown(void);
181 194
182
183#ifdef __cplusplus
184}
185#endif
186
187#include <ecore_audio_obj.h> 195#include <ecore_audio_obj.h>
188#include <ecore_audio_obj_in.h> 196#include <ecore_audio_obj_in.h>
189#include <ecore_audio_obj_out.h> 197#include <ecore_audio_obj_out.h>
@@ -193,12 +201,26 @@ EAPI int ecore_audio_shutdown(void);
193 201
194#include <ecore_audio_obj_in_tone.h> 202#include <ecore_audio_obj_in_tone.h>
195 203
196#include <ecore_audio_obj_out_pulse.h> 204#if HAVE_PULSE
205# include <ecore_audio_obj_out_pulse.h>
206# define ECORE_AUDIO_OUT_RENDER_CLASS ECORE_AUDIO_OUT_PULSE_CLASS
207# define ECORE_AUDIO_OUT_RENDER_EVENT_CONTEXT_FAIL ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL
208#endif
209
210#if HAVE_WASAPI
211# include <ecore_audio_obj_out_wasapi.h>
212# define ECORE_AUDIO_OUT_RENDER_CLASS ECORE_AUDIO_OUT_WASAPI_CLASS
213# define ECORE_AUDIO_OUT_RENDER_EVENT_CONTEXT_FAIL ECORE_AUDIO_OUT_WASAPI_EVENT_CONTEXT_FAIL
214#endif
197 215
198/** 216/**
199 * @} 217 * @}
200 */ 218 */
201 219
220#ifdef __cplusplus
221}
222#endif
223
202#undef EAPI 224#undef EAPI
203#define EAPI 225#define EAPI
204 226
diff --git a/src/lib/ecore_audio/ecore_audio_obj.h b/src/lib/ecore_audio/ecore_audio_obj.h
index 55acca2..cb74281 100644
--- a/src/lib/ecore_audio/ecore_audio_obj.h
+++ b/src/lib/ecore_audio/ecore_audio_obj.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj.h 8 * @file ecore_audio_obj.h
23 * @brief Base Ecore_Audio object. 9 * @brief Base Ecore_Audio object.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj - Base Ecore_Audio object 13 * @defgroup ecore_audio_obj - Base Ecore_Audio object
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -37,8 +18,5 @@ extern "C"
37/** 18/**
38 * @} 19 * @}
39 */ 20 */
40#ifdef __cplusplus
41}
42#endif
43 21
44#endif 22#endif
diff --git a/src/lib/ecore_audio/ecore_audio_obj_in.h b/src/lib/ecore_audio/ecore_audio_obj_in.h
index 003d5f7..9dc0760 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_in.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_in.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_in.h 8 * @file ecore_audio_obj_in.h
23 * @brief Ecore_Audio Input Object. 9 * @brief Ecore_Audio Input Object.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_in - Ecore_Audio input object 13 * @defgroup ecore_audio_obj_in - Ecore_Audio input object
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -38,8 +19,4 @@ extern "C"
38 * @} 19 * @}
39 */ 20 */
40 21
41#ifdef __cplusplus
42}
43#endif 22#endif
44
45#endif \ No newline at end of file
diff --git a/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h b/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h
index cbd7769..ca8908e 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_in_sndfile.h 8 * @file ecore_audio_obj_in_sndfile.h
23 * @brief Ecore_Audio sndfile input. 9 * @brief Ecore_Audio sndfile input.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_in_sndfile - Ecore_Audio sndfile input 13 * @defgroup ecore_audio_obj_in_sndfile - Ecore_Audio sndfile input
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -38,8 +19,4 @@ extern "C"
38 * @} 19 * @}
39 */ 20 */
40 21
41#ifdef __cplusplus
42}
43#endif 22#endif
44
45#endif \ No newline at end of file
diff --git a/src/lib/ecore_audio/ecore_audio_obj_in_tone.h b/src/lib/ecore_audio/ecore_audio_obj_in_tone.h
index e25a331..b393aad 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_in_tone.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_in_tone.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_in_tone.h 8 * @file ecore_audio_obj_in_tone.h
23 * @brief Ecore_Audio tone input. 9 * @brief Ecore_Audio tone input.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_in_tone - Ecore_Audio tone input 13 * @defgroup ecore_audio_obj_in_tone - Ecore_Audio tone input
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -47,8 +28,4 @@ extern "C"
47 * @} 28 * @}
48 */ 29 */
49 30
50#ifdef __cplusplus
51}
52#endif
53
54#endif 31#endif
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out.h b/src/lib/ecore_audio/ecore_audio_obj_out.h
index 5433a7f..1aa33e0 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_out.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_out.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_out.h 8 * @file ecore_audio_obj_out.h
23 * @brief Ecore_Audio output object. 9 * @brief Ecore_Audio output object.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_out - Ecore_Audio output object 13 * @defgroup ecore_audio_obj_out - Ecore_Audio output object
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -38,8 +19,4 @@ extern "C"
38 * @} 19 * @}
39 */ 20 */
40 21
41#ifdef __cplusplus
42}
43#endif 22#endif
44
45#endif \ No newline at end of file
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h
index ec0ac15..94fd352 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_out_pulse.h 8 * @file ecore_audio_obj_out_pulse.h
23 * @brief Ecore_Audio pulseaudio output. 9 * @brief Ecore_Audio pulseaudio output.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_out_pulse - Ecore_Audio pulseaudio output 13 * @defgroup ecore_audio_obj_out_pulse - Ecore_Audio pulseaudio output
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -38,8 +19,4 @@ extern "C"
38 * @} 19 * @}
39 */ 20 */
40 21
41#ifdef __cplusplus
42}
43#endif 22#endif
44
45#endif \ No newline at end of file
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h b/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h
index f2b807d..9f5fac8 100644
--- a/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h
@@ -4,30 +4,11 @@
4#include <Eina.h> 4#include <Eina.h>
5#include <Eo.h> 5#include <Eo.h>
6 6
7#ifdef EAPI
8#undef EAPI
9#endif
10
11#ifdef __GNUC__
12#if __GNUC__ >= 4
13#define EAPI __attribute__ ((visibility("default")))
14#else
15#define EAPI
16#endif
17#else
18#define EAPI
19#endif
20
21/** 7/**
22 * @file ecore_audio_obj_out_sndfile.h 8 * @file ecore_audio_obj_out_sndfile.h
23 * @brief Ecore_Audio sndfile output. 9 * @brief Ecore_Audio sndfile output.
24 */ 10 */
25 11
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31/** 12/**
32 * @defgroup ecore_audio_obj_out_sndfile - Ecore_Audio sndfile output 13 * @defgroup ecore_audio_obj_out_sndfile - Ecore_Audio sndfile output
33 * @ingroup Ecore_Audio_Group 14 * @ingroup Ecore_Audio_Group
@@ -38,8 +19,4 @@ extern "C"
38 * @} 19 * @}
39 */ 20 */
40 21
41#ifdef __cplusplus
42}
43#endif
44
45#endif 22#endif
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.c b/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.c
new file mode 100644
index 0000000..899a0f9
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.c
@@ -0,0 +1,609 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <string.h>
8
9#include <Eo.h>
10#include "ecore_audio_private.h"
11
12#define INITGUID
13#include <initguid.h>
14#include <functiondiscoverykeys.h>
15#include <audioclient.h>
16#include <audiopolicy.h>
17#include <endpointvolume.h>
18#include <mmdeviceapi.h>
19#include <mmreg.h>
20#include <wtypes.h>
21#include <rpc.h>
22#include <rpcdce.h>
23#include <propkey.h>
24
25#define MY_CLASS ECORE_AUDIO_OUT_WASAPI_CLASS
26#define MY_CLASS_NAME "Ecore_Audio_Out_Wasapi"
27
28#define REFTIMES_PER_SEC 10000000
29#define REFTIMES_PER_MILLISEC 10000
30
31static int client_connect_count = 0;
32
33DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName,0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10);
34
35struct _Ecore_Audio_Wasapi_Class {
36
37 Ecore_Job *state_job;
38 Eina_List *outputs;
39};
40
41typedef struct _Ecore_Audio_Out_Wasapi_Device Ecore_Audio_Out_Wasapi_Device;
42typedef struct _Ecore_Audio_Out_Wasapi_Data Ecore_Audio_Out_Wasapi_Data;
43
44struct _Ecore_Audio_Out_Wasapi_Device
45{
46 IMMDevice *pDevice;
47 IMMDeviceEnumerator *pDeviceEnumerator;
48};
49
50struct _Ecore_Audio_Out_Wasapi_Data
51{
52 Eo *in;
53 Eo *out;
54 IAudioClient *client;
55 IAudioRenderClient *render;
56 IAudioStreamVolume *volume;
57 WAVEFORMATEXTENSIBLE *wave_format;
58 HANDLE event;
59 UINT32 NumBufferFrames;
60 Eina_Bool spec_format;
61 Eina_Bool play;
62};
63
64Ecore_Audio_Out_Wasapi_Device *device = NULL;
65
66EOLIAN static void
67_ecore_audio_out_wasapi_ecore_audio_volume_set(Eo *eo_obj EINA_UNUSED, Ecore_Audio_Out_Wasapi_Data *_pd, double volume)
68{
69 HRESULT hr;
70 UINT32 count;
71 const float volumes = volume;
72
73 hr = _pd->client->lpVtbl->GetService(_pd->client,
74 &IID_IAudioStreamVolume,
75 (void**)&(_pd->volume));
76
77 if (hr != S_OK)
78 {
79 ERR("GetService does not have access to the IID_IAudioStreamVolume interface.");
80 return;
81 }
82
83 hr = _pd->volume->lpVtbl->GetChannelCount(_pd->volume, &count);
84 if (hr != S_OK)
85 {
86 ERR("The GetChannelCount method can not to gets a count of the channels.");
87 return;
88 }
89
90 hr = _pd->volume->lpVtbl->SetAllVolumes(_pd->volume, count, &volumes);
91 if (hr != S_OK)
92 {
93 ERR("The SetAllVolumes method can not to sets the individual volume levels for all the channels in the audio stream.");
94 return;
95 }
96}
97
98
99static void
100_close_cb(void *data, const Efl_Event *event EINA_UNUSED)
101{
102 Ecore_Audio_Out_Wasapi_Data *_pd = data;
103
104 if (_pd->event) CloseHandle(_pd->event);
105 if (_pd->render) _pd->render->lpVtbl->Release(_pd->render);
106 if (_pd->client) _pd->client->lpVtbl->Release(_pd->client);
107
108 _pd->event = NULL;
109 _pd->render = NULL;
110 _pd->client = NULL;
111 _pd->play = EINA_FALSE;
112}
113
114static void
115_samplerate_changed_cb(void *data, const Efl_Event *event EINA_UNUSED)
116{
117 HRESULT hr;
118
119 IAudioClient *client;
120 IAudioClockAdjustment *adjustment;
121 Ecore_Audio_Out_Wasapi_Data *_pd;
122
123 double sr;
124 double speed;
125 unsigned int samplerate;
126
127 _pd = data;
128 client = _pd->client;
129
130 speed = ecore_audio_obj_in_speed_get(_pd->in);
131 samplerate = ecore_audio_obj_in_samplerate_get(_pd->in);
132 samplerate = samplerate * speed;
133
134 hr = client->lpVtbl->GetService(client,
135 &IID_IAudioClockAdjustment,
136 (void**)&(adjustment));
137 if (hr != S_OK)
138 {
139 ERR("GetService does not have access to the IID_IAudioClockAdjustments interface.");
140 return;
141 }
142
143 sr = (REFERENCE_TIME)(_pd->NumBufferFrames / samplerate);
144 adjustment->lpVtbl->SetSampleRate(adjustment, sr);
145}
146
147
148static Eina_Bool
149_write_cb(void *data, Ecore_Win32_Handler *wh EINA_UNUSED)
150{
151 Ecore_Audio_Out_Wasapi_Data *_pd;
152
153 HRESULT hr;
154 BYTE *pData;
155 UINT32 numAvailableFrames;
156 UINT32 numPaddingFrames;
157 int nBlockAlign;
158 ssize_t bread;
159
160 _pd = data;
161 pData = NULL;
162 numPaddingFrames = 0;
163 bread = 0;
164
165 nBlockAlign = _pd->wave_format->Format.nBlockAlign;
166
167 hr = (_pd->client->lpVtbl->GetBufferSize(_pd->client, &(_pd->NumBufferFrames)));
168 if (hr != S_OK)
169 {
170 ERR("The GetBufferSize does not can retrieves the size (maximum capacity) of the endpoint buffer.");
171 return ECORE_CALLBACK_CANCEL;
172 }
173
174 if (!_pd->render)
175 {
176 hr = _pd->client->lpVtbl->GetService(_pd->client,
177 &IID_IAudioRenderClient,
178 (void**)&(_pd->render));
179 if (hr != S_OK)
180 {
181 ERR("GetService does not have access to the IID_IAudioRenderClient interface.");
182 return ECORE_CALLBACK_CANCEL;
183 }
184 }
185
186 numPaddingFrames = 0;
187 hr = _pd->client->lpVtbl->GetCurrentPadding(_pd->client, &(numPaddingFrames));
188 if (hr == S_OK)
189 {
190 numAvailableFrames = _pd->NumBufferFrames - numPaddingFrames;
191 if (numAvailableFrames == 0) return ECORE_CALLBACK_RENEW;
192
193 hr = _pd->render->lpVtbl->GetBuffer(_pd->render, numAvailableFrames, &pData);
194 if (hr == S_OK)
195 {
196 bread = ecore_audio_obj_in_read(_pd->in, pData, nBlockAlign*numAvailableFrames);
197 if (bread > 0)
198 {
199 if (bread < (nBlockAlign * numAvailableFrames))
200 memset((char *)pData + bread, 0, (nBlockAlign * numAvailableFrames) - bread);
201
202 hr = _pd->render->lpVtbl->ReleaseBuffer(_pd->render, (UINT32)(bread / nBlockAlign), 0);
203 if (hr == S_OK)
204 {
205 if ((bread % nBlockAlign) == 0) return ECORE_CALLBACK_RENEW;
206 }
207 else
208 {
209 ERR("ReleaseBuffer method cannot releases the buffer space acquired in the previous call to the IAudioRenderClient::GetBuffer method.");
210 }
211 }
212 }
213 else
214 {
215 ERR("GetBuffer method cannot retrieves a pointer to the next available space in the rendering endpoint buffer into which the caller can write a data packet.");
216 }
217 }
218 else
219 {
220 ERR("GetCurrentPadding method cannot retrieves the number of frames of padding in the endpoint buffer.");
221 }
222
223 if (_pd->client) _pd->client->lpVtbl->Stop(_pd->client);
224
225 ecore_main_win32_handler_del(_pd->event);
226 efl_event_callback_call(_pd->out, ECORE_AUDIO_OUT_WASAPI_EVENT_STOP, NULL);
227
228 _pd->play = EINA_FALSE;
229
230 return ECORE_CALLBACK_CANCEL;
231}
232
233static Eina_Bool
234wave_format_selection(Ecore_Audio_Out_Wasapi_Data *_pd, Eo *in)
235{
236 HRESULT hr;
237
238 IAudioClient *client;
239 WAVEFORMATEXTENSIBLE *buff;
240 WAVEFORMATEXTENSIBLE *correct_wave_format;
241
242 double speed;
243 unsigned int channels;
244 unsigned int samplerate;
245
246 client = _pd->client;
247 buff = NULL;
248 correct_wave_format = NULL;
249
250 speed = ecore_audio_obj_in_speed_get(in);
251 channels = ecore_audio_obj_in_channels_get(in);
252 samplerate = ecore_audio_obj_in_samplerate_get(in);
253 samplerate = samplerate * speed;
254
255 if (_pd->spec_format)
256 {
257 CoTaskMemFree(_pd->wave_format);
258 _pd->wave_format = NULL;
259 _pd->spec_format = EINA_FALSE;
260 }
261
262 hr = client->lpVtbl->GetMixFormat(client, (WAVEFORMATEX **)&(buff));
263 if (hr != S_OK)
264 {
265 return EINA_FALSE;
266 }
267
268 buff->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
269 buff->Format.nChannels = channels;
270 buff->Format.nSamplesPerSec = samplerate;
271 buff->Format.nBlockAlign = (buff->Format.nChannels * buff->Format.wBitsPerSample) / 8;
272 buff->Format.nAvgBytesPerSec = buff->Format.nSamplesPerSec * buff->Format.nBlockAlign;
273 buff->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
274 buff->dwChannelMask = 0;
275
276 switch(channels)
277 {
278 case 1:
279 buff->dwChannelMask = KSAUDIO_SPEAKER_MONO;
280 break;
281 case 2:
282 buff->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
283 break;
284 case 4:
285 buff->dwChannelMask = KSAUDIO_SPEAKER_QUAD;
286 break;
287 case 6:
288 buff->dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
289 break;
290 case 8:
291 buff->dwChannelMask = KSAUDIO_SPEAKER_7POINT1;
292 break;
293 default:
294 buff->dwChannelMask = 0;
295 break;
296 }
297
298 buff->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
299
300 hr = client->lpVtbl->IsFormatSupported(client,
301 AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX *)buff,
302 (WAVEFORMATEX **)&correct_wave_format);
303 switch (hr)
304 {
305 case S_OK:
306 _pd->wave_format = buff;
307 return EINA_TRUE;
308 case S_FALSE:
309 ERR("Succeeded with a closest match to the specified format.");
310 _pd->spec_format = EINA_TRUE;
311 _pd->wave_format = correct_wave_format;
312 return EINA_TRUE;
313 case E_POINTER:
314 ERR("code: E_POINTER");
315 return EINA_FALSE;
316 case E_INVALIDARG:
317 ERR("code: E_INVALIDARG");
318 return EINA_FALSE;
319 case AUDCLNT_E_DEVICE_INVALIDATED:
320 ERR("code: AUDCLNT_E_DEVICE_INVALIDATED");
321 return EINA_FALSE;
322 case AUDCLNT_E_SERVICE_NOT_RUNNING:
323 ERR("code: AUDCLNT_E_SERVICE_NOT_RUNNING");
324 return EINA_FALSE;
325 default:
326 ERR("IsFormatSupported - return code is unknown");
327 return EINA_FALSE;
328 }
329 return EINA_TRUE;
330}
331
332
333static Eina_Bool
334_client_initialize( Ecore_Audio_Out_Wasapi_Data *_pd )
335{
336 HRESULT hr;
337 IAudioClient *client;
338 REFERENCE_TIME hnsRequestedDuration;
339 WAVEFORMATEXTENSIBLE *correct_wave_format;
340 DWORD flags;
341 int nbf;
342 int sps;
343
344 client = _pd->client;
345 hnsRequestedDuration = REFTIMES_PER_SEC;
346 correct_wave_format = _pd->wave_format;
347 flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_RATEADJUST | AUDCLNT_STREAMFLAGS_NOPERSIST;
348
349 hr = client->lpVtbl->GetDevicePeriod(client, NULL, &hnsRequestedDuration);
350
351 hr = client->lpVtbl->Initialize(client,
352 AUDCLNT_SHAREMODE_SHARED,
353 flags,
354 hnsRequestedDuration,
355 hnsRequestedDuration,
356 (WAVEFORMATEX *)correct_wave_format,
357 NULL);
358 switch (hr)
359 {
360 case S_OK:
361 break;
362 case AUDCLNT_E_ALREADY_INITIALIZED:
363 ERR("code: AUDCLNT_E_ALREADY_INITIALIZED");
364 return EINA_FALSE;
365 case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
366 ERR("code: AUDCLNT_E_WRONG_ENDPOINT_TYPE");
367 return EINA_FALSE;
368 case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
369 ERR("code: AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED");
370
371 hr = client->lpVtbl->GetBufferSize(client, &(_pd->NumBufferFrames));
372 if (hr != S_OK)
373 {
374 ERR("The GetBufferSize does not can retrieves the size (maximum capacity) of the endpoint buffer.");
375 return EINA_FALSE;
376 }
377
378 nbf = _pd->NumBufferFrames;
379 sps = correct_wave_format->Format.nSamplesPerSec;
380
381 //*Calculate the aligned buffer size in 100-nansecond units (hns).(https://msdn.microsoft.com/en-us/library/windows/desktop/dd370875(v=vs.85).aspx)*//
382 hnsRequestedDuration = (REFERENCE_TIME)(((REFTIMES_PER_SEC * nbf) / sps) + 0.5);
383 if (client)
384 client->lpVtbl->Release(client);
385
386 hr = device->pDevice->lpVtbl->Activate(device->pDevice,
387 &IID_IAudioClient,
388 CLSCTX_ALL,
389 NULL,
390 (void**)&(client));
391 if (hr != S_OK)
392 {
393 ERR("The Activate method cannot create a COM object with the specified interface.");
394 return EINA_FALSE;
395 }
396
397 hr = client->lpVtbl->GetMixFormat(client, (WAVEFORMATEX **)&(correct_wave_format));
398 if (hr != S_OK)
399 {
400 ERR("The GetMixFormat cannot retrieves the stream format that the audio engine uses for its internal processing of shared-mode streams.");
401 return EINA_FALSE;
402 }
403
404 hr = client->lpVtbl->Initialize(client,
405 AUDCLNT_SHAREMODE_SHARED,
406 flags,
407 hnsRequestedDuration,
408 hnsRequestedDuration,
409 (WAVEFORMATEX *)correct_wave_format,
410 NULL);
411
412 if (hr != S_OK) return EINA_FALSE;
413 return EINA_TRUE;
414 case AUDCLNT_E_BUFFER_SIZE_ERROR:
415 ERR("code: AUDCLNT_E_BUFFER_SIZE_ERROR");
416 return EINA_FALSE;
417 case AUDCLNT_E_CPUUSAGE_EXCEEDED:
418 ERR("code: AUDCLNT_E_CPUUSAGE_EXCEEDED");
419 return EINA_FALSE;
420 case AUDCLNT_E_DEVICE_INVALIDATED:
421 ERR("code: AUDCLNT_E_DEVICE_INVALIDATED");
422 return EINA_FALSE;
423 case AUDCLNT_E_DEVICE_IN_USE:
424 ERR("code: AUDCLNT_E_DEVICE_IN_USE");
425 return EINA_FALSE;
426 case AUDCLNT_E_ENDPOINT_CREATE_FAILED:
427 ERR("code: AUDCLNT_E_ENDPOINT_CREATE_FAILED");
428 return EINA_FALSE;
429 case AUDCLNT_E_INVALID_DEVICE_PERIOD:
430 ERR("code: AUDCLNT_E_INVALID_DEVICE_PERIOD");
431 return EINA_FALSE;
432 case AUDCLNT_E_UNSUPPORTED_FORMAT:
433 ERR("code: AUDCLNT_E_UNSUPPORTED_FORMAT");
434 return EINA_FALSE;
435 case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:
436 ERR("code: AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED");
437 return EINA_FALSE;
438 case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:
439 ERR("code: AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL");
440 return EINA_FALSE;
441 case AUDCLNT_E_SERVICE_NOT_RUNNING:
442 ERR("code: AUDCLNT_E_SERVICE_NOT_RUNNING");
443 return EINA_FALSE;
444 case E_POINTER:
445 ERR("code: E_POINTER");
446 return EINA_FALSE;
447 case E_INVALIDARG:
448 ERR("code: E_INVALIDARG");
449 return EINA_FALSE;
450 case E_OUTOFMEMORY:
451 ERR("code: E_OUTOFMEMORY");
452 return EINA_FALSE;
453 default:
454 ERR("code: ");
455 return EINA_FALSE;
456 }
457 if (!_pd->event )
458 {
459 _pd->event = CreateEvent(NULL, 0, 0, NULL);
460 hr = client->lpVtbl->SetEventHandle(client, _pd->event);
461 if (hr != S_OK) return EINA_FALSE;
462 }
463
464 return EINA_TRUE;
465}
466
467static Eina_Bool
468_input_attach_internal(Eo *eo_obj EINA_UNUSED, Eo *in, Ecore_Audio_Out_Wasapi_Data *_pd)
469{
470 HRESULT hr;
471
472 if (!device || !device->pDevice) return EINA_FALSE;
473
474 if (!_pd->client)
475 {
476 hr = device->pDevice->lpVtbl->Activate(device->pDevice,
477 &IID_IAudioClient,
478 CLSCTX_ALL,
479 NULL,
480 (void**)&(_pd->client));
481 if (hr != S_OK)
482 {
483 ERR("The Activate method cannot create a COM object with the specified interface.");
484 return EINA_FALSE;
485 }
486 }
487
488 if (!wave_format_selection( _pd, in))
489 return EINA_FALSE;
490
491 if (!_client_initialize(_pd))
492 return EINA_FALSE;
493
494 _pd->in = in;
495
496 return EINA_TRUE;
497}
498
499EOLIAN static Eina_Bool
500_ecore_audio_out_wasapi_ecore_audio_out_input_attach(Eo *eo_obj, Ecore_Audio_Out_Wasapi_Data *_pd, Eo *in)
501{
502 Eina_Bool ret = ecore_audio_obj_out_input_attach(efl_super(eo_obj, MY_CLASS), in);
503
504 if (!ret) return EINA_FALSE;
505 if (!device) return EINA_FALSE;
506 if (_pd->play) return EINA_TRUE;
507 if (!_input_attach_internal(eo_obj, in, _pd)) return EINA_FALSE;
508
509 ecore_main_win32_handler_add(_pd->event, _write_cb, _pd);
510 efl_event_callback_add(in, ECORE_AUDIO_IN_EVENT_IN_SAMPLERATE_CHANGED, _samplerate_changed_cb, eo_obj);
511 efl_event_callback_add(eo_obj, ECORE_AUDIO_OUT_WASAPI_EVENT_STOP, _close_cb, _pd);
512
513 _pd->play = EINA_TRUE;
514 _pd->out = eo_obj;
515 _pd->client->lpVtbl->Start(_pd->client);
516
517 return EINA_TRUE;
518}
519
520EOLIAN static Eina_Bool
521_ecore_audio_out_wasapi_ecore_audio_out_input_detach(Eo *eo_obj, Ecore_Audio_Out_Wasapi_Data *_pd EINA_UNUSED, Eo *in)
522{
523 Eina_Bool ret = ecore_audio_obj_out_input_detach(efl_super(eo_obj, MY_CLASS), in);
524 if (!ret) return EINA_FALSE;
525
526 efl_event_callback_call(_pd->out, ECORE_AUDIO_OUT_WASAPI_EVENT_STOP, NULL);
527 return EINA_TRUE;
528}
529
530EOLIAN static Eo *
531_ecore_audio_out_wasapi_efl_object_constructor(Eo *eo_obj, Ecore_Audio_Out_Wasapi_Data *_pd EINA_UNUSED)
532{
533 HRESULT hr;
534
535 if (!device)
536 {
537 device = calloc(1, sizeof(Ecore_Audio_Out_Wasapi_Device));
538 if (!device) return NULL;
539 }
540
541 if (device->pDeviceEnumerator && device->pDevice)
542 {
543 client_connect_count++;
544 eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
545 Ecore_Audio_Output *out_obj = efl_data_scope_get(eo_obj, ECORE_AUDIO_OUT_CLASS);
546 out_obj->need_writer = EINA_FALSE;
547 return eo_obj;
548 }
549
550 hr = CoInitialize(NULL);
551
552 if (hr == S_OK || hr == S_FALSE)
553 {
554 if (device->pDeviceEnumerator)
555 device->pDeviceEnumerator->lpVtbl->Release(device->pDeviceEnumerator);
556
557 if (device->pDevice)
558 device->pDevice->lpVtbl->Release(device->pDevice);
559
560 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator,
561 NULL,
562 CLSCTX_ALL,
563 &IID_IMMDeviceEnumerator,
564 (void**)&(device->pDeviceEnumerator));
565 if (hr == S_OK)
566 {
567 hr = device->pDeviceEnumerator->lpVtbl->GetDefaultAudioEndpoint(device->pDeviceEnumerator,
568 eRender,
569 eMultimedia,
570 &(device->pDevice));
571 if (hr == S_OK)
572 {
573 client_connect_count++;
574 eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
575 Ecore_Audio_Output *out_obj = efl_data_scope_get(eo_obj, ECORE_AUDIO_OUT_CLASS);
576 out_obj->need_writer = EINA_FALSE;
577 return eo_obj;
578 }
579 device->pDeviceEnumerator->lpVtbl->Release(device->pDeviceEnumerator);
580 }
581 }
582
583 CoUninitialize();
584 free(device);
585 device = NULL;
586 return NULL;
587}
588
589EOLIAN static void
590_ecore_audio_out_wasapi_efl_object_destructor(Eo *eo_obj, Ecore_Audio_Out_Wasapi_Data *_pd EINA_UNUSED)
591{
592 client_connect_count--;
593 efl_destructor(efl_super(eo_obj, MY_CLASS));
594
595 if (!client_connect_count)
596 {
597 if (device->pDevice)
598 device->pDevice->lpVtbl->Release(device->pDevice);
599
600 if (device->pDeviceEnumerator)
601 device->pDeviceEnumerator->lpVtbl->Release(device->pDeviceEnumerator);
602
603 free(device);
604 device = NULL;
605 CoUninitialize();
606 }
607}
608
609#include "ecore_audio_out_wasapi.eo.c"
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.h b/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.h
new file mode 100644
index 0000000..87457e0
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_wasapi.h
@@ -0,0 +1,22 @@
1#ifndef __ECORE_AUDIO_OUT_WASAPI_H__
2#define __ECORE_AUDIO_OUT_WASAPI_H__
3
4#include <Eina.h>
5#include <Eo.h>
6
7/**
8 * @file ecore_audio_obj_out_wasapi.h
9 * @brief Ecore_Audio wasapi output.
10 */
11
12/**
13 * @defgroup ecore_audio_obj_out_wasapi - Ecore_Audio wasapi output
14 * @ingroup Ecore_Audio_Group
15 * @{
16 */
17#include "ecore_audio_out_wasapi.eo.h"
18/**
19 * @}
20 */
21
22#endif /* __ECORE_AUDIO_OUT_WASAPI_H__ */
diff --git a/src/lib/ecore_audio/ecore_audio_out_wasapi.eo b/src/lib/ecore_audio/ecore_audio_out_wasapi.eo
new file mode 100644
index 0000000..fd362f1
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_out_wasapi.eo
@@ -0,0 +1,18 @@
1class Ecore.Audio.Out.Wasapi (Ecore.Audio.Out)
2{
3 [[Ecore audio ouput for WasapiAudio.]]
4 eo_prefix: ecore_audio_obj_out_wasapi;
5 event_prefix: ecore_audio_out_wasapi;
6 implements {
7 Efl.Object.constructor;
8 Efl.Object.destructor;
9 Ecore.Audio.volume { set;}
10 Ecore.Audio.Out.input_attach;
11 Ecore.Audio.Out.input_detach;
12 }
13 events {
14 context,ready; [[Called when the output is ready for playback.]]
15 context,fail; [[Called when context fails.]]
16 stop; [[Called when need to stop.]]
17 }
18}