diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-11-28 14:23:59 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-11-28 14:23:59 +0000 |
commit | adcfee2f842e6d25c5b7a9c34a4ee0bbcdfe300b (patch) | |
tree | bfb075c038db828b88dbd07c0dcb84a2663c2503 /audio/headset.c | |
parent | 8776296ee1360e3a7ae1f22c1740cdbc8231df56 (diff) |
Support for providing input and output files for audio
Diffstat (limited to 'audio/headset.c')
-rw-r--r-- | audio/headset.c | 162 |
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); } } |