summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-11-28 14:23:59 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-11-28 14:23:59 +0000
commitadcfee2f842e6d25c5b7a9c34a4ee0bbcdfe300b (patch)
treebfb075c038db828b88dbd07c0dcb84a2663c2503
parent8776296ee1360e3a7ae1f22c1740cdbc8231df56 (diff)
Support for providing input and output files for audio
-rw-r--r--audio/headset.c162
1 files changed, 157 insertions, 5 deletions
diff --git a/audio/headset.c b/audio/headset.c
index 8910c864..8098e8ed 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -71,6 +71,9 @@ struct headset {
GIOChannel *rfcomm;
GIOChannel *sco;
+ GIOChannel *audio_input;
+ int out;
+
guint ring_timer;
char buf[BUF_SIZE];
@@ -96,6 +99,9 @@ static struct headset *hs = NULL;
static GIOChannel *server_sk = NULL;
+static char *audio_input = NULL;
+static char *audio_output = NULL;
+
static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
const char *address);
static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg);
@@ -359,6 +365,8 @@ failed:
send_simple_signal("Disconnected");
if (hs->sco)
g_io_channel_close(hs->sco);
+ if (hs->out >= 0)
+ close(hs->out);
g_io_channel_close(chan);
free(hs);
hs = NULL;
@@ -407,6 +415,8 @@ static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
memset(hs, 0, sizeof(struct headset));
+ hs->out = -1;
+
hs->rfcomm = g_io_channel_unix_new(cli_sk);
if (!hs->rfcomm) {
error("Allocating new GIOChannel failed!");
@@ -428,10 +438,87 @@ static gboolean server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
return TRUE;
}
+static gboolean audio_input_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
+{
+ int in, out, data_size, written;
+ char buf[1024];
+
+ if (cond & G_IO_NVAL) {
+ g_io_channel_unref(chan);
+ hs->audio_input = NULL;
+ return FALSE;
+ }
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(hs->audio_input);
+ hs->audio_input = NULL;
+ if (hs->out >= 0) {
+ close(hs->out);
+ hs->out = -1;
+ }
+ return FALSE;
+ }
+
+ in = g_io_channel_unix_get_fd(chan);
+ out = g_io_channel_unix_get_fd(hs->sco);
+
+ data_size = read(in, buf, sizeof(buf));
+ if (data_size < 0) {
+ error("read: %s (%d)", strerror(errno), errno);
+ g_io_channel_close(chan);
+ hs->audio_input = NULL;
+ return TRUE;
+ }
+
+ /* EOF */
+ if (data_size == 0) {
+ debug("Reached end of file");
+ g_io_channel_close(chan);
+ hs->audio_input = NULL;
+ return TRUE;
+ }
+
+ written = 0;
+
+ while (written < data_size) {
+ int ret;
+
+ ret = write(out, &buf[written], data_size - written);
+
+ if (ret < 0) {
+ error("write(%d, %p, %d): %s (%d)", out, &buf[data_size],
+ data_size - written, strerror(errno), errno);
+ g_io_channel_close(chan);
+ hs->audio_input = NULL;
+ return TRUE;
+ }
+
+ debug("wrote %d bytes to %s", ret, audio_output);
+
+ written += ret;
+ }
+
+ return TRUE;
+}
+
static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data)
{
+ int in, ret;
+ char buf[1024];
+
if (cond & G_IO_NVAL) {
g_io_channel_unref(chan);
+ if (hs) {
+ if (hs->audio_input) {
+ g_io_channel_close(hs->audio_input);
+ hs->audio_input = NULL;
+ }
+ if (hs->out >= 0) {
+ close(hs->out);
+ hs->out = -1;
+ }
+ }
+
return FALSE;
}
@@ -439,11 +526,32 @@ static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond, gpointer user_dat
error("Audio connection got disconnected");
g_io_channel_close(chan);
hs->sco = NULL;
+ if (hs->audio_input) {
+ g_io_channel_close(hs->audio_input);
+ hs->audio_input = NULL;
+ }
send_simple_signal("Stopped");
return FALSE;
}
- debug("sco_io_cb: Unhandled IO condition");
+ if (!audio_output) {
+ debug("sco_io_cb: Unhandled IO condition");
+ return TRUE;
+ }
+
+ in = g_io_channel_unix_get_fd(chan);
+ if (hs->out < 0)
+ hs->out = open(audio_output, O_WRONLY | O_SYNC | O_CREAT);
+
+ if (hs->out < 0) {
+ error("open(%s): %s (%d)", audio_output, strerror(errno), errno);
+ g_io_channel_close(chan);
+ return TRUE;
+ }
+
+ ret = read(in, buf, sizeof(buf));
+ if (ret > 0)
+ ret = write(hs->out, buf, ret);
return TRUE;
}
@@ -451,7 +559,7 @@ static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond, gpointer user_dat
static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
struct pending_connect *c)
{
- int ret, sk, err;
+ int ret, sk, err, flags;
DBusMessage *reply;
socklen_t len;
@@ -475,8 +583,15 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
goto failed;
}
+ debug("SCO socket %d opened", sk);
+
+ if (audio_output)
+ flags = G_IO_IN;
+ else
+ flags = 0;
+
hs->sco = chan;
- g_io_add_watch(chan, 0, sco_io_cb, NULL);
+ g_io_add_watch(chan, flags, sco_io_cb, NULL);
reply = dbus_message_new_method_return(c->msg);
if (reply) {
@@ -484,6 +599,20 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
dbus_message_unref(reply);
}
+ if (audio_input) {
+ int in;
+
+ in = open(audio_input, O_RDONLY | O_NOCTTY);
+
+ if (in < 0)
+ error("open(%s): %s %d", audio_input, strerror(errno), errno);
+ else {
+ hs->audio_input = g_io_channel_unix_new(in);
+ g_io_add_watch(hs->audio_input, G_IO_IN, audio_input_cb, NULL);
+ }
+
+ }
+
pending_connect_free(c, FALSE);
send_simple_signal("Playing");
@@ -531,6 +660,8 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct pe
memset(hs, 0, sizeof(struct headset));
+ hs->out = -1;
+
ba2str(&c->bda, hs->address);
hs->rfcomm = chan;
@@ -891,6 +1022,10 @@ static DBusHandlerResult stop_message(DBusConnection *conn,
g_io_channel_close(hs->sco);
if (hs->rfcomm)
g_io_channel_close(hs->rfcomm);
+ if (hs->out >= 0) {
+ close(hs->out);
+ hs->out = -1;
+ }
free(hs);
hs = NULL;
}
@@ -1226,6 +1361,10 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg)
if (hs->sco)
g_io_channel_close(hs->sco);
+ if (hs->out >= 0) {
+ close(hs->out);
+ hs->out = -1;
+ }
if (hs->rfcomm)
g_io_channel_close(hs->rfcomm);
@@ -1493,6 +1632,11 @@ static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg)
g_io_channel_close(hs->sco);
hs->sco = NULL;
+ if (hs->out >= 0) {
+ close(hs->out);
+ hs->out = -1;
+ }
+
send_simple_signal("Stopped");
dbus_connection_send(conn, reply, NULL);
@@ -1506,7 +1650,7 @@ int main(int argc, char *argv[])
struct sigaction sa;
int opt, daemonize = 1;
- while ((opt = getopt(argc, argv, "nc:")) != EOF) {
+ while ((opt = getopt(argc, argv, "nc:o:i:")) != EOF) {
switch (opt) {
case 'n':
daemonize = 0;
@@ -1516,8 +1660,16 @@ int main(int argc, char *argv[])
config_channel = strtol(optarg, NULL, 0);
break;
+ case 'i':
+ audio_input = optarg;
+ break;
+
+ case 'o':
+ audio_output = optarg;
+ break;
+
default:
- printf("Usage: %s -c local_channel [-n] [bdaddr]\n", argv[0]);
+ printf("Usage: %s -c local_channel [-n] [-o output] [-i input] [bdaddr]\n", argv[0]);
exit(1);
}
}