PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
audsrv.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*/
9
15#include <stdio.h>
16#include <thbase.h>
17#include <thsemap.h>
18#include <loadcore.h>
19#include <sysmem.h>
20#include <intrman.h>
21#include <sifcmd.h>
22#include <libsd.h>
23#include <sysclib.h>
24
25#include <audsrv.h>
26#include "audsrv_internal.h"
27#include "common.h"
28#include "rpc_server.h"
29#include "rpc_client.h"
30#include "upsamplers.h"
31#include "hw.h"
32#include "spu.h"
33#include "debug_printf.h"
34
35#define MODNAME "audsrv"
36#define VERSION "0.93"
37IRX_ID(MODNAME, 1, 4);
38
39/* globals */
43static int core1_freq = 0;
45static int core1_bits = 0;
47static int core1_channels = 0;
49static int core1_sample_shift = 0;
50
51/* status */
53static int initialized = 0;
55static int playing = 0;
56
57
58/* ring buffer properties */
60static char ringbuf[20480];
62static int ringbuf_size = sizeof(ringbuf);
64static int readpos;
66static int writepos;
67
69static int play_tid = 0;
71static int queue_sema = 0;
73static int transfer_sema = 0;
75static int fillbuf_threshold = 0;
76
78static int format_changed = 0;
79
81static u8 core1_buf[0x1000] __attribute__((aligned (16)));
82
83static short rendered_left [ 512 ];
84static short rendered_right[ 512 ];
85
87extern struct irx_export_table _exp_audsrv;
88
89/* forward declarations */
90static void play_thread(void *arg);
91
99static int transfer_complete(void *arg)
100{
101 (void)arg;
102
103 iSignalSema(transfer_sema);
104 return 1;
105}
106
108static void update_volume()
109{
110 int vol;
111
112 /* external input */
113 sceSdSetParam(SD_CORE_1 | SD_PARAM_AVOLL, 0x7fff);
114 sceSdSetParam(SD_CORE_1 | SD_PARAM_AVOLR, 0x7fff);
115
116 /* core0 input */
117 sceSdSetParam(SD_CORE_0 | SD_PARAM_BVOLL, 0);
118 sceSdSetParam(SD_CORE_0 | SD_PARAM_BVOLR, 0);
119
120 /* core1 input */
121 vol = playing ? core1_volume : 0;
122 sceSdSetParam(SD_CORE_1 | SD_PARAM_BVOLL, vol);
123 sceSdSetParam(SD_CORE_1 | SD_PARAM_BVOLR, vol);
124
125 /* set master volume for core 0 */
126 sceSdSetParam(SD_CORE_0 | SD_PARAM_MVOLL, 0);
127 sceSdSetParam(SD_CORE_0 | SD_PARAM_MVOLR, 0);
128
129 /* set master volume for core 1 */
130 sceSdSetParam(SD_CORE_1 | SD_PARAM_MVOLL, MAX_VOLUME);
131 sceSdSetParam(SD_CORE_1 | SD_PARAM_MVOLR, MAX_VOLUME);
132}
133
140{
141 /* audio is still playing, just mute */
142 playing = 0;
145
146 return AUDSRV_ERR_NOERROR;
147}
148
156int audsrv_format_ok(int freq, int bits, int channels)
157{
158 if (find_upsampler(freq, bits, channels) != NULL)
159 {
160 return 1;
161 }
162
163 /* unsupported format */
164 return 0;
165}
166
178int audsrv_set_format(int freq, int bits, int channels)
179{
180 int feed_size;
181
182 if (audsrv_format_ok(freq, bits, channels) == 0)
183 {
184 return -AUDSRV_ERR_FORMAT_NOT_SUPPORTED;
185 }
186
187 /* update shift-right count */
189 if (bits == 16)
190 {
192 }
193
194 if (channels == 2)
195 {
197 }
198
199 core1_freq = freq;
200 core1_bits = bits;
201 core1_channels = channels;
202
203 /* set ring buffer size to 10 iterations worth of data (~50 ms) */
204 feed_size = ((512 * core1_freq) / 48000) << core1_sample_shift;
205 ringbuf_size = feed_size * 10;
206
207 writepos = 0;
208 readpos = (feed_size * 5) & ~3;
209
210 DPRINTF("freq %d bits %d channels %d ringbuf_sz %d feed_size %d shift %d\n", freq, bits, channels, ringbuf_size, feed_size, core1_sample_shift);
211
212 format_changed = 1;
213 return AUDSRV_ERR_NOERROR;
214}
215
220{
221 if (initialized)
222 {
223 return 0;
224 }
225
226 /* initialize libsd */
227 if (sceSdInit(SD_INIT_COLD) < 0)
228 {
229 DPRINTF("failed to initialize libsd\n");
230 return -1;
231 }
232
233 readpos = 0;
234 writepos = 0;
235
236 /* initialize transfer_complete's semaphore */
237 transfer_sema = CreateMutex(0);
238 if (transfer_sema < 0)
239 {
240 return AUDSRV_ERR_OUT_OF_MEMORY;
241 }
242
243 queue_sema = CreateMutex(0);
244 if (queue_sema < 0)
245 {
246 DeleteSema(transfer_sema);
247 return AUDSRV_ERR_OUT_OF_MEMORY;
248 }
249
250 /* audio is always playing in the background. trick is to
251 * set the data input volume to zero
252 */
254
255 /* initialize transfer-complete callback */
256 sceSdSetTransCallback(AUDSRV_BLOCK_DMA_CH, (void *)transfer_complete);
257 sceSdBlockTrans(AUDSRV_BLOCK_DMA_CH, SD_TRANS_LOOP, core1_buf, sizeof(core1_buf), 0);
258
259 /* default to SPU's native */
260 audsrv_set_format(48000, 16, 2);
261
263 DPRINTF("playing thread 0x%x started\n", play_tid);
264
265 DPRINTF("kickstarted\n");
266
267 initialized = 1;
268 return AUDSRV_ERR_NOERROR;
269}
270
279{
280 if (writepos <= readpos)
281 {
282 return readpos - writepos;
283 }
284 else
285 {
286 return (ringbuf_size - (writepos - readpos));
287 }
288}
289
296{
297 if (writepos < readpos)
298 {
299 return (ringbuf_size - (readpos - writepos));
300 }
301 else
302 {
303 return writepos - readpos;
304 }
305}
306
314int audsrv_wait_audio(int buflen)
315{
316 if (ringbuf_size < buflen)
317 {
318 /* this will never happen */
319 return AUDSRV_ERR_ARGS;
320 }
321
322 while (1)
323 {
324 if (audsrv_available() >= buflen)
325 {
326 /* enough space! */
327 return AUDSRV_ERR_NOERROR;
328 }
329
330 WaitSema(queue_sema);
331 }
332}
333
344int audsrv_play_audio(const char *buf, int buflen)
345{
346 int sent = 0;
347
348 if (initialized == 0)
349 {
350 return -AUDSRV_ERR_NOT_INITIALIZED;
351 }
352
353 if (playing == 0)
354 {
355 /* audio is always playing, just change the volume */
356 playing = 1;
358 }
359
360 //DPRINTF("play audio %d bytes, readpos %d, writepos %d avail %d\n", buflen, readpos, writepos, audsrv_available());
361
362 /* limit to what's available, no crossing possible */
363 buflen = MIN(buflen, audsrv_available());
364
365 while (buflen > 0)
366 {
367 int copy = buflen;
368 if (writepos >= readpos)
369 {
370 copy = MIN(ringbuf_size - writepos, buflen);
371 }
372
373 memcpy(ringbuf + writepos, buf, copy);
374 buf = buf + copy;
375 buflen = buflen - copy;
376 sent = sent + copy;
377
378 writepos = writepos + copy;
379 if (writepos >= ringbuf_size)
380 {
381 /* rewind */
382 writepos = 0;
383 }
384 }
385
386 return sent;
387}
388
394{
395 if (vol < 0 || vol > MAX_VOLUME)
396 {
397 /* bad joke */
398 return AUDSRV_ERR_ARGS;
399 }
400
401 core1_volume = vol;
403 return AUDSRV_ERR_NOERROR;
404}
405
406int audsrv_set_threshold(int amount)
407{
408 if (amount > (ringbuf_size / 2))
409 {
410 /* amount is greater than what we'd recommend */
411 return AUDSRV_ERR_ARGS;
412 }
413
414 DPRINTF("callback threshold: %d\n", amount);
415 fillbuf_threshold = amount;
416 return 0;
417}
418
429static void play_thread(void *arg)
430{
431 int intr_state;
432 int step;
433 struct upsample_t up;
434 upsampler_t upsampler = NULL;
435
436 (void)arg;
437
438 DPRINTF("starting play thread\n");
439 while (1)
440 {
441 int block;
442 u8 *bufptr;
443 int available;
444
445 if (format_changed)
446 {
448 format_changed = 0;
449 }
450
451 if (playing && upsampler != NULL)
452 {
453 up.src = (const unsigned char *)ringbuf + readpos;
454 up.left = rendered_left;
455 up.right = rendered_right;
456 step = upsampler(&up);
457
458 readpos = readpos + step;
459 if (readpos >= ringbuf_size)
460 {
461 /* wrap around */
462 readpos = 0;
463 }
464 }
465 else
466 {
467 /* not playing */
468 memset(rendered_left, '\0', sizeof(rendered_left));
469 memset(rendered_right, '\0', sizeof(rendered_right));
470 }
471
472 /* wait until it's safe to transmit another block */
473 WaitSema(transfer_sema);
474
475 /* suspend all interrupts */
476 CpuSuspendIntr(&intr_state);
477
478 /* one block is playing currently, other is idle */
479 block = 1 - (sceSdBlockTransStatus(AUDSRV_BLOCK_DMA_CH, 0) >> 24);
480
481 /* copy 1024 bytes from left and right buffers, into core1_buf */
482 bufptr = core1_buf + (block << 11);
483 wmemcpy(bufptr + 0, rendered_left + 0, 512);
484 wmemcpy(bufptr + 512, rendered_right + 0, 512);
485 wmemcpy(bufptr + 1024, rendered_left + 256, 512);
486 wmemcpy(bufptr + 1536, rendered_right + 256, 512);
487
488 CpuResumeIntr(intr_state);
489
490 available = audsrv_available();
491 if (available >= (ringbuf_size / 10))
492 {
493 /* arbitrarily selected ringbuf_size / 10, to reduce
494 * number of semaphores signalled.
495 */
496 SignalSema(queue_sema);
497 }
498
499 if (fillbuf_threshold > 0 && available >= fillbuf_threshold)
500 {
501 /* EE client requested a callback */
502 call_client_callback(AUDSRV_FILLBUF_CALLBACK);
503 }
504
505 //DPRINTF("avaiable: %d, queued: %d\n", available, ringbuf_size - available);
506 }
507}
508
513{
514 /* silence! */
518
519 /* stop transmission */
520 sceSdSetTransCallback(AUDSRV_BLOCK_DMA_CH, NULL);
521 sceSdBlockTrans(AUDSRV_BLOCK_DMA_CH, SD_TRANS_STOP, 0, 0, 0);
522
523 /* stop playing thread */
524 if (play_tid > 0)
525 {
526 TerminateThread(play_tid);
527 DeleteThread(play_tid);
528 play_tid = 0;
529 }
530
531#ifndef NO_RPC_THREAD
532 /* Deinitialize RPC client, only once the playback thread is stopped. */
533 deinitialize_rpc_client();
534#endif
535
536 if (transfer_sema > 0)
537 {
538 DeleteSema(transfer_sema);
539 transfer_sema = 0;
540 }
541
542 if (queue_sema > 0)
543 {
544 DeleteSema(queue_sema);
545 queue_sema = 0;
546 }
547
548 return 0;
549}
550
556int _start(int argc, char *argv[])
557{
558 int err;
559
560 (void)argc;
561 (void)argv;
562
563 FlushDcache();
564 CpuEnableIntr(0);
565
566 printf("greetings from version " VERSION " !\n");
567
568 err = RegisterLibraryEntries(&_exp_audsrv);
569 if (err != 0)
570 {
571 DPRINTF("couldn't register library entries. Error %d\n", err);
572 return MODULE_NO_RESIDENT_END;
573 }
574
576
577 /* create RPC listener thread */
578 initialize_rpc_thread();
579
580 return MODULE_RESIDENT_END;
581}
int audsrv_queued()
Definition audsrv.c:295
static int play_tid
Definition audsrv.c:69
int audsrv_set_volume(int vol)
Definition audsrv.c:393
int audsrv_wait_audio(int buflen)
Definition audsrv.c:314
static int core1_channels
Definition audsrv.c:47
static int playing
Definition audsrv.c:55
int audsrv_init()
Definition audsrv.c:219
static int writepos
Definition audsrv.c:66
static int fillbuf_threshold
Definition audsrv.c:75
static char ringbuf[20480]
Definition audsrv.c:60
static int core1_volume
Definition audsrv.c:41
static int readpos
Definition audsrv.c:64
int audsrv_stop_audio()
Definition audsrv.c:139
static int core1_sample_shift
Definition audsrv.c:49
static int queue_sema
Definition audsrv.c:71
int _start(int argc, char *argv[])
Definition audsrv.c:556
static int transfer_complete(void *arg)
Definition audsrv.c:99
int audsrv_available()
Definition audsrv.c:278
int audsrv_set_format(int freq, int bits, int channels)
Definition audsrv.c:178
int audsrv_format_ok(int freq, int bits, int channels)
Definition audsrv.c:156
static int ringbuf_size
Definition audsrv.c:62
static void update_volume()
Definition audsrv.c:108
static int format_changed
Definition audsrv.c:78
static int core1_freq
Definition audsrv.c:43
static int core1_bits
Definition audsrv.c:45
static int initialized
Definition audsrv.c:53
struct irx_export_table _exp_audsrv
int audsrv_play_audio(const char *buf, int buflen)
Definition audsrv.c:344
static void play_thread(void *arg)
Definition audsrv.c:429
static int transfer_sema
Definition audsrv.c:73
int audsrv_quit()
Definition audsrv.c:512
#define AUDSRV_ERR_NOERROR
Definition audsrv.h:28
int audsrv_adpcm_init()
Definition audsrv_rpc.c:394
#define MAX_VOLUME
Definition audsrv.h:25
int audsrv_stop_cd()
Definition audsrv_rpc.c:207
int CpuEnableIntr()
Definition intrman.c:250
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int create_thread(void *func, int priority, void *param)
Definition common.c:34
upsampler_t find_upsampler(int freq, int bits, int channels)
Definition upsamplers.c:636