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"
29 /** after a failure, wait this number of seconds before
30 automatically reopening the device */
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
),
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
;
72 if (!audio_format_equals(&ao
->inAudioFormat
, &ao
->outAudioFormat
))
73 convertAudioFormat(ao
, &data
, &size
);
75 ret
= ao
->plugin
->play(ao
->data
, data
, size
);
77 ao
->plugin
->cancel(ao
->data
);
78 ao
->plugin
->close(ao
->data
);
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
);
94 /* pause is not supported - simply close the device */
95 ao
->plugin
->close(ao
->data
);
97 ao_command_finished(ao
);
101 static void *audio_output_task(void *arg
)
103 struct audio_output
*ao
= arg
;
107 switch (ao
->command
) {
108 case AO_COMMAND_NONE
:
111 case AO_COMMAND_OPEN
:
113 ret
= ao
->plugin
->open(ao
->data
,
114 &ao
->outAudioFormat
);
120 ao
->reopen_after
= time(NULL
) + REOPEN_AFTER
;
122 ao_command_finished(ao
);
125 case AO_COMMAND_CLOSE
:
127 ao
->plugin
->cancel(ao
->data
);
128 ao
->plugin
->close(ao
->data
);
130 ao_command_finished(ao
);
133 case AO_COMMAND_PLAY
:
137 case AO_COMMAND_PAUSE
:
141 case AO_COMMAND_CANCEL
:
142 ao
->plugin
->cancel(ao
->data
);
143 ao_command_finished(ao
);
146 case AO_COMMAND_SEND_TAG
:
147 ao
->plugin
->send_tag(ao
->data
, ao
->args
.tag
);
148 ao_command_finished(ao
);
151 case AO_COMMAND_KILL
:
152 ao_command_finished(ao
);
156 notify_wait(&ao
->notify
);
160 void audio_output_thread_start(struct audio_output
*ao
)
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
));