Add RVA2 tag support to MPD
[mpd-mk/avuton.git] / src / output_thread.c
blobb65a601a3e6b405cf4132094040ad3ba7182ba52
1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2008 Max Kellermann <max@duempel.org>
3 * This project's homepage is: http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "output_thread.h"
20 #include "output_api.h"
21 #include "output_internal.h"
23 #include <glib.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <errno.h>
28 enum {
29 /** after a failure, wait this number of seconds before
30 automatically reopening the device */
31 REOPEN_AFTER = 10,
34 static void ao_command_finished(struct audio_output *ao)
36 assert(ao->command != AO_COMMAND_NONE);
37 ao->command = AO_COMMAND_NONE;
38 notify_signal(&audio_output_client_notify);
41 static void convertAudioFormat(struct audio_output *audioOutput,
42 const char **chunkArgPtr, size_t *sizeArgPtr)
44 size_t size = pcm_convert_size(&(audioOutput->inAudioFormat),
45 *sizeArgPtr,
46 &(audioOutput->outAudioFormat));
48 if (size > audioOutput->convBufferLen) {
49 if (audioOutput->convBuffer != NULL)
50 free(audioOutput->convBuffer);
51 audioOutput->convBuffer = g_malloc(size);
52 audioOutput->convBufferLen = size;
55 *sizeArgPtr = pcm_convert(&(audioOutput->inAudioFormat),
56 *chunkArgPtr, *sizeArgPtr,
57 &(audioOutput->outAudioFormat),
58 audioOutput->convBuffer,
59 &audioOutput->convState);
61 *chunkArgPtr = audioOutput->convBuffer;
64 static void ao_play(struct audio_output *ao)
66 const char *data = ao->args.play.data;
67 size_t size = ao->args.play.size;
68 bool ret;
70 assert(size > 0);
72 if (!audio_format_equals(&ao->inAudioFormat, &ao->outAudioFormat))
73 convertAudioFormat(ao, &data, &size);
75 ret = ao->plugin->play(ao->data, data, size);
76 if (!ret) {
77 ao->plugin->cancel(ao->data);
78 ao->plugin->close(ao->data);
79 ao->open = false;
82 ao_command_finished(ao);
85 static void ao_pause(struct audio_output *ao)
87 ao->plugin->cancel(ao->data);
89 if (ao->plugin->pause != NULL) {
90 /* pause is supported */
91 ao_command_finished(ao);
92 ao->plugin->pause(ao->data);
93 } else {
94 /* pause is not supported - simply close the device */
95 ao->plugin->close(ao->data);
96 ao->open = false;
97 ao_command_finished(ao);
101 static void *audio_output_task(void *arg)
103 struct audio_output *ao = arg;
104 bool ret;
106 while (1) {
107 switch (ao->command) {
108 case AO_COMMAND_NONE:
109 break;
111 case AO_COMMAND_OPEN:
112 assert(!ao->open);
113 ret = ao->plugin->open(ao->data,
114 &ao->outAudioFormat);
116 assert(!ao->open);
117 if (ret == true)
118 ao->open = true;
119 else
120 ao->reopen_after = time(NULL) + REOPEN_AFTER;
122 ao_command_finished(ao);
123 break;
125 case AO_COMMAND_CLOSE:
126 assert(ao->open);
127 ao->plugin->cancel(ao->data);
128 ao->plugin->close(ao->data);
129 ao->open = false;
130 ao_command_finished(ao);
131 break;
133 case AO_COMMAND_PLAY:
134 ao_play(ao);
135 break;
137 case AO_COMMAND_PAUSE:
138 ao_pause(ao);
139 break;
141 case AO_COMMAND_CANCEL:
142 ao->plugin->cancel(ao->data);
143 ao_command_finished(ao);
144 break;
146 case AO_COMMAND_SEND_TAG:
147 ao->plugin->send_tag(ao->data, ao->args.tag);
148 ao_command_finished(ao);
149 break;
151 case AO_COMMAND_KILL:
152 ao_command_finished(ao);
153 return NULL;
156 notify_wait(&ao->notify);
160 void audio_output_thread_start(struct audio_output *ao)
162 pthread_attr_t attr;
164 assert(ao->command == AO_COMMAND_NONE);
166 pthread_attr_init(&attr);
167 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
168 if (pthread_create(&ao->thread, &attr, audio_output_task, ao))
169 g_error("Failed to spawn output task: %s\n", strerror(errno));