GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/mediaplayers.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 14 0.0%
Functions: 0 7 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/mediaplayers.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_SYS_WIN) && !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_WIN16)
33 # define GATE_TECH_MEDIAPLAYER_WIN_MCI 1
34 #else
35 # define GATE_TECH_MEDIAPLAYER_NO_IMPL 1
36 #endif
37
38
39
40 #if defined(GATE_TECH_MEDIAPLAYER_WIN_MCI)
41
42 #include "gate/platforms.h"
43 #include <windows.h>
44 #include <mmsystem.h>
45
46 #if defined(GATE_SYS_WINCE)
47
48
49 gate_result_t gate_mediaplayer_enum(gate_mediaplayer_enum_callback_t cb, void* cb_param, unsigned format_flags)
50 {
51 return GATE_RESULT_NOTIMPLEMENTED;
52 }
53 gate_result_t gate_mediaplayer_open(gate_mediaplayer_id_t id, gate_mediaplayer_device_t* ptr_device)
54 {
55 return GATE_RESULT_NOTIMPLEMENTED;
56 }
57 gate_result_t gate_mediaplayer_close(gate_mediaplayer_device_t* ptr_device)
58 {
59 return GATE_RESULT_NOTIMPLEMENTED;
60 }
61 gate_result_t gate_mediaplayer_load_file(gate_mediaplayer_device_t* ptr_device, gate_string_t const* file_path)
62 {
63 return GATE_RESULT_NOTIMPLEMENTED;
64 }
65 gate_result_t gate_mediaplayer_status(gate_mediaplayer_device_t* ptr_device, gate_mediaplayer_status_t* ptr_status)
66 {
67 return GATE_RESULT_NOTIMPLEMENTED;
68 }
69 gate_result_t gate_mediaplayer_play(gate_mediaplayer_device_t* ptr_device)
70 {
71 return GATE_RESULT_NOTIMPLEMENTED;
72 }
73 gate_result_t gate_mediaplayer_stop(gate_mediaplayer_device_t* ptr_device)
74 {
75 return GATE_RESULT_NOTIMPLEMENTED;
76 }
77
78
79 #else /* GATE SYS_WINCE */
80
81 typedef UINT(CALLBACK* MCIYIELDPROC)(UINT mciId, DWORD dwYieldData);
82
83 typedef struct win32_mci_api_class
84 {
85 UINT(WINAPI* GetDeviceID) (LPCTSTR pszDevice);
86 UINT(WINAPI* GetDeviceIDFromElementID) (DWORD dwElementID, LPTSTR lpstrType);
87 DWORD(WINAPI* SendCommand) (UINT mciId, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
88 HANDLE(WINAPI* GetCreatorTask) (UINT mciId);
89 DWORD(WINAPI* SendString) (LPCTSTR lpstrCommand, LPTSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback);
90 MCIYIELDPROC(WINAPI* GetYieldProc) (UINT mciId, LPDWORD pdwYieldData);
91 BOOL(WINAPI* SetYieldProc) (UINT mciId, MCIYIELDPROC fpYieldProc, DWORD dwYieldData);
92 } win32_mci_api_t;
93
94 static win32_mci_api_t win32_mci;
95 static gate_bool_t volatile win32_mci_loaded = false;
96
97 static gate_result_t load_win32_mci_api()
98 {
99 static HMODULE hmod_winmm = NULL;
100 HMODULE hmod;
101 gate_bool_t succeeded = true;
102
103 if (hmod_winmm == NULL)
104 {
105 hmod_winmm = gate_win32_load_library(_T("winmm.dll"), 0);
106 if (hmod_winmm == NULL)
107 {
108 return GATE_RESULT_NOTAVAILABLE;
109 }
110 }
111
112 if (!win32_mci_loaded)
113 {
114 hmod = hmod_winmm;
115 succeeded &= gate_win32_get_proc_address(hmod, GATE_WINAPI_DUAL_NAME("mciGetDeviceID"), &win32_mci.GetDeviceID);
116 succeeded &= gate_win32_get_proc_address(hmod, GATE_WINAPI_DUAL_NAME("mciGetDeviceIDFromElementID"), &win32_mci.GetDeviceIDFromElementID);
117 succeeded &= gate_win32_get_proc_address(hmod, GATE_WINAPI_DUAL_NAME("mciSendCommand"), &win32_mci.SendCommand);
118 succeeded &= gate_win32_get_proc_address(hmod, GATE_WINAPI_DUAL_NAME("mciSendString"), &win32_mci.SendString);
119 succeeded &= gate_win32_get_proc_address(hmod, "mciGetCreatorTask", &win32_mci.GetCreatorTask);
120 succeeded &= gate_win32_get_proc_address(hmod, "mciGetYieldProc", &win32_mci.GetYieldProc);
121 succeeded &= gate_win32_get_proc_address(hmod, "mciSetYieldProc", &win32_mci.SetYieldProc);
122 win32_mci_loaded = succeeded;
123 }
124
125 return succeeded ? GATE_RESULT_OK : GATE_RESULT_FAILED;
126 }
127
128 typedef struct gate_mediaplayer_impl_class
129 {
130 UINT dev_type;
131 UINT mci_device_id;
132 } gate_mediaplayer_impl_t;
133
134
135 gate_result_t gate_mediaplayer_enum(gate_mediaplayer_enum_callback_t cb, void* cb_param, unsigned format_flags)
136 {
137 gate_result_t result;
138 static gate_string_t const descr_audio = GATE_STRING_INIT_STATIC("Audio");
139 do
140 {
141 result = load_win32_mci_api();
142 GATE_BREAK_IF_FAILED(result);
143
144 if (cb)
145 {
146 if (GATE_FLAG_ENABLED(format_flags, GATE_MEDIAPLAYER_FORMAT_AUDIOFILE))
147 {
148 cb((gate_mediaplayer_id_t)MCI_DEVTYPE_WAVEFORM_AUDIO, &descr_audio, cb_param);
149 }
150 }
151
152 result = GATE_RESULT_OK;
153
154 } while (0);
155
156 return result;
157 }
158
159 gate_result_t gate_mediaplayer_open(gate_mediaplayer_id_t id, gate_mediaplayer_device_t* ptr_device)
160 {
161 gate_result_t ret;
162 gate_mediaplayer_impl_t* ptr_impl = NULL;
163 UINT devid = (UINT)(gate_uintptr_t)id;
164
165 do
166 {
167 ret = load_win32_mci_api();
168 GATE_BREAK_IF_FAILED(ret);
169
170 switch (devid)
171 {
172 case MCI_DEVTYPE_WAVEFORM_AUDIO:
173 {
174 /* OK */
175 devid = MCI_DEVTYPE_DIGITAL_VIDEO;
176 break;
177 }
178 default:
179 {
180 devid = 0;
181 break;
182 }
183 }
184 if (devid == 0)
185 {
186 ret = GATE_RESULT_NOTSUPPORTED;
187 break;
188 }
189
190 ptr_impl = (gate_mediaplayer_impl_t*)gate_mem_alloc(sizeof(gate_mediaplayer_impl_t));
191 if (NULL == ptr_impl)
192 {
193 ret = GATE_RESULT_OUTOFMEMORY;
194 break;
195 }
196
197 ptr_impl->dev_type = devid;
198 ptr_impl->mci_device_id = 0;
199
200 *ptr_device = (gate_mediaplayer_device_t)ptr_impl;
201 ptr_impl = NULL;
202 ret = GATE_RESULT_OK;
203 } while (0);
204
205 if (ptr_impl)
206 {
207 gate_mem_dealloc(ptr_impl);
208 }
209 return ret;
210 }
211
212 gate_result_t gate_mediaplayer_close(gate_mediaplayer_device_t* ptr_device)
213 {
214 gate_result_t ret = GATE_RESULT_FAILED;
215 gate_mediaplayer_impl_t* impl = ptr_device ? (gate_mediaplayer_impl_t*)*ptr_device : NULL;
216 MCI_GENERIC_PARMS gen_params = GATE_INIT_EMPTY;
217
218 do
219 {
220 if (!impl)
221 {
222 ret = GATE_RESULT_INVALIDARG;
223 break;
224 }
225 if (impl->mci_device_id != 0)
226 {
227 gen_params.dwCallback = 0;
228 win32_mci.SendCommand(impl->mci_device_id, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)(void*)&gen_params);
229 impl->mci_device_id = 0;
230 }
231 gate_mem_dealloc(impl);
232 *ptr_device = NULL;
233 ret = GATE_RESULT_OK;
234 } while (0);
235
236 return ret;
237 }
238
239 gate_result_t gate_mediaplayer_load_file(gate_mediaplayer_device_t* ptr_device, gate_string_t const* file_path)
240 {
241 gate_result_t ret = GATE_RESULT_FAILED;
242 gate_mediaplayer_impl_t* impl = ptr_device ? (gate_mediaplayer_impl_t*)*ptr_device : NULL;
243 DWORD error;
244 MCI_OPEN_PARMS open_params = GATE_INIT_EMPTY;
245 MCI_GENERIC_PARMS gen_params = GATE_INIT_EMPTY;
246 TCHAR path_buffer[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
247
248 do
249 {
250 if (!impl)
251 {
252 ret = GATE_RESULT_INVALIDARG;
253 break;
254 }
255
256 if (impl->mci_device_id != 0)
257 {
258 gen_params.dwCallback = 0;
259 win32_mci.SendCommand(impl->mci_device_id, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)(void*)&gen_params);
260 impl->mci_device_id = 0;
261 }
262
263 gate_win32_utf8_2_winstr(gate_string_ptr(file_path, 0), gate_string_length(file_path),
264 path_buffer, sizeof(path_buffer) / sizeof(path_buffer[0]));
265 open_params.dwCallback = 0;
266 open_params.lpstrElementName = path_buffer;
267 open_params.wDeviceID = 0;
268 //open_params.lpstrDeviceType = (LPCTSTR)(gate_uintptr_t)impl->dev_type;
269 open_params.lpstrDeviceType = _T("MPEGVideo");
270 error = win32_mci.SendCommand(0,
271 MCI_OPEN,
272 MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
273 (DWORD_PTR)(void*)&open_params);
274 if (error)
275 {
276 ret = GATE_RESULT_FAILED;
277 break;
278 }
279 impl->mci_device_id = open_params.wDeviceID;
280 ret = GATE_RESULT_OK;
281 } while (0);
282
283 return ret;
284 }
285
286 static gate_bool_t gate_mediaplayer_get_status(UINT device_id, DWORD query_item, DWORD_PTR* ptr_value, DWORD* ptr_track)
287 {
288 MCI_STATUS_PARMS status_params = GATE_INIT_EMPTY;
289 DWORD error;
290 DWORD flags = MCI_WAIT | MCI_STATUS_ITEM;
291 status_params.dwItem = query_item;
292 status_params.dwCallback = 0;
293 status_params.dwReturn = ptr_value ? *ptr_value : 0;
294 status_params.dwTrack = ptr_track ? *ptr_track : 0;
295 if (ptr_track)
296 {
297 //status_params.dwItem |= MCI_TRACK;
298 flags |= MCI_TRACK;
299 }
300
301 error = win32_mci.SendCommand(device_id, MCI_STATUS, flags, (DWORD_PTR)(void*)&status_params);
302 if (error)
303 {
304 return false;
305 }
306 if (ptr_value)
307 {
308 *ptr_value = status_params.dwReturn;
309 }
310 if (ptr_track)
311 {
312 *ptr_track = status_params.dwTrack;
313 }
314 return true;
315 }
316
317 gate_result_t gate_mediaplayer_status(gate_mediaplayer_device_t* ptr_device, gate_mediaplayer_status_t* ptr_status)
318 {
319 gate_result_t ret = GATE_RESULT_FAILED;
320 gate_mediaplayer_impl_t* impl = ptr_device ? (gate_mediaplayer_impl_t*)*ptr_device : NULL;
321 MCI_STATUS_PARMS status_params = GATE_INIT_EMPTY;
322 DWORD_PTR value, timeformat;
323 DWORD track;
324
325 do
326 {
327 if (!impl || !ptr_status || (impl->mci_device_id == 0))
328 {
329 ret = GATE_RESULT_INVALIDARG;
330 break;
331 }
332
333 gate_mem_clear(ptr_status, sizeof(gate_mediaplayer_status_t));
334
335 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_MODE, &value, NULL))
336 {
337 switch (value)
338 {
339 case MCI_MODE_OPEN: ptr_status->status = GATE_MEDIAPLAYER_STATUS_IDLE; break;
340 case MCI_MODE_PLAY: ptr_status->status = GATE_MEDIAPLAYER_STATUS_PLAYING; break;
341 case MCI_MODE_PAUSE: ptr_status->status = GATE_MEDIAPLAYER_STATUS_PAUSED; break;
342 case MCI_MODE_STOP: ptr_status->status = GATE_MEDIAPLAYER_STATUS_STOPPED; break;
343 case MCI_MODE_RECORD: ptr_status->status = GATE_MEDIAPLAYER_STATUS_RECORDING; break;
344 case MCI_MODE_SEEK: ptr_status->status = GATE_MEDIAPLAYER_STATUS_SEEKING; break;
345 case MCI_MODE_NOT_READY: ptr_status->status = GATE_MEDIAPLAYER_STATUS_ERROR; break;
346 default: ptr_status->status = GATE_MEDIAPLAYER_STATUS_UNKONWN; break;
347 }
348 }
349 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_NUMBER_OF_TRACKS, &value, NULL))
350 {
351 ptr_status->step_count = (unsigned int)value;
352 }
353 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_CURRENT_TRACK, &value, NULL))
354 {
355 track = (DWORD)value;
356 ptr_status->step = (unsigned int)value;
357 }
358 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_TIME_FORMAT, &value, NULL))
359 {
360 timeformat = value;
361 }
362 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_LENGTH, &value, &track))
363 {
364 ptr_status->length = value;
365 }
366
367 if (gate_mediaplayer_get_status(impl->mci_device_id, MCI_STATUS_POSITION, &value, &track))
368 {
369 ptr_status->position = value;
370 }
371
372 ret = GATE_RESULT_OK;
373 } while (0);
374 return ret;
375 }
376
377 gate_result_t gate_mediaplayer_play(gate_mediaplayer_device_t* ptr_device)
378 {
379 gate_result_t ret = GATE_RESULT_FAILED;
380 gate_mediaplayer_impl_t* impl = ptr_device ? (gate_mediaplayer_impl_t*)*ptr_device : NULL;
381 DWORD error;
382 MCI_PLAY_PARMS play_params = GATE_INIT_EMPTY;
383
384 do
385 {
386 if (!impl || (impl->mci_device_id == 0))
387 {
388 ret = GATE_RESULT_INVALIDARG;
389 break;
390 }
391 play_params.dwCallback = 0;
392 play_params.dwFrom = 0;
393 play_params.dwTo = 0;
394 error = win32_mci.SendCommand(impl->mci_device_id, MCI_PLAY, MCI_NOTIFY, (DWORD_PTR)(void*)&play_params);
395 if (error)
396 {
397 ret = GATE_RESULT_FAILED;
398 break;
399 }
400
401 ret = GATE_RESULT_OK;
402 } while (0);
403 return ret;
404 }
405
406 gate_result_t gate_mediaplayer_stop(gate_mediaplayer_device_t* ptr_device)
407 {
408 gate_result_t ret = GATE_RESULT_FAILED;
409 gate_mediaplayer_impl_t* impl = ptr_device ? (gate_mediaplayer_impl_t*)*ptr_device : NULL;
410 DWORD error;
411 MCI_GENERIC_PARMS stop_params = GATE_INIT_EMPTY;
412
413 do
414 {
415 if (!impl || (impl->mci_device_id == 0))
416 {
417 ret = GATE_RESULT_INVALIDARG;
418 break;
419 }
420 stop_params.dwCallback = 0;
421 error = win32_mci.SendCommand(impl->mci_device_id, MCI_STOP, MCI_WAIT, (DWORD_PTR)(void*)&stop_params);
422 if (error)
423 {
424 ret = GATE_RESULT_FAILED;
425 break;
426 }
427
428 ret = GATE_RESULT_OK;
429 } while (0);
430 return ret;
431 }
432
433 #endif /* GATE SYS_WINCE */
434
435 #endif /* GATE_TECH_MEDIAPLAYER_WIN_MCI */
436
437
438
439
440 #if defined(GATE_TECH_MEDIAPLAYER_NO_IMPL)
441
442 gate_result_t gate_mediaplayer_enum(gate_mediaplayer_enum_callback_t cb, void* cb_param, unsigned format_flags)
443 {
444 GATE_UNUSED_ARG(cb);
445 GATE_UNUSED_ARG(cb_param);
446 GATE_UNUSED_ARG(format_flags);
447 return GATE_RESULT_NOTIMPLEMENTED;
448 }
449 gate_result_t gate_mediaplayer_open(gate_mediaplayer_id_t id, gate_mediaplayer_device_t* ptr_device)
450 {
451 GATE_UNUSED_ARG(id);
452 GATE_UNUSED_ARG(ptr_device);
453 return GATE_RESULT_NOTIMPLEMENTED;
454 }
455 gate_result_t gate_mediaplayer_close(gate_mediaplayer_device_t* ptr_device)
456 {
457 GATE_UNUSED_ARG(ptr_device);
458 return GATE_RESULT_NOTIMPLEMENTED;
459 }
460 gate_result_t gate_mediaplayer_load_file(gate_mediaplayer_device_t* ptr_device, gate_string_t const* file_path)
461 {
462 GATE_UNUSED_ARG(ptr_device);
463 GATE_UNUSED_ARG(file_path);
464 return GATE_RESULT_NOTIMPLEMENTED;
465 }
466 gate_result_t gate_mediaplayer_status(gate_mediaplayer_device_t* ptr_device, gate_mediaplayer_status_t* ptr_status)
467 {
468 GATE_UNUSED_ARG(ptr_device);
469 GATE_UNUSED_ARG(ptr_status);
470 return GATE_RESULT_NOTIMPLEMENTED;
471 }
472 gate_result_t gate_mediaplayer_play(gate_mediaplayer_device_t* ptr_device)
473 {
474 GATE_UNUSED_ARG(ptr_device);
475 return GATE_RESULT_NOTIMPLEMENTED;
476 }
477 gate_result_t gate_mediaplayer_stop(gate_mediaplayer_device_t* ptr_device)
478 {
479 GATE_UNUSED_ARG(ptr_device);
480 return GATE_RESULT_NOTIMPLEMENTED;
481 }
482
483 #endif
484