1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2011-2017 - Daniel De Matteis
3 *
4 * RetroArch is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with RetroArch.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "tasks_internal.h"
17
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22
23 #include <file/nbio.h>
24 #include <file/file_path.h>
25 #include <audio/audio_mixer.h>
26 #include <compat/strl.h>
27 #include <string/stdstring.h>
28 #include <retro_miscellaneous.h>
29 #include <queues/task_queue.h>
30
31 #include "../file_path_special.h"
32 #include "../retroarch.h"
33 #include "../verbosity.h"
34
35 #include "task_file_transfer.h"
36 #include "tasks_internal.h"
37
38 struct audio_mixer_userdata
39 {
40 unsigned slot_selection_idx;
41 enum audio_mixer_stream_type stream_type;
42 enum audio_mixer_slot_selection_type slot_selection_type;
43 };
44
45 struct audio_mixer_handle
46 {
47 nbio_buf_t *buffer;
48 retro_task_callback_t cb;
49 enum audio_mixer_type type;
50 char path[4095];
51 bool copy_data_over;
52 bool is_finished;
53 };
54
task_audio_mixer_load_free(retro_task_t * task)55 static void task_audio_mixer_load_free(retro_task_t *task)
56 {
57 nbio_handle_t *nbio = (nbio_handle_t*)task->state;
58 struct audio_mixer_handle *mixer = (struct audio_mixer_handle*)nbio->data;
59
60 if (mixer)
61 {
62 if (mixer->buffer)
63 {
64 if (mixer->buffer->path)
65 free(mixer->buffer->path);
66 free(mixer->buffer);
67 }
68
69 if (mixer->cb)
70 mixer->cb(task, NULL, NULL, NULL);
71 }
72
73 if (!string_is_empty(nbio->path))
74 free(nbio->path);
75 if (nbio->data)
76 free(nbio->data);
77 nbio_free(nbio->handle);
78 free(nbio);
79 }
80
cb_nbio_audio_mixer_load(void * data,size_t len)81 static int cb_nbio_audio_mixer_load(void *data, size_t len)
82 {
83 nbio_handle_t *nbio = (nbio_handle_t*)data;
84 struct audio_mixer_handle *mixer= (struct audio_mixer_handle*)nbio->data;
85 void *ptr = nbio_get_ptr(nbio->handle, &len);
86 nbio_buf_t *buffer = (nbio_buf_t*)calloc(1, sizeof(*mixer->buffer));
87
88 if (!buffer)
89 return -1;
90
91 mixer->buffer = buffer;
92 mixer->buffer->buf = ptr;
93 mixer->buffer->bufsize = (unsigned)len;
94 mixer->copy_data_over = true;
95 nbio->is_finished = true;
96
97 return 0;
98 }
99
task_audio_mixer_handle_upload_ogg(retro_task_t * task,void * task_data,void * user_data,const char * err)100 static void task_audio_mixer_handle_upload_ogg(retro_task_t *task,
101 void *task_data,
102 void *user_data, const char *err)
103 {
104 audio_mixer_stream_params_t params;
105 nbio_buf_t *img = (nbio_buf_t*)task_data;
106 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
107 if (!img || !user)
108 return;
109
110 params.volume = 1.0f;
111 params.slot_selection_type = user->slot_selection_type;
112 params.slot_selection_idx = user->slot_selection_idx;
113 params.stream_type = user->stream_type;
114 params.type = AUDIO_MIXER_TYPE_OGG;
115 params.state = AUDIO_STREAM_STATE_STOPPED;
116 params.buf = img->buf;
117 params.bufsize = img->bufsize;
118 params.cb = NULL;
119 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
120
121 audio_driver_mixer_add_stream(¶ms);
122
123 if (img->path)
124 free(img->path);
125 if (params.basename != NULL)
126 free(params.basename);
127 free(img);
128 free(user_data);
129 }
130
task_audio_mixer_handle_upload_ogg_and_play(retro_task_t * task,void * task_data,void * user_data,const char * err)131 static void task_audio_mixer_handle_upload_ogg_and_play(retro_task_t *task,
132 void *task_data,
133 void *user_data, const char *err)
134 {
135 audio_mixer_stream_params_t params;
136 nbio_buf_t *img = (nbio_buf_t*)task_data;
137 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
138
139 if (!img || !user)
140 return;
141
142 params.volume = 1.0f;
143 params.slot_selection_type = user->slot_selection_type;
144 params.slot_selection_idx = user->slot_selection_idx;
145 params.stream_type = user->stream_type;
146 params.type = AUDIO_MIXER_TYPE_OGG;
147 params.state = AUDIO_STREAM_STATE_PLAYING;
148 params.buf = img->buf;
149 params.bufsize = img->bufsize;
150 params.cb = NULL;
151 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
152
153 audio_driver_mixer_add_stream(¶ms);
154
155 if (img->path)
156 free(img->path);
157 if (params.basename != NULL)
158 free(params.basename);
159 free(img);
160 free(user_data);
161 }
162
task_audio_mixer_handle_upload_flac(retro_task_t * task,void * task_data,void * user_data,const char * err)163 static void task_audio_mixer_handle_upload_flac(retro_task_t *task,
164 void *task_data,
165 void *user_data, const char *err)
166 {
167 audio_mixer_stream_params_t params;
168 nbio_buf_t *img = (nbio_buf_t*)task_data;
169 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
170
171 if (!img || !user)
172 return;
173
174 params.volume = 1.0f;
175 params.slot_selection_type = user->slot_selection_type;
176 params.slot_selection_idx = user->slot_selection_idx;
177 params.stream_type = user->stream_type;
178 params.type = AUDIO_MIXER_TYPE_FLAC;
179 params.state = AUDIO_STREAM_STATE_STOPPED;
180 params.buf = img->buf;
181 params.bufsize = img->bufsize;
182 params.cb = NULL;
183 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
184
185 audio_driver_mixer_add_stream(¶ms);
186
187 if (img->path)
188 free(img->path);
189 if (params.basename != NULL)
190 free(params.basename);
191 free(img);
192 free(user_data);
193 }
194
task_audio_mixer_handle_upload_flac_and_play(retro_task_t * task,void * task_data,void * user_data,const char * err)195 static void task_audio_mixer_handle_upload_flac_and_play(retro_task_t *task,
196 void *task_data,
197 void *user_data, const char *err)
198 {
199 audio_mixer_stream_params_t params;
200 nbio_buf_t *img = (nbio_buf_t*)task_data;
201 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
202
203 if (!img || !user)
204 return;
205
206 params.volume = 1.0f;
207 params.slot_selection_type = user->slot_selection_type;
208 params.slot_selection_idx = user->slot_selection_idx;
209 params.stream_type = user->stream_type;
210 params.type = AUDIO_MIXER_TYPE_FLAC;
211 params.state = AUDIO_STREAM_STATE_PLAYING;
212 params.buf = img->buf;
213 params.bufsize = img->bufsize;
214 params.cb = NULL;
215 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
216
217 audio_driver_mixer_add_stream(¶ms);
218
219 if (img->path)
220 free(img->path);
221 if (params.basename != NULL)
222 free(params.basename);
223 free(img);
224 free(user_data);
225 }
226
task_audio_mixer_handle_upload_mp3(retro_task_t * task,void * task_data,void * user_data,const char * err)227 static void task_audio_mixer_handle_upload_mp3(retro_task_t *task,
228 void *task_data,
229 void *user_data, const char *err)
230 {
231 audio_mixer_stream_params_t params;
232 nbio_buf_t *img = (nbio_buf_t*)task_data;
233 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
234
235 if (!img || !user)
236 return;
237
238 params.volume = 1.0f;
239 params.slot_selection_type = user->slot_selection_type;
240 params.slot_selection_idx = user->slot_selection_idx;
241 params.stream_type = user->stream_type;
242 params.type = AUDIO_MIXER_TYPE_MP3;
243 params.state = AUDIO_STREAM_STATE_STOPPED;
244 params.buf = img->buf;
245 params.bufsize = img->bufsize;
246 params.cb = NULL;
247 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
248
249 audio_driver_mixer_add_stream(¶ms);
250
251 if (img->path)
252 free(img->path);
253 if (params.basename != NULL)
254 free(params.basename);
255 free(img);
256 free(user_data);
257 }
258
task_audio_mixer_handle_upload_mp3_and_play(retro_task_t * task,void * task_data,void * user_data,const char * err)259 static void task_audio_mixer_handle_upload_mp3_and_play(retro_task_t *task,
260 void *task_data,
261 void *user_data, const char *err)
262 {
263 audio_mixer_stream_params_t params;
264 nbio_buf_t *img = (nbio_buf_t*)task_data;
265 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
266
267 if (!img || !user)
268 return;
269
270 params.volume = 1.0f;
271 params.slot_selection_type = user->slot_selection_type;
272 params.slot_selection_idx = user->slot_selection_idx;
273 params.stream_type = user->stream_type;
274 params.type = AUDIO_MIXER_TYPE_MP3;
275 params.state = AUDIO_STREAM_STATE_PLAYING;
276 params.buf = img->buf;
277 params.bufsize = img->bufsize;
278 params.cb = NULL;
279 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
280
281 audio_driver_mixer_add_stream(¶ms);
282
283 if (img->path)
284 free(img->path);
285 if (params.basename != NULL)
286 free(params.basename);
287 free(img);
288 free(user_data);
289 }
290
task_audio_mixer_handle_upload_mod(retro_task_t * task,void * task_data,void * user_data,const char * err)291 static void task_audio_mixer_handle_upload_mod(retro_task_t *task,
292 void *task_data,
293 void *user_data, const char *err)
294 {
295 audio_mixer_stream_params_t params;
296 nbio_buf_t *img = (nbio_buf_t*)task_data;
297 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
298
299 if (!img || !user)
300 return;
301
302 params.volume = 1.0f;
303 params.slot_selection_type = user->slot_selection_type;
304 params.slot_selection_idx = user->slot_selection_idx;
305 params.stream_type = user->stream_type;
306 params.type = AUDIO_MIXER_TYPE_MOD;
307 params.state = AUDIO_STREAM_STATE_STOPPED;
308 params.buf = img->buf;
309 params.bufsize = img->bufsize;
310 params.cb = NULL;
311 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
312
313 audio_driver_mixer_add_stream(¶ms);
314
315 if (img->path)
316 free(img->path);
317 if (params.basename != NULL)
318 free(params.basename);
319 free(img);
320 free(user_data);
321 }
322
task_audio_mixer_handle_upload_mod_and_play(retro_task_t * task,void * task_data,void * user_data,const char * err)323 static void task_audio_mixer_handle_upload_mod_and_play(retro_task_t *task,
324 void *task_data,
325 void *user_data, const char *err)
326 {
327 audio_mixer_stream_params_t params;
328 nbio_buf_t *img = (nbio_buf_t*)task_data;
329 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
330
331 if (!img || !user)
332 return;
333
334 params.volume = 1.0f;
335 params.slot_selection_type = user->slot_selection_type;
336 params.slot_selection_idx = user->slot_selection_idx;
337 params.stream_type = user->stream_type;
338 params.type = AUDIO_MIXER_TYPE_MOD;
339 params.state = AUDIO_STREAM_STATE_PLAYING;
340 params.buf = img->buf;
341 params.bufsize = img->bufsize;
342 params.cb = NULL;
343 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
344
345 audio_driver_mixer_add_stream(¶ms);
346
347 if (img->path)
348 free(img->path);
349 if (params.basename != NULL)
350 free(params.basename);
351 free(img);
352 free(user_data);
353 }
354
355 #ifdef HAVE_RWAV
task_audio_mixer_handle_upload_wav(retro_task_t * task,void * task_data,void * user_data,const char * err)356 static void task_audio_mixer_handle_upload_wav(retro_task_t *task,
357 void *task_data,
358 void *user_data, const char *err)
359 {
360 audio_mixer_stream_params_t params;
361 nbio_buf_t *img = (nbio_buf_t*)task_data;
362 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
363
364 if (!img || !user)
365 return;
366
367 params.volume = 1.0f;
368 params.slot_selection_type = user->slot_selection_type;
369 params.slot_selection_idx = user->slot_selection_idx;
370 params.stream_type = user->stream_type;
371 params.type = AUDIO_MIXER_TYPE_WAV;
372 params.state = AUDIO_STREAM_STATE_STOPPED;
373 params.buf = img->buf;
374 params.bufsize = img->bufsize;
375 params.cb = NULL;
376 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
377
378 audio_driver_mixer_add_stream(¶ms);
379
380 if (img->path)
381 free(img->path);
382 if (params.basename != NULL)
383 free(params.basename);
384 free(img);
385 free(user_data);
386 }
387
task_audio_mixer_handle_upload_wav_and_play(retro_task_t * task,void * task_data,void * user_data,const char * err)388 static void task_audio_mixer_handle_upload_wav_and_play(retro_task_t *task,
389 void *task_data,
390 void *user_data, const char *err)
391 {
392 audio_mixer_stream_params_t params;
393 nbio_buf_t *img = (nbio_buf_t*)task_data;
394 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)user_data;
395
396 if (!img || !user)
397 return;
398
399 params.volume = 1.0f;
400 params.slot_selection_type = user->slot_selection_type;
401 params.slot_selection_idx = user->slot_selection_idx;
402 params.stream_type = user->stream_type;
403 params.type = AUDIO_MIXER_TYPE_WAV;
404 params.state = AUDIO_STREAM_STATE_PLAYING;
405 params.buf = img->buf;
406 params.bufsize = img->bufsize;
407 params.cb = NULL;
408 params.basename = !string_is_empty(img->path) ? strdup(path_basename(img->path)) : NULL;
409
410 audio_driver_mixer_add_stream(¶ms);
411
412 if (img->path)
413 free(img->path);
414 if (params.basename != NULL)
415 free(params.basename);
416 free(img);
417 free(user_data);
418 }
419 #endif
420
task_audio_mixer_load_handler(retro_task_t * task)421 bool task_audio_mixer_load_handler(retro_task_t *task)
422 {
423 nbio_handle_t *nbio = (nbio_handle_t*)task->state;
424 struct audio_mixer_handle *mixer = (struct audio_mixer_handle*)nbio->data;
425
426 if (
427 nbio->is_finished
428 && (mixer && !mixer->is_finished)
429 && (mixer->copy_data_over)
430 && (!task_get_cancelled(task)))
431 {
432 nbio_buf_t *img = (nbio_buf_t*)malloc(sizeof(*img));
433
434 if (img)
435 {
436 img->buf = mixer->buffer->buf;
437 img->bufsize = mixer->buffer->bufsize;
438 img->path = strdup(nbio->path);
439 }
440
441 task_set_data(task, img);
442
443 mixer->copy_data_over = false;
444 mixer->is_finished = true;
445
446 return false;
447 }
448
449 return true;
450 }
451
task_push_audio_mixer_load_and_play(const char * fullpath,retro_task_callback_t cb,void * user_data,bool system,enum audio_mixer_slot_selection_type slot_selection_type,int slot_selection_idx)452 bool task_push_audio_mixer_load_and_play(
453 const char *fullpath, retro_task_callback_t cb, void *user_data,
454 bool system,
455 enum audio_mixer_slot_selection_type slot_selection_type,
456 int slot_selection_idx)
457 {
458 nbio_handle_t *nbio = NULL;
459 struct audio_mixer_handle *mixer = NULL;
460 retro_task_t *t = task_init();
461 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)calloc(1, sizeof(*user));
462 /* We are comparing against a fixed list of file
463 * extensions, the longest (jpeg) being 4 characters
464 * in length. We therefore only need to extract the first
465 * 5 characters from the extension of the input path
466 * to correctly validate a match */
467 const char *ext = NULL;
468 char ext_lower[6];
469
470 ext_lower[0] = '\0';
471
472 if (!t || !user)
473 goto error;
474
475 nbio = (nbio_handle_t*)calloc(1, sizeof(*nbio));
476
477 if (!nbio)
478 goto error;
479
480 nbio->path = strdup(fullpath);
481
482 mixer = (struct audio_mixer_handle*)calloc(1, sizeof(*mixer));
483 if (!mixer)
484 goto error;
485
486 mixer->is_finished = false;
487
488 strlcpy(mixer->path, fullpath, sizeof(mixer->path));
489
490 nbio->type = NBIO_TYPE_NONE;
491 mixer->type = AUDIO_MIXER_TYPE_NONE;
492
493 /* Get file extension */
494 ext = strrchr(fullpath, '.');
495
496 if (!ext || (*(++ext) == '\0'))
497 goto error;
498
499 /* Copy and convert to lower case */
500 strlcpy(ext_lower, ext, sizeof(ext_lower));
501 string_to_lower(ext_lower);
502
503 #ifdef HAVE_RWAV
504 if (string_is_equal(ext_lower, "wav"))
505 {
506 mixer->type = AUDIO_MIXER_TYPE_WAV;
507 nbio->type = NBIO_TYPE_WAV;
508 t->callback = task_audio_mixer_handle_upload_wav_and_play;
509 }
510 else
511 #endif
512 if (string_is_equal(ext_lower, "ogg"))
513 {
514 mixer->type = AUDIO_MIXER_TYPE_OGG;
515 nbio->type = NBIO_TYPE_OGG;
516 t->callback = task_audio_mixer_handle_upload_ogg_and_play;
517 }
518 else if (string_is_equal(ext_lower, "mp3"))
519 {
520 mixer->type = AUDIO_MIXER_TYPE_MP3;
521 nbio->type = NBIO_TYPE_MP3;
522 t->callback = task_audio_mixer_handle_upload_mp3_and_play;
523 }
524 else if (string_is_equal(ext_lower, "flac"))
525 {
526 mixer->type = AUDIO_MIXER_TYPE_FLAC;
527 nbio->type = NBIO_TYPE_FLAC;
528 t->callback = task_audio_mixer_handle_upload_flac_and_play;
529 }
530 else if (
531 string_is_equal(ext_lower, "mod") ||
532 string_is_equal(ext_lower, "s3m") ||
533 string_is_equal(ext_lower, "xm"))
534 {
535 mixer->type = AUDIO_MIXER_TYPE_MOD;
536 nbio->type = NBIO_TYPE_MOD;
537 t->callback = task_audio_mixer_handle_upload_mod_and_play;
538 }
539
540 if (system)
541 user->stream_type = AUDIO_STREAM_TYPE_SYSTEM;
542 else
543 user->stream_type = AUDIO_STREAM_TYPE_USER;
544
545 user->slot_selection_type = slot_selection_type;
546 user->slot_selection_idx = slot_selection_idx;
547
548 nbio->data = (struct audio_mixer_handle*)mixer;
549 nbio->is_finished = false;
550 nbio->cb = &cb_nbio_audio_mixer_load;
551 nbio->status = NBIO_STATUS_INIT;
552
553 t->state = nbio;
554 t->handler = task_file_load_handler;
555 t->cleanup = task_audio_mixer_load_free;
556 t->user_data = user;
557
558 task_queue_push(t);
559
560 return true;
561
562 error:
563 if (nbio)
564 {
565 if (!string_is_empty(nbio->path))
566 free(nbio->path);
567 if (nbio->data)
568 free(nbio->data);
569 nbio_free(nbio->handle);
570 free(nbio);
571 }
572 if (user)
573 free(user);
574 if (t)
575 free(t);
576
577 RARCH_ERR("[audio mixer load] Failed to open '%s': %s.\n",
578 fullpath, strerror(errno));
579
580 return false;
581 }
582
task_push_audio_mixer_load(const char * fullpath,retro_task_callback_t cb,void * user_data,bool system,enum audio_mixer_slot_selection_type slot_selection_type,int slot_selection_idx)583 bool task_push_audio_mixer_load(
584 const char *fullpath, retro_task_callback_t cb, void *user_data,
585 bool system,
586 enum audio_mixer_slot_selection_type slot_selection_type,
587 int slot_selection_idx)
588 {
589 nbio_handle_t *nbio = NULL;
590 struct audio_mixer_handle *mixer = NULL;
591 retro_task_t *t = task_init();
592 struct audio_mixer_userdata *user = (struct audio_mixer_userdata*)calloc(1, sizeof(*user));
593 /* We are comparing against a fixed list of file
594 * extensions, the longest (jpeg) being 4 characters
595 * in length. We therefore only need to extract the first
596 * 5 characters from the extension of the input path
597 * to correctly validate a match */
598 const char *ext = NULL;
599 char ext_lower[6];
600
601 ext_lower[0] = '\0';
602
603 if (!t || !user)
604 goto error;
605
606 nbio = (nbio_handle_t*)calloc(1, sizeof(*nbio));
607
608 if (!nbio)
609 goto error;
610
611 nbio->path = strdup(fullpath);
612
613 mixer = (struct audio_mixer_handle*)calloc(1, sizeof(*mixer));
614 if (!mixer)
615 goto error;
616
617 mixer->is_finished = false;
618 mixer->cb = cb;
619
620 strlcpy(mixer->path, fullpath, sizeof(mixer->path));
621
622 nbio->type = NBIO_TYPE_NONE;
623 mixer->type = AUDIO_MIXER_TYPE_NONE;
624
625 /* Get file extension */
626 ext = strrchr(fullpath, '.');
627
628 if (!ext || (*(++ext) == '\0'))
629 goto error;
630
631 /* Copy and convert to lower case */
632 strlcpy(ext_lower, ext, sizeof(ext_lower));
633 string_to_lower(ext_lower);
634
635 #ifdef HAVE_RWAV
636 if (string_is_equal(ext_lower, "wav"))
637 {
638 mixer->type = AUDIO_MIXER_TYPE_WAV;
639 nbio->type = NBIO_TYPE_WAV;
640 t->callback = task_audio_mixer_handle_upload_wav;
641 }
642 else
643 #endif
644 if (string_is_equal(ext_lower, "ogg"))
645 {
646 mixer->type = AUDIO_MIXER_TYPE_OGG;
647 nbio->type = NBIO_TYPE_OGG;
648 t->callback = task_audio_mixer_handle_upload_ogg;
649 }
650 else if (string_is_equal(ext_lower, "mp3"))
651 {
652 mixer->type = AUDIO_MIXER_TYPE_MP3;
653 nbio->type = NBIO_TYPE_MP3;
654 t->callback = task_audio_mixer_handle_upload_mp3;
655 }
656 else if (string_is_equal(ext_lower, "flac"))
657 {
658 mixer->type = AUDIO_MIXER_TYPE_FLAC;
659 nbio->type = NBIO_TYPE_FLAC;
660 t->callback = task_audio_mixer_handle_upload_flac;
661 }
662 else if (
663 string_is_equal(ext_lower, "mod") ||
664 string_is_equal(ext_lower, "s3m") ||
665 string_is_equal(ext_lower, "xm"))
666 {
667 mixer->type = AUDIO_MIXER_TYPE_MOD;
668 nbio->type = NBIO_TYPE_MOD;
669 t->callback = task_audio_mixer_handle_upload_mod;
670 }
671
672 nbio->data = (struct audio_mixer_handle*)mixer;
673 nbio->is_finished = false;
674 nbio->cb = &cb_nbio_audio_mixer_load;
675 nbio->status = NBIO_STATUS_INIT;
676
677 if (system)
678 user->stream_type = AUDIO_STREAM_TYPE_SYSTEM;
679 else
680 user->stream_type = AUDIO_STREAM_TYPE_USER;
681
682 user->slot_selection_type = slot_selection_type;
683 user->slot_selection_idx = slot_selection_idx;
684
685 t->state = nbio;
686 t->handler = task_file_load_handler;
687 t->cleanup = task_audio_mixer_load_free;
688 t->user_data = user;
689
690 task_queue_push(t);
691
692 return true;
693
694 error:
695 if (nbio)
696 {
697 if (!string_is_empty(nbio->path))
698 free(nbio->path);
699 if (nbio->data)
700 free(nbio->data);
701 nbio_free(nbio->handle);
702 free(nbio);
703 }
704 if (user)
705 free(user);
706 if (t)
707 free(t);
708
709 RARCH_ERR("[audio mixer load] Failed to open '%s': %s.\n",
710 fullpath, strerror(errno));
711
712 return false;
713 }
714