summaryrefslogtreecommitdiff
path: root/src/liana/handlers/cdio_server.c
blob: c67330d9378d02cc5c3a7aab2bdb6daf1da4756a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#define AL_LOG_SECTION "cdio"
#include <al/log.h>

#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;
}