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