~ubuntu-dev/ubuntu/lucid/mpd/lucid-201002101854

« back to all changes in this revision

Viewing changes to src/output_control.c

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2009-10-23 12:38:20 UTC
  • mfrom: (1.1.12 upstream) (2.2.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091023123820-rxt21lmekscxbkbt
Tags: 0.15.4-1ubuntu1
* Merge from debian unstable, Ubuntu remaining changes:
  - debian/control:
    + Don't build-depends on libmikmod2-dev (Debian bug #510675).
    + Move avahi-daemon from Suggests field to Recommends field.
  - debian/mpd.init.d:
    + Read mpd user from mpd.conf.
* Also fixes LP: #332332.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* the Music Player Daemon (MPD)
2
 
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3
 
 * This project's homepage is: http://www.musicpd.org
 
1
/*
 
2
 * Copyright (C) 2003-2009 The Music Player Daemon Project
 
3
 * http://www.musicpd.org
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License as published by
11
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
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
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License along
 
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
 */
18
19
 
19
20
#include "output_control.h"
20
21
#include "output_api.h"
21
22
#include "output_internal.h"
22
23
#include "output_thread.h"
23
 
#include "pcm_utils.h"
 
24
#include "mixer_control.h"
 
25
#include "mixer_plugin.h"
24
26
 
25
 
#include <pthread.h>
26
27
#include <assert.h>
27
28
#include <stdlib.h>
28
29
 
29
 
struct notify audio_output_client_notify = NOTIFY_INITIALIZER;
 
30
enum {
 
31
        /** after a failure, wait this number of seconds before
 
32
            automatically reopening the device */
 
33
        REOPEN_AFTER = 10,
 
34
};
 
35
 
 
36
struct notify audio_output_client_notify;
30
37
 
31
38
static void ao_command_wait(struct audio_output *ao)
32
39
{
51
58
        notify_signal(&ao->notify);
52
59
}
53
60
 
 
61
static bool
 
62
audio_output_open(struct audio_output *ao,
 
63
                  const struct audio_format *audio_format,
 
64
                  const struct music_pipe *mp)
 
65
{
 
66
        bool open;
 
67
 
 
68
        assert(mp != NULL);
 
69
 
 
70
        if (ao->fail_timer != NULL) {
 
71
                g_timer_destroy(ao->fail_timer);
 
72
                ao->fail_timer = NULL;
 
73
        }
 
74
 
 
75
        if (ao->open &&
 
76
            audio_format_equals(audio_format, &ao->in_audio_format)) {
 
77
                assert(ao->pipe == mp);
 
78
 
 
79
                if (ao->pause) {
 
80
                        /* unpause with the CANCEL command; this is a
 
81
                           hack, but suits well for forcing the thread
 
82
                           to leave the ao_pause() thread, and we need
 
83
                           to flush the device buffer anyway */
 
84
 
 
85
                        /* we're not using audio_output_cancel() here,
 
86
                           because that function is asynchronous */
 
87
                        ao_command(ao, AO_COMMAND_CANCEL);
 
88
                }
 
89
 
 
90
                return true;
 
91
        }
 
92
 
 
93
        ao->in_audio_format = *audio_format;
 
94
        ao->chunk = NULL;
 
95
 
 
96
        if (!ao->config_audio_format) {
 
97
                if (ao->open)
 
98
                        audio_output_close(ao);
 
99
 
 
100
                /* no audio format is configured: copy in->out, let
 
101
                   the output's open() method determine the effective
 
102
                   out_audio_format */
 
103
                ao->out_audio_format = ao->in_audio_format;
 
104
        }
 
105
 
 
106
        ao->pipe = mp;
 
107
 
 
108
        if (ao->thread == NULL)
 
109
                audio_output_thread_start(ao);
 
110
 
 
111
        open = ao->open;
 
112
        if (!open) {
 
113
                ao_command(ao, AO_COMMAND_OPEN);
 
114
                open = ao->open;
 
115
        }
 
116
 
 
117
        if (open && ao->mixer != NULL)
 
118
                mixer_open(ao->mixer);
 
119
 
 
120
        return open;
 
121
}
 
122
 
54
123
bool
55
 
audio_output_open(struct audio_output *audioOutput,
56
 
                  const struct audio_format *audioFormat)
57
 
{
58
 
        audioOutput->reopen_after = 0;
59
 
 
60
 
        if (audioOutput->open &&
61
 
            audio_format_equals(audioFormat, &audioOutput->inAudioFormat)) {
62
 
                return true;
63
 
        }
64
 
 
65
 
        audioOutput->inAudioFormat = *audioFormat;
66
 
 
67
 
        if (audio_format_defined(&audioOutput->reqAudioFormat)) {
68
 
                /* copy reqAudioFormat to outAudioFormat only if the
69
 
                   device is not yet open; if it is already open,
70
 
                   plugin->open() may have modified outAudioFormat,
71
 
                   and the value is already ok */
72
 
                if (!audioOutput->open)
73
 
                        audioOutput->outAudioFormat =
74
 
                                audioOutput->reqAudioFormat;
75
 
        } else {
76
 
                audioOutput->outAudioFormat = audioOutput->inAudioFormat;
77
 
                if (audioOutput->open)
78
 
                        audio_output_close(audioOutput);
79
 
        }
80
 
 
81
 
        if (audioOutput->thread == 0)
82
 
                audio_output_thread_start(audioOutput);
83
 
 
84
 
        if (!audioOutput->open)
85
 
                ao_command(audioOutput, AO_COMMAND_OPEN);
86
 
 
87
 
        return audioOutput->open;
88
 
}
89
 
 
90
 
void
91
124
audio_output_update(struct audio_output *ao,
92
 
                    const struct audio_format *audio_format)
 
125
                    const struct audio_format *audio_format,
 
126
                    const struct music_pipe *mp)
93
127
{
 
128
        assert(mp != NULL);
 
129
 
94
130
        if (ao->enabled) {
95
 
                if (ao->reopen_after == 0 || time(NULL) > ao->reopen_after)
96
 
                        audio_output_open(ao, audio_format);
 
131
                if (ao->fail_timer == NULL ||
 
132
                    g_timer_elapsed(ao->fail_timer, NULL) > REOPEN_AFTER)
 
133
                        return audio_output_open(ao, audio_format, mp);
97
134
        } else if (audio_output_is_open(ao))
98
135
                audio_output_close(ao);
 
136
 
 
137
        return false;
99
138
}
100
139
 
101
140
void
102
 
audio_output_signal(struct audio_output *ao)
 
141
audio_output_play(struct audio_output *ao)
103
142
{
 
143
        if (!ao->open)
 
144
                return;
 
145
 
104
146
        notify_signal(&ao->notify);
105
147
}
106
148
 
107
 
void audio_output_play(struct audio_output *audioOutput,
108
 
                       const char *playChunk, size_t size)
109
 
{
110
 
        assert(size > 0);
111
 
 
112
 
        if (!audioOutput->open)
113
 
                return;
114
 
 
115
 
        audioOutput->args.play.data = playChunk;
116
 
        audioOutput->args.play.size = size;
117
 
        ao_command_async(audioOutput, AO_COMMAND_PLAY);
118
 
}
119
 
 
120
 
void audio_output_pause(struct audio_output *audioOutput)
121
 
{
122
 
        ao_command_async(audioOutput, AO_COMMAND_PAUSE);
123
 
}
124
 
 
125
 
void audio_output_cancel(struct audio_output *audioOutput)
126
 
{
127
 
        ao_command_async(audioOutput, AO_COMMAND_CANCEL);
128
 
}
129
 
 
130
 
void audio_output_close(struct audio_output *audioOutput)
131
 
{
132
 
        if (audioOutput->open)
133
 
                ao_command(audioOutput, AO_COMMAND_CLOSE);
134
 
}
135
 
 
136
 
void audio_output_finish(struct audio_output *audioOutput)
137
 
{
138
 
        audio_output_close(audioOutput);
139
 
        if (audioOutput->thread != 0)
140
 
                ao_command(audioOutput, AO_COMMAND_KILL);
141
 
        if (audioOutput->plugin->finish)
142
 
                audioOutput->plugin->finish(audioOutput->data);
143
 
        if (audioOutput->convBuffer)
144
 
                free(audioOutput->convBuffer);
145
 
}
146
 
 
147
 
void audio_output_send_tag(struct audio_output *audioOutput,
148
 
                           const struct tag *tag)
149
 
{
150
 
        if (audioOutput->plugin->send_tag == NULL)
151
 
                return;
152
 
 
153
 
        audioOutput->args.tag = tag;
154
 
        ao_command_async(audioOutput, AO_COMMAND_SEND_TAG);
 
149
void audio_output_pause(struct audio_output *ao)
 
150
{
 
151
        if (ao->mixer != NULL && ao->plugin->pause == NULL)
 
152
                /* the device has no pause mode: close the mixer,
 
153
                   unless its "global" flag is set (checked by
 
154
                   mixer_auto_close()) */
 
155
                mixer_auto_close(ao->mixer);
 
156
 
 
157
        ao_command_async(ao, AO_COMMAND_PAUSE);
 
158
}
 
159
 
 
160
void audio_output_cancel(struct audio_output *ao)
 
161
{
 
162
        ao_command_async(ao, AO_COMMAND_CANCEL);
 
163
}
 
164
 
 
165
void audio_output_close(struct audio_output *ao)
 
166
{
 
167
        assert(!ao->open || ao->fail_timer == NULL);
 
168
 
 
169
        if (ao->mixer != NULL)
 
170
                mixer_auto_close(ao->mixer);
 
171
 
 
172
        if (ao->open)
 
173
                ao_command(ao, AO_COMMAND_CLOSE);
 
174
        else if (ao->fail_timer != NULL) {
 
175
                g_timer_destroy(ao->fail_timer);
 
176
                ao->fail_timer = NULL;
 
177
        }
 
178
}
 
179
 
 
180
void audio_output_finish(struct audio_output *ao)
 
181
{
 
182
        audio_output_close(ao);
 
183
 
 
184
        assert(ao->fail_timer == NULL);
 
185
 
 
186
        if (ao->thread != NULL) {
 
187
                ao_command(ao, AO_COMMAND_KILL);
 
188
                g_thread_join(ao->thread);
 
189
        }
 
190
 
 
191
        if (ao->mixer != NULL)
 
192
                mixer_free(ao->mixer);
 
193
 
 
194
        ao_plugin_finish(ao->plugin, ao->data);
 
195
 
 
196
        notify_deinit(&ao->notify);
 
197
        g_mutex_free(ao->mutex);
155
198
}