summaryrefslogtreecommitdiffstats
path: root/src/modules/module-bt-device.c
blob: 8690e313e42154e99fb034ec3db7a7279ad36130 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/***
    This file is part of PulseAudio.

    Copyright 2008 Joao Paulo Rechi Vita

    PulseAudio is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2 of the License,
    or (at your option) any later version.

    PulseAudio is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with PulseAudio; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
    USA.

    1. Connects to the BlueZ audio service via one BlueZ specific well known unix socket
        bluez/audio/ipc: bt_audio_service_open()
    2. Configures a connection to the BT device
    3. Gets a BT socket fd passed in via the unix socket
        bluez/audio/ipc: bt_audio_service_get_data_fd()
    4. Hands this over to its RT thread.
        pa_thread_mq
***/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <pulse/xmalloc.h>
#include <pulsecore/module.h>
#include <pulsecore/modargs.h>

#include "dbus-util.h"
#include "module-bt-device-symdef.h"
#include "bt-ipc.h"

PA_MODULE_AUTHOR("Joao Paulo Rechi Vita");
PA_MODULE_DESCRIPTION("Bluetooth audio sink and source");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
        "addr=<address of the device> "
        "uuid=<the profile that this device will work on>");

struct userdata {
    pa_core *core;
    pa_module *module;
    pa_sink *sink;

    const char *addr;
    const char *uuid;
};

static const char* const valid_modargs[] = {
    "addr",
    "uuid",
    NULL
};

static int audioservice_send(int sk, const bt_audio_msg_header_t *msg) {
    int e;
    pa_log("sending %s", bt_audio_strmsg(msg->msg_type)); /*debug*/
    if (send(sk, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0)
        e = 0;
    else {
        e = -errno;
        pa_log_error("Error sending data to audio service: %s(%d)", strerror(errno), errno);
    }
    return e;
}

static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) {
    int err;
    const char *type;

    pa_log/*_debug*/("trying to receive msg from audio service...");
    if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) {
        type = bt_audio_strmsg(inmsg->msg_type);
        if (type) {
            pa_log/*_debug*/("Received %s", type);
            err = 0;
        }
        else {
            err = -EINVAL;
            pa_log_error("Bogus message type %d received from audio service", inmsg->msg_type);
        }
    }
    else {
        err = -errno;
        pa_log_error("Error receiving data from audio service: %s(%d)", strerror(errno), errno);
    }

    return err;
}

static int audioservice_expect(int sk, bt_audio_msg_header_t *rsp_hdr, int expected_type) {
    int err = audioservice_recv(sk, rsp_hdr);
    if (err == 0) {
        if (rsp_hdr->msg_type != expected_type) {
            err = -EINVAL;
            pa_log_error("Bogus message %s received while %s was expected", bt_audio_strmsg(rsp_hdr->msg_type),
                    bt_audio_strmsg(expected_type));
        }
    }
    return err;
}

int pa__init(pa_module* m) {
    pa_modargs *ma;
    struct userdata *u;
    int sk = -1;

    pa_assert(m);
    m->userdata = u = pa_xnew0(struct userdata, 1);
    u->module = m;

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log_error("failed to parse module arguments");
        goto fail;
    }
    if (!(u->addr = pa_modargs_get_value(ma, "addr", NULL))) {
        pa_log_error("failed to parse device address from module arguments");
        goto fail;
    }
    if (!(u->uuid = pa_modargs_get_value(ma, "uuid", NULL))) {
        pa_log_error("failed to parse device uuid from module arguments");
        goto fail;
    }
    pa_log("Loading module-bt-device for %s, UUID=%s", u->addr, u->uuid);

    /* Connects to the BlueZ audio service via one BlueZ specific well known unix socket */
    sk = bt_audio_service_open();
    if (sk <= 0) {
        pa_log_error("couldn't connect to bluetooth audio service");
        goto fail;
    }
    pa_log("socket to audio service: %d", sk); /*debug*/

    return 0;

fail:
    pa__done(m);
    return -1;
}

void pa__done(pa_module *m) {
    pa_log("Unloading module-bt-device");
}