1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <stdlib.h>
18 #include <boolean.h>
19
20 #include <xenon_sound/sound.h>
21
22 #include <retro_inline.h>
23
24 #include "../../retroarch.h"
25
26 #define SOUND_FREQUENCY 48000
27 #define MAX_BUFFER 2048
28
29 typedef struct
30 {
31 uint32_t buffer[2048];
32 bool nonblock;
33 bool is_paused;
34 } xenon_audio_t;
35
xenon360_audio_init(const char * device,unsigned rate,unsigned latency,unsigned block_frames,unsigned * new_rate)36 static void *xenon360_audio_init(const char *device,
37 unsigned rate, unsigned latency,
38 unsigned block_frames,
39 unsigned *new_rate)
40 {
41 static bool inited = false;
42
43 if (!inited)
44 {
45 xenon_sound_init();
46 inited = true;
47 }
48
49 *new_rate = SOUND_FREQUENCY;
50
51 return calloc(1, sizeof(xenon_audio_t));
52 }
53
bswap_32(uint32_t val)54 static INLINE uint32_t bswap_32(uint32_t val)
55 {
56 return (val >> 24) | (val << 24) |
57 ((val >> 8) & 0xff00) | ((val << 8) & 0xff0000);
58 }
59
xenon360_audio_write(void * data,const void * buf,size_t size)60 static ssize_t xenon360_audio_write(void *data, const void *buf, size_t size)
61 {
62 size_t written = 0, i;
63 const uint32_t *in_buf = buf;
64 xenon_audio_t *xa = data;
65
66 for (i = 0; i < (size >> 2); i++)
67 xa->buffer[i] = bswap_32(in_buf[i]);
68
69 if (xa->nonblock)
70 {
71 if (xenon_sound_get_unplayed() < MAX_BUFFER)
72 {
73 xenon_sound_submit(xa->buffer, size);
74 written = size;
75 }
76 }
77 else
78 {
79 while (xenon_sound_get_unplayed() >= MAX_BUFFER)
80 {
81 /* libxenon doesn't have proper
82 * synchronization primitives for this... */
83 udelay(50);
84 }
85
86 xenon_sound_submit(xa->buffer, size);
87 written = size;
88 }
89
90 return written;
91 }
92
xenon360_audio_stop(void * data)93 static bool xenon360_audio_stop(void *data)
94 {
95 xenon_audio_t *xa = data;
96 xa->is_paused = true;
97 return true;
98 }
99
xenon360_audio_alive(void * data)100 static bool xenon360_audio_alive(void *data)
101 {
102 xenon_audio_t *xa = data;
103 if (!xa)
104 return false;
105 return !xa->is_paused;
106 }
107
xenon360_audio_set_nonblock_state(void * data,bool state)108 static void xenon360_audio_set_nonblock_state(void *data, bool state)
109 {
110 xenon_audio_t *xa = data;
111 if (xa)
112 xa->nonblock = state;
113 }
114
xenon360_audio_start(void * data,bool is_shutdown)115 static bool xenon360_audio_start(void *data, bool is_shutdown)
116 {
117 xenon_audio_t *xa = data;
118 xa->is_paused = false;
119 return true;
120 }
121
xenon360_audio_free(void * data)122 static void xenon360_audio_free(void *data)
123 {
124 if (data)
125 free(data);
126 }
127
xenon360_use_float(void * data)128 static bool xenon360_use_float(void *data)
129 {
130 (void)data;
131 return false;
132 }
133
xenon360_write_avail(void * data)134 static size_t xenon360_write_avail(void *data)
135 {
136 (void)data;
137 return 0;
138 }
139
140 audio_driver_t audio_xenon360 = {
141 xenon360_audio_init,
142 xenon360_audio_write,
143 xenon360_audio_stop,
144 xenon360_audio_start,
145 xenon360_audio_alive,
146 xenon360_audio_set_nonblock_state,
147 xenon360_audio_free,
148 xenon360_use_float,
149 "xenon360",
150 NULL,
151 NULL,
152 xenon360_write_avail,
153 NULL
154 };
155