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 
23 #include <audsrv.h>
24 #include "audsrv_rpc.h"
25 
26 #define MIN(a,b) ((a) <= (b)) ? (a) : (b)
27 
28 /* rpc mambo jambo */
29 static struct t_SifRpcClientData cd0;
30 static unsigned int sbuff[4096] __attribute__((aligned (64)));
31 static struct t_SifRpcDataQueue cb_queue;
32 static struct t_SifRpcServerData cb_srv;
33 static unsigned char rpc_server_stack[0x1800] __attribute__((aligned (16)));
34 
35 extern void *_gp;
36 
37 static int initialized = 0;
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 
334  if (initialized)
335  {
336  /* already done */
337  return 0;
338  }
339 
340  memset(&cd0, '\0', sizeof(cd0));
341 
342  while (1)
343  {
344  if (sceSifBindRpc(&cd0, AUDSRV_IRX, 0) < 0)
345  {
346  set_error(AUDSRV_ERR_RPC_FAILED);
347  return -1;
348  }
349 
350  if (cd0.server != 0)
351  {
352  break;
353  }
354 
355  nopdelay();
356  }
357 
358  compSema.init_count = 1;
359  compSema.max_count = 1;
360  compSema.option = 0;
361  completion_sema = CreateSema(&compSema);
362  if (completion_sema < 0)
363  {
364  set_error(AUDSRV_ERR_FAILED_TO_CREATE_SEMA);
365  return -1;
366  }
367 
368  /* Create RPC server */
369  rpcThread.attr = 0;
370  rpcThread.option = 0;
371  rpcThread.func = &rpc_server_thread;
372  rpcThread.stack = rpc_server_stack;
373  rpcThread.stack_size = sizeof(rpc_server_stack);
374  rpcThread.gp_reg = &_gp;
375  rpcThread.initial_priority = 0x60;
376  rpc_server_thread_id = CreateThread(&rpcThread);
377  StartThread(rpc_server_thread_id, NULL);
378 
379  sceSifCallRpc(&cd0, AUDSRV_INIT, 0, sbuff, 64, sbuff, 64, NULL, NULL);
380  ret = sbuff[0];
381  if (ret != 0)
382  {
383  set_error(ret);
384  return ret;
385  }
386 
387  /* initialize IOP heap (for adpcm samples) */
388  SifInitIopHeap();
389 
391  return AUDSRV_ERR_NOERROR;
392 }
393 
395 {
396  return call_rpc_1(AUDSRV_INIT_ADPCM, 0);
397 }
398 
399 int audsrv_adpcm_set_volume_and_pan(int ch, int volume, int pan)
400 {
401  if (volume > MAX_VOLUME)
402  {
403  volume = MAX_VOLUME;
404  }
405  else if (volume < MIN_VOLUME)
406  {
407  volume = MIN_VOLUME;
408  }
409 
410  if (pan > 100)
411  {
412  pan = 100;
413  }
414  else if (pan < -100)
415  {
416  pan = -100;
417  }
418 
419  int volumel = volume;
420  int volumer = volume;
421 
422  if (pan < 0)
423  volumer = volumer * (100 + pan) / 100;
424  else if (pan > 0)
425  volumel = volumel * (100 - pan) / 100;
426 
427  return call_rpc_3(AUDSRV_ADPCM_SET_VOLUME, ch, vol_values[volumel/4], vol_values[volumer/4]);
428 }
429 
430 int audsrv_load_adpcm(audsrv_adpcm_t *adpcm, void *buffer, int size)
431 {
432  void* iop_addr;
433  SifDmaTransfer_t sifdma;
434  int id, ret;
435 
436  iop_addr = SifAllocIopHeap(size);
437  if (iop_addr == 0)
438  {
439  return -AUDSRV_ERR_OUT_OF_MEMORY;
440  }
441 
442  sifdma.src = buffer;
443  sifdma.dest = iop_addr;
444  sifdma.size = size;
445  sifdma.attr = 0;
446 
447  /* send by dma */
448  while((id = sceSifSetDma(&sifdma, 1)) == 0);
449  while(sceSifDmaStat(id) >= 0);
450 
451  WaitSema(completion_sema);
452 
453  sbuff[0] = (int)iop_addr;
454  sbuff[1] = size;
455  sbuff[2] = (int)adpcm; /* use as id */
456 
457  sceSifCallRpc(&cd0, AUDSRV_LOAD_ADPCM, 0, sbuff, 12, sbuff, 16, NULL, NULL);
458 
459  if(sbuff[0] != 0)
460  {
461  adpcm->buffer = 0;
462  ret = sbuff[0];
463  }
464  else
465  {
466  adpcm->buffer = buffer;
467  adpcm->size = size;
468  adpcm->pitch = sbuff[1];
469  adpcm->loop = sbuff[2];
470  adpcm->channels = sbuff[3];
471  ret = AUDSRV_ERR_NOERROR;
472  }
473 
474  SignalSema(completion_sema);
475 
476  SifFreeIopHeap(iop_addr);
477 
478  return ret;
479 }
480 
482 {
483  /* on iop side, the sample id is like the pointer on ee side */
484  return call_rpc_2(AUDSRV_PLAY_ADPCM, ch, (u32)adpcm);
485 }
486 
488 {
489  return call_rpc_2(AUDSRV_IS_ADPCM_PLAYING, ch, (u32)adpcm);
490 }
491 
493 {
494  /* on iop side, the sample id is like the pointer on ee side */
495  return call_rpc_1(AUDSRV_FREE_ADPCM, (u32)adpcm);
496 }
497 
499 {
500  switch(audsrv_get_error())
501  {
502  case AUDSRV_ERR_NOERROR:
503  return "No error";
504 
505  case AUDSRV_ERR_NOT_INITIALIZED:
506  return "Not initialized";
507 
508  case AUDSRV_ERR_OUT_OF_MEMORY:
509  return "Out of IOP memory";
510 
511  case AUDSRV_ERR_RPC_FAILED:
512  return "RPC operation failed";
513 
514  case AUDSRV_ERR_FORMAT_NOT_SUPPORTED:
515  return "Format not supported";
516 
517  case AUDSRV_ERR_NO_DISC:
518  return "No disc in drive";
519  }
520 
521  return "Unknown error";
522 }
523 
524 int audsrv_on_cdda_stop(audsrv_callback_t cb, void *arg)
525 {
526  on_cdda_stop = cb;
527  on_cdda_stop_arg = arg;
528  return AUDSRV_ERR_NOERROR;
529 }
530 
531 int audsrv_on_fillbuf(int amount, audsrv_callback_t cb, void *arg)
532 {
533  int err;
534 
535  on_fillbuf = 0;
536  on_fillbuf_arg = 0;
537 
538  err = call_rpc_1(AUDSRV_SET_THRESHOLD, amount);
539  if (err != 0)
540  {
541  return err;
542  }
543 
544  on_fillbuf = cb;
545  on_fillbuf_arg = arg;
546  return AUDSRV_ERR_NOERROR;
547 }
548 
550 {
551  return call_rpc_1(AUDSRV_AVAILABLE, 0);
552 }
553 
555 {
556  return call_rpc_1(AUDSRV_QUEUED, 0);
557 }
558 
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:394
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
initialized
static int initialized
Definition: audsrv.c:53
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:481
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:531
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:492
audsrv_adpcm_set_volume_and_pan
int audsrv_adpcm_set_volume_and_pan(int ch, int volume, int pan)
Definition: audsrv_rpc.c:399
iopheap.h
audsrv_on_cdda_stop
int audsrv_on_cdda_stop(audsrv_callback_t cb, void *arg)
Definition: audsrv_rpc.c:524
_gp
void * _gp
audsrv_load_adpcm
int audsrv_load_adpcm(audsrv_adpcm_t *adpcm, void *buffer, int size)
Definition: audsrv_rpc.c:430
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
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:498
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:549
audsrv_queued
int audsrv_queued()
Definition: audsrv_rpc.c:554
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:487
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