PS2SDK
PS2 Homebrew Libraries
audsrv_rpc.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2005, ps2dev - http://www.ps2dev.org
7 # Licenced under GNU Library General Public License version 2
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
16 #include <stdio.h>
17 #include <kernel.h>
18 #include <sifrpc.h>
19 #include <tamtypes.h>
20 #include <string.h>
21 #include <iopheap.h>
22 #include <iopcontrol.h>
23 
24 #include <audsrv.h>
25 #include "audsrv_rpc.h"
26 
27 #define MIN(a,b) ((a) <= (b)) ? (a) : (b)
28 
29 /* rpc mambo jambo */
30 static struct t_SifRpcClientData cd0;
31 static unsigned int sbuff[4096] __attribute__((aligned (64)));
32 static struct t_SifRpcDataQueue cb_queue;
33 static struct t_SifRpcServerData cb_srv;
34 static unsigned char rpc_server_stack[0x1800] __attribute__((aligned (16)));
35 
36 extern void *_gp;
37 
38 static int rpc_server_thread_id;
39 static int audsrv_error = AUDSRV_ERR_NOERROR;
40 static int completion_sema;
41 
42 static audsrv_callback_t on_cdda_stop = NULL;
43 static void *on_cdda_stop_arg = NULL;
44 
45 static audsrv_callback_t on_fillbuf = NULL;
46 static void *on_fillbuf_arg = NULL;
47 
48 static const unsigned short vol_values[26] =
49 {
50  0x0000,
51  0x0000, 0x0096, 0x0190, 0x0230, 0x0320,
52  0x042E, 0x0532, 0x05FA, 0x06C2, 0x088E,
53  0x09F6, 0x0BC2, 0x0DC0, 0x0FF0, 0x118A,
54  0x1482, 0x1752, 0x1B4E, 0x1F40, 0x2378,
55  0x28D2, 0x2EFE, 0x34F8, 0x3A5C, 0x3FFF
56 };
57 
61 static void set_error(int err)
62 {
63  audsrv_error = err;
64 }
65 
67 {
68  return audsrv_error;
69 }
70 
76 static int call_rpc_1(int func, int arg)
77 {
78  int ret;
79 
80  WaitSema(completion_sema);
81 
82  sbuff[0] = arg;
83  sceSifCallRpc(&cd0, func, 0, sbuff, 1*4, sbuff, 4, NULL, NULL);
84 
85  ret = sbuff[0];
86  SignalSema(completion_sema);
87 
88  set_error(ret);
89 
90  return ret;
91 }
92 
99 static int call_rpc_2(int func, int arg1, int arg2)
100 {
101  int ret;
102 
103  WaitSema(completion_sema);
104 
105  sbuff[0] = arg1;
106  sbuff[1] = arg2;
107  sceSifCallRpc(&cd0, func, 0, sbuff, 2*4, sbuff, 4, NULL, NULL);
108 
109  ret = sbuff[0];
110  SignalSema(completion_sema);
111 
112  set_error(ret);
113 
114  return ret;
115 }
116 
124 static int call_rpc_3(int func, int arg1, int arg2, int arg3)
125 {
126  int ret;
127 
128  WaitSema(completion_sema);
129 
130  sbuff[0] = arg1;
131  sbuff[1] = arg2;
132  sbuff[2] = arg3;
133  sceSifCallRpc(&cd0, func, 0, sbuff, 3*4, sbuff, 4, NULL, NULL);
134 
135  ret = sbuff[0];
136  SignalSema(completion_sema);
137 
138  set_error(ret);
139 
140  return ret;
141 }
142 
144 {
145  WaitSema(completion_sema);
146 
147  sceSifCallRpc(&cd0, AUDSRV_QUIT, 0, sbuff, 1*4, sbuff, 4, NULL, NULL);
149 
150  sceSifRemoveRpc(&cb_srv, &cb_queue);
151  sceSifRemoveRpcQueue(&cb_queue);
152  TerminateThread(rpc_server_thread_id);
153  DeleteThread(rpc_server_thread_id);
154 
155  DeleteSema(completion_sema);
156  return 0;
157 }
158 
160 {
161  int ret;
162 
163  WaitSema(completion_sema);
164 
165  sbuff[0] = fmt->freq;
166  sbuff[1] = fmt->bits;
167  sbuff[2] = fmt->channels;
168  sceSifCallRpc(&cd0, AUDSRV_SET_FORMAT, 0, sbuff, 3*4, sbuff, 4, NULL, NULL);
169 
170  ret = sbuff[0];
171  SignalSema(completion_sema);
172 
173  set_error(ret);
174 
175  return ret;
176 }
177 
178 int audsrv_wait_audio(int bytes)
179 {
180  return call_rpc_1(AUDSRV_WAIT_AUDIO, bytes);
181 }
182 
183 int audsrv_set_volume(int volume)
184 {
185  if (volume > MAX_VOLUME)
186  {
187  volume = MAX_VOLUME;
188  }
189  else if (volume < MIN_VOLUME)
190  {
191  volume = MIN_VOLUME;
192  }
193 
194  return call_rpc_1(AUDSRV_SET_VOLUME, vol_values[volume/4]);
195 }
196 
197 int audsrv_play_cd(int track)
198 {
199  return call_rpc_1(AUDSRV_PLAY_CD, track);
200 }
201 
202 int audsrv_play_sectors(int start, int end)
203 {
204  return call_rpc_2(AUDSRV_PLAY_SECTORS, start, end);
205 }
206 
208 {
209  int ret;
210  ret = call_rpc_1(AUDSRV_STOP_CD, 0);
211  return ret;
212 }
213 
215 {
216  return call_rpc_1(AUDSRV_GET_CDPOS, 0);
217 }
218 
220 {
221  return call_rpc_1(AUDSRV_GET_TRACKPOS, 0);
222 }
223 
225 {
226  return call_rpc_1(AUDSRV_GET_NUMTRACKS, 0);
227 }
228 
230 {
231  return call_rpc_1(AUDSRV_GET_TRACKOFFSET, track);
232 }
233 
235 {
236  return call_rpc_1(AUDSRV_PAUSE_CD, 0);
237 }
238 
240 {
241  return call_rpc_1(AUDSRV_RESUME_CD, 0);
242 }
243 
245 {
246  return call_rpc_1(AUDSRV_GET_CD_TYPE, 0);
247 }
248 
250 {
251  return call_rpc_1(AUDSRV_GET_CD_STATUS, 0);
252 }
253 
254 int audsrv_play_audio(const char *chunk, int bytes)
255 {
256  int maxcopy;
257  int sent = 0;
258 
260  maxcopy = sizeof(sbuff) - sizeof(int);
261  while (bytes > 0)
262  {
263  int copy, copied;
264  int packet_size;
265 
266  WaitSema(completion_sema);
267 
268  copy = MIN(bytes, maxcopy);
269  sbuff[0] = copy;
270  memcpy(&sbuff[1], chunk, copy);
271  packet_size = copy + sizeof(int);
272  sceSifCallRpc(&cd0, AUDSRV_PLAY_AUDIO, 0, sbuff, packet_size, sbuff, 1*4, NULL, NULL);
273 
274  copied = sbuff[0];
275  SignalSema(completion_sema);
276 
277  if (copied < 0)
278  {
279  /* there was an error */
280  set_error(-copied);
281  break;
282  }
283 
284  chunk = chunk + copy;
285  bytes = bytes - copy;
286  sent = sent + copied;
287  }
288 
289  return sent;
290 }
291 
293 {
294  int ret;
295  ret = call_rpc_1(AUDSRV_STOP_AUDIO, 0);
296  return ret;
297 }
298 
299 static void *audsrv_ee_rpc_handler(int fnum, void *buffer, int len)
300 {
301  (void)len;
302 
303  switch(fnum){
304  case AUDSRV_FILLBUF_CALLBACK:
305  if (on_fillbuf != NULL)
306  on_fillbuf(on_fillbuf_arg);
307  break;
308  case AUDSRV_CDDA_CALLBACK:
309  if (on_cdda_stop != NULL)
310  on_cdda_stop(on_cdda_stop_arg);
311  break;
312  }
313 
314  return buffer;
315 }
316 
317 static void rpc_server_thread(void *arg)
318 {
319  static unsigned char cb_rpc_buffer[64] __attribute__((__aligned__(64)));
320 
321  (void)arg;
322 
323  sceSifSetRpcQueue(&cb_queue, GetThreadId());
324  sceSifRegisterRpc(&cb_srv, AUDSRV_IRX, &audsrv_ee_rpc_handler, cb_rpc_buffer, NULL, NULL, &cb_queue);
325  sceSifRpcLoop(&cb_queue);
326 }
327 
329 {
330  ee_sema_t compSema;
331  ee_thread_t rpcThread;
332  int ret;
333 
335  memset(&cd0, 0, sizeof(cd0));
336 
337  if (cd0.server)
338  {
339  /* already done */
340  return 0;
341  }
342 
343  while (1)
344  {
345  if (sceSifBindRpc(&cd0, AUDSRV_IRX, 0) < 0)
346  {
347  set_error(AUDSRV_ERR_RPC_FAILED);
348  return -1;
349  }
350 
351  if (cd0.server != 0)
352  {
353  break;
354  }
355 
356  nopdelay();
357  }
358 
359  compSema.init_count = 1;
360  compSema.max_count = 1;
361  compSema.option = 0;
362  completion_sema = CreateSema(&compSema);
363  if (completion_sema < 0)
364  {
365  set_error(AUDSRV_ERR_FAILED_TO_CREATE_SEMA);
366  return -1;
367  }
368 
369  /* Create RPC server */
370  rpcThread.attr = 0;
371  rpcThread.option = 0;
372  rpcThread.func = &rpc_server_thread;
373  rpcThread.stack = rpc_server_stack;
374  rpcThread.stack_size = sizeof(rpc_server_stack);
375  rpcThread.gp_reg = &_gp;
376  rpcThread.initial_priority = 0x60;
377  rpc_server_thread_id = CreateThread(&rpcThread);
378  StartThread(rpc_server_thread_id, NULL);
379 
380  sceSifCallRpc(&cd0, AUDSRV_INIT, 0, sbuff, 64, sbuff, 64, NULL, NULL);
381  ret = sbuff[0];
382  if (ret != 0)
383  {
384  set_error(ret);
385  return ret;
386  }
387 
388  /* initialize IOP heap (for adpcm samples) */
389  SifInitIopHeap();
390 
392  return AUDSRV_ERR_NOERROR;
393 }
394 
396 {
397  return call_rpc_1(AUDSRV_INIT_ADPCM, 0);
398 }
399 
400 int audsrv_adpcm_set_volume_and_pan(int ch, int volume, int pan)
401 {
402  if (volume > MAX_VOLUME)
403  {
404  volume = MAX_VOLUME;
405  }
406  else if (volume < MIN_VOLUME)
407  {
408  volume = MIN_VOLUME;
409  }
410 
411  if (pan > 100)
412  {
413  pan = 100;
414  }
415  else if (pan < -100)
416  {
417  pan = -100;
418  }
419 
420  int volumel = volume;
421  int volumer = volume;
422 
423  if (pan < 0)
424  volumer = volumer * (100 + pan) / 100;
425  else if (pan > 0)
426  volumel = volumel * (100 - pan) / 100;
427 
428  return call_rpc_3(AUDSRV_ADPCM_SET_VOLUME, ch, vol_values[volumel/4], vol_values[volumer/4]);
429 }
430 
431 int audsrv_load_adpcm(audsrv_adpcm_t *adpcm, void *buffer, int size)
432 {
433  void* iop_addr;
434  SifDmaTransfer_t sifdma;
435  int id, ret;
436 
437  iop_addr = SifAllocIopHeap(size);
438  if (iop_addr == 0)
439  {
440  return -AUDSRV_ERR_OUT_OF_MEMORY;
441  }
442 
443  sifdma.src = buffer;
444  sifdma.dest = iop_addr;
445  sifdma.size = size;
446  sifdma.attr = 0;
447 
448  /* send by dma */
449  while((id = sceSifSetDma(&sifdma, 1)) == 0);
450  while(sceSifDmaStat(id) >= 0);
451 
452  WaitSema(completion_sema);
453 
454  sbuff[0] = (int)iop_addr;
455  sbuff[1] = size;
456  sbuff[2] = (int)adpcm; /* use as id */
457 
458  sceSifCallRpc(&cd0, AUDSRV_LOAD_ADPCM, 0, sbuff, 12, sbuff, 16, NULL, NULL);
459 
460  if(sbuff[0] != 0)
461  {
462  adpcm->buffer = 0;
463  ret = sbuff[0];
464  }
465  else
466  {
467  adpcm->buffer = buffer;
468  adpcm->size = size;
469  adpcm->pitch = sbuff[1];
470  adpcm->loop = sbuff[2];
471  adpcm->channels = sbuff[3];
472  ret = AUDSRV_ERR_NOERROR;
473  }
474 
475  SignalSema(completion_sema);
476 
477  SifFreeIopHeap(iop_addr);
478 
479  return ret;
480 }
481 
483 {
484  /* on iop side, the sample id is like the pointer on ee side */
485  return call_rpc_2(AUDSRV_PLAY_ADPCM, ch, (u32)adpcm);
486 }
487 
489 {
490  return call_rpc_2(AUDSRV_IS_ADPCM_PLAYING, ch, (u32)adpcm);
491 }
492 
494 {
495  /* on iop side, the sample id is like the pointer on ee side */
496  return call_rpc_1(AUDSRV_FREE_ADPCM, (u32)adpcm);
497 }
498 
500 {
501  switch(audsrv_get_error())
502  {
503  case AUDSRV_ERR_NOERROR:
504  return "No error";
505 
506  case AUDSRV_ERR_NOT_INITIALIZED:
507  return "Not initialized";
508 
509  case AUDSRV_ERR_OUT_OF_MEMORY:
510  return "Out of IOP memory";
511 
512  case AUDSRV_ERR_RPC_FAILED:
513  return "RPC operation failed";
514 
515  case AUDSRV_ERR_FORMAT_NOT_SUPPORTED:
516  return "Format not supported";
517 
518  case AUDSRV_ERR_NO_DISC:
519  return "No disc in drive";
520  }
521 
522  return "Unknown error";
523 }
524 
525 int audsrv_on_cdda_stop(audsrv_callback_t cb, void *arg)
526 {
527  on_cdda_stop = cb;
528  on_cdda_stop_arg = arg;
529  return AUDSRV_ERR_NOERROR;
530 }
531 
532 int audsrv_on_fillbuf(int amount, audsrv_callback_t cb, void *arg)
533 {
534  int err;
535 
536  on_fillbuf = 0;
537  on_fillbuf_arg = 0;
538 
539  err = call_rpc_1(AUDSRV_SET_THRESHOLD, amount);
540  if (err != 0)
541  {
542  return err;
543  }
544 
545  on_fillbuf = cb;
546  on_fillbuf_arg = arg;
547  return AUDSRV_ERR_NOERROR;
548 }
549 
551 {
552  return call_rpc_1(AUDSRV_AVAILABLE, 0);
553 }
554 
556 {
557  return call_rpc_1(AUDSRV_QUEUED, 0);
558 }
559 
kernel.h
audsrv_play_sectors
int audsrv_play_sectors(int start, int end)
Definition: audsrv_rpc.c:202
AUDSRV_INIT_ADPCM
#define AUDSRV_INIT_ADPCM
Definition: audsrv_rpc.h:50
audsrv_adpcm_init
int audsrv_adpcm_init()
Definition: audsrv_rpc.c:395
audsrv_play_audio
int audsrv_play_audio(const char *chunk, int bytes)
Definition: audsrv_rpc.c:254
__attribute__
static unsigned char rpc_server_stack[0x1800] __attribute__((aligned(16)))
Definition: netcnfif.c:19
call_rpc_3
static int call_rpc_3(int func, int arg1, int arg2, int arg3)
Definition: audsrv_rpc.c:124
call_rpc_2
static int call_rpc_2(int func, int arg1, int arg2)
Definition: audsrv_rpc.c:99
AUDSRV_PLAY_CD
#define AUDSRV_PLAY_CD
Definition: audsrv_rpc.h:37
MIN
#define MIN(a, b)
Definition: audsrv_internal.h:19
audsrv_stop_cd
int audsrv_stop_cd()
Definition: audsrv_rpc.c:207
audsrv_get_cd_status
int audsrv_get_cd_status()
Definition: audsrv_rpc.c:249
audsrv_set_volume
int audsrv_set_volume(int volume)
Definition: audsrv_rpc.c:183
audsrv_set_format
int audsrv_set_format(struct audsrv_fmt_t *fmt)
Definition: audsrv_rpc.c:159
audsrv_ch_play_adpcm
int audsrv_ch_play_adpcm(int ch, audsrv_adpcm_t *adpcm)
Definition: audsrv_rpc.c:482
iopcontrol.h
audsrv_resume_cd
int audsrv_resume_cd()
Definition: audsrv_rpc.c:239
t_ee_sema
Definition: kernel.h:193
audsrv_stop_audio
int audsrv_stop_audio()
Definition: audsrv_rpc.c:292
set_error
static void set_error(int err)
Definition: audsrv_rpc.c:61
audsrv_on_fillbuf
int audsrv_on_fillbuf(int amount, audsrv_callback_t cb, void *arg)
Definition: audsrv_rpc.c:532
audsrv_init
int audsrv_init()
Definition: audsrv_rpc.c:328
audsrv_free_adpcm
int audsrv_free_adpcm(audsrv_adpcm_t *adpcm)
Definition: audsrv_rpc.c:493
audsrv_adpcm_set_volume_and_pan
int audsrv_adpcm_set_volume_and_pan(int ch, int volume, int pan)
Definition: audsrv_rpc.c:400
iopheap.h
audsrv_on_cdda_stop
int audsrv_on_cdda_stop(audsrv_callback_t cb, void *arg)
Definition: audsrv_rpc.c:525
_gp
void * _gp
audsrv_load_adpcm
int audsrv_load_adpcm(audsrv_adpcm_t *adpcm, void *buffer, int size)
Definition: audsrv_rpc.c:431
audsrv_get_trackpos
int audsrv_get_trackpos()
Definition: audsrv_rpc.c:219
audsrv_get_track_offset
int audsrv_get_track_offset(int track)
Definition: audsrv_rpc.c:229
MIN_VOLUME
#define MIN_VOLUME
Definition: audsrv.h:22
tamtypes.h
audsrv_fmt_t
Definition: audsrv.h:41
HasIopRebootedSinceLastCall
static int HasIopRebootedSinceLastCall(void)
Definition: iopcontrol.h:47
stdio.h
MAX_VOLUME
#define MAX_VOLUME
Definition: audsrv.h:25
audsrv_rpc.h
audsrv_get_error_string
const char * audsrv_get_error_string()
Definition: audsrv_rpc.c:499
audsrv_wait_audio
int audsrv_wait_audio(int bytes)
Definition: audsrv_rpc.c:178
audsrv_get_cdpos
int audsrv_get_cdpos()
Definition: audsrv_rpc.c:214
t_SifDmaTransfer
Definition: sifdma.h:52
t_SifRpcServerData
Definition: sifrpc-common.h:98
audsrv_fmt_t::channels
int channels
Definition: audsrv.h:48
t_SifRpcDataQueue
Definition: sifrpc-common.h:153
audsrv_get_numtracks
int audsrv_get_numtracks()
Definition: audsrv_rpc.c:224
audsrv_play_cd
int audsrv_play_cd(int track)
Definition: audsrv_rpc.c:197
t_SifRpcClientData
Definition: sifrpc-common.h:134
audsrv_fmt_t::freq
int freq
Definition: audsrv.h:44
__attribute__
Definition: gif_registers.h:38
audsrv_available
int audsrv_available()
Definition: audsrv_rpc.c:550
audsrv_queued
int audsrv_queued()
Definition: audsrv_rpc.c:555
audsrv_pause_cd
int audsrv_pause_cd()
Definition: audsrv_rpc.c:234
t_ee_thread
Definition: kernel.h:203
AUDSRV_ERR_NOERROR
#define AUDSRV_ERR_NOERROR
Definition: audsrv.h:28
audsrv_is_adpcm_playing
int audsrv_is_adpcm_playing(int ch, audsrv_adpcm_t *adpcm)
Definition: audsrv_rpc.c:488
rpc_server_thread
static void rpc_server_thread(void *arg)
Definition: rpc_server.c:182
audsrv_adpcm_t
Definition: audsrv.h:52
audsrv_get_cd_type
int audsrv_get_cd_type()
Definition: audsrv_rpc.c:244
audsrv_get_error
int audsrv_get_error()
Definition: audsrv_rpc.c:66
AUDSRV_INIT
#define AUDSRV_INIT
Definition: audsrv_rpc.h:24
call_rpc_1
static int call_rpc_1(int func, int arg)
Definition: audsrv_rpc.c:76
audsrv_fmt_t::bits
int bits
Definition: audsrv.h:46
audsrv_quit
int audsrv_quit()
Definition: audsrv_rpc.c:143