#define AL_LOG_SECTION "cdio" #include #include "../../cache/entry.h" #include "../../cache/handlers/cdio.h" #include "cdio.h" #define SECTORS_PER_PACKET 8 static bool cdio_server_init(struct lia_server_handler *handler, struct cch_handle *handle) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; cdio->handle = handle; cdio->fmt.format = CAMU_SAMPLE_FORMAT_S16; cdio->fmt.sample_rate = 44100; cdio->fmt.channel_count = 2; nn_buffer_init(&cdio->buffer); cdio->pts = 0.0; if (handle->entry->chapter) { cch_handle_seek(handle, handle->entry->chapter->start * CDIO_CD_FRAMESIZE_RAW, SEEK_SET); } return true; } static void cdio_server_write_info(struct lia_server_handler *handler, struct nn_packet *packet) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; u64 duration = cdio->handler.get_duration(&cdio->handler); nn_packet_write_u64(packet, duration); nn_packet_write_u32(packet, 1); // 1 stream. nn_packet_write_str(packet, &al_str_c("pcm_s16le")); nn_packet_write_u8(packet, CAMU_NORMAL); nn_packet_write_u8(packet, CAMU_STREAM_AUDIO); nn_packet_write_u64(packet, duration); nn_packet_write_s32(packet, 0); // index. nn_packet_write_s32(packet, cdio->fmt.format); nn_packet_write_s32(packet, cdio->fmt.sample_rate); nn_packet_write_s32(packet, cdio->fmt.channel_count); } static void cdio_server_subscribe(struct lia_server_handler *handler, u64 mask) { (void)handler; (void)mask; } static u64 cdio_server_get_duration(struct lia_server_handler *handler) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; struct cch_chapter *first = &al_array_at(cdio->handle->entry->chapters, 0); struct cch_chapter *last = &al_array_last(cdio->handle->entry->chapters); u64 length = camu_audio_format_bytes_to_usec(&cdio->fmt, (last->end - first->start) * CDIO_CD_FRAMESIZE_RAW); log_info("Length: %.2fs.", length / 1000000.0); return length; } static bool cdio_server_seek(struct lia_server_handler *handler, u64 pos) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; (void)cdio; (void)pos; return false; } static void cdio_server_step(struct lia_server_handler *handler) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; (void)cdio; } static void cdio_server_write_packet(struct lia_server_handler *handler, struct nn_packet *packet) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)handler; off_t size = CDIO_CD_FRAMESIZE_RAW * SECTORS_PER_PACKET; nn_buffer_ensure_space(&cdio->buffer, size); s32 ret = cch_handle_read(cdio->handle, nn_buffer_get_ptr(&cdio->buffer, 0), size); if (ret == CAMU_ERR_EOF) { cdio->handler.status = CAMU_ERR_EOF; nn_packet_write_u8(packet, LIANA_PACKET_EOF); return; } cdio->handler.status = CAMU_OK; nn_packet_write_u8(packet, LIANA_PACKET_DATA); nn_packet_write_s32(packet, 0); nn_packet_write_f64(packet, cdio->pts); s32 sample_count = ret / (camu_audio_format_bytes_per_sample(&cdio->fmt) * cdio->fmt.channel_count); nn_packet_write_s32(packet, sample_count); cdio->buffer.size = ret; nn_packet_write_buffer(packet, &cdio->buffer); cdio->pts += camu_audio_format_samples_to_sec(&cdio->fmt, sample_count); } static void cdio_server_free(struct lia_server_handler **handler) { struct lia_cdio_server *cdio = (struct lia_cdio_server *)*handler; al_free(cdio); *handler = NULL; } struct lia_server_handler *lia_cdio_server_create() { struct lia_cdio_server *cdio = al_alloc_object(struct lia_cdio_server); cdio->handler.init = cdio_server_init; cdio->handler.write_info = cdio_server_write_info; cdio->handler.subscribe = cdio_server_subscribe; cdio->handler.get_duration = cdio_server_get_duration; cdio->handler.seek = cdio_server_seek; cdio->handler.step = cdio_server_step; cdio->handler.write_packet = cdio_server_write_packet; cdio->handler.free = cdio_server_free; return (struct lia_server_handler *)cdio; }