~ubuntu-branches/ubuntu/precise/ultrastar-ng/precise

« back to all changes in this revision

Viewing changes to src/audio.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Miriam Ruiz, Miriam Ruiz, Mario Bonino, Jon Dowland, Ansgar Burchardt
  • Date: 2008-06-07 16:43:18 UTC
  • mfrom: (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080607164318-4cnzizck1tp8mrwp
Tags: 0.2.1-1
[ Miriam Ruiz ]
* New Upstream Release (Closes: #453132)
* Removed unneeded patches
* Added packages to build deps:
  + libtool
  + portaudio19-dev | portaudio-dev
  + libboost-dev, libboost-thread-dev, libboost-serialization-dev
  + libboost-program-options-dev, libboost-regex-dev
* Moved shared objects to private directory: /usr/lib/ultraster-ng
* Added rpath to binaries to search for shared objects in the private dir
* Uses ultrastar-ng-gstreamer as default, instead of ultrastar-ng-xine,
  since there are significantly less issues with GStreamer.
* Added patch to fix upstream desktop file
* Added -Wl,-as-needed to LDFLAGS
* Replaced fftw3-dev by libfftw3-dev in build dependencies.
* Standards-Version upgraded to 3.7.3

[ Mario Bonino ]
* Fixed data/Makefile.am to install .desktop file and icon

[ Jon Dowland ]
* add Homepage: control field to source stanza
* fix a bashism in debian/rules (Closes: #478634)

[ Ansgar Burchardt ]
* debian/control: Change XS-Vcs-* to Vcs-*
* Remove Homepage semi-field from description

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#include <audio.h>
2
2
 
 
3
#include <iostream>
 
4
#include <boost/thread/xtime.hpp>
 
5
#include <cmath>
 
6
 
3
7
#define LENGTH_ERROR -1
4
8
 
5
 
CAudio::CAudio()
6
 
{
 
9
CAudio::CAudio(): m_type() {
7
10
#ifdef USE_LIBXINE_AUDIO
8
11
        xine = xine_new();
9
 
        xine_init(xine);
10
 
        vo_port = xine_open_video_driver ( xine, NULL, XINE_VISUAL_TYPE_NONE, NULL);    /*Create a fake vo_port*/ 
11
 
        ao_port = xine_open_audio_driver(xine , "auto", NULL);
12
 
        stream = xine_stream_new(xine, ao_port, vo_port);
13
 
        event_queue = xine_event_new_queue(stream);
 
12
        xine_init(xine);
 
13
        vo_port = xine_open_video_driver (xine, NULL, XINE_VISUAL_TYPE_NONE, NULL);    /*Create a fake vo_port*/ 
 
14
        ao_port = xine_open_audio_driver(xine , "auto", NULL);
 
15
        stream = xine_stream_new(xine, ao_port, vo_port);
 
16
        event_queue = xine_event_new_queue(stream);
14
17
        xine_playing = 0;
15
18
#endif
16
19
#ifdef USE_GSTREAMER_AUDIO
22
25
        music = gst_element_factory_make ("playbin", "play");
23
26
        /*If you don't want play video with gstreamer*/
24
27
        fakesink = gst_element_factory_make ("fakesink", "fakesink");
25
 
        g_object_set (G_OBJECT (music), "video-sink", fakesink, NULL);
26
 
        /*Output sink*/
27
 
        sink = gst_element_factory_make ("gconfaudiosink", "audiosink");
28
 
        /* if we could create the gconf sink use that, otherwise let playbin decide */
29
 
        if (sink != NULL) {
30
 
                /* set the profile property on the gconfaudiosink to "music and movies" */
31
 
                if (g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "profile"))
32
 
                        g_object_set (G_OBJECT (sink), "profile", 1, NULL);
33
 
 
34
 
                g_object_set (G_OBJECT (music), "audio-sink", sink, NULL);
35
 
        }
 
28
        g_object_set (G_OBJECT (music), "video-sink", fakesink, NULL);
 
29
        /*Output sink*/
 
30
        sink = gst_element_factory_make ("gconfaudiosink", "audiosink");
 
31
        /* if we could create the gconf sink use that, otherwise let playbin decide */
 
32
        if (sink != NULL) {
 
33
                /* set the profile property on the gconfaudiosink to "music and movies" */
 
34
                if (g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "profile"))
 
35
                  g_object_set (G_OBJECT (sink), "profile", 1, NULL);
 
36
                g_object_set (G_OBJECT (music), "audio-sink", sink, NULL);
 
37
        }
36
38
#endif
37
39
        length = 0;
 
40
        m_thread.reset(new boost::thread(boost::ref(*this)));
38
41
}
39
42
 
40
 
CAudio::~CAudio()
41
 
{
 
43
CAudio::~CAudio() {
 
44
        {
 
45
                boost::mutex::scoped_lock l(m_mutex);
 
46
                m_type = QUIT;
 
47
                m_cond.notify_one();
 
48
        }
 
49
        m_thread->join();
42
50
#ifdef USE_LIBXINE_AUDIO
43
 
        xine_close(stream);
44
 
        xine_event_dispose_queue(event_queue);
45
 
        xine_dispose(stream);
46
 
        stream = NULL;
47
 
        xine_close_audio_driver(xine, ao_port);
48
 
        xine_close_video_driver(xine, vo_port);   
49
 
        xine_exit(xine);
 
51
        xine_close(stream);
 
52
        xine_event_dispose_queue(event_queue);
 
53
        xine_dispose(stream);
 
54
        stream = NULL;
 
55
        xine_close_audio_driver(xine, ao_port);
 
56
        xine_close_video_driver(xine, vo_port);   
 
57
        xine_exit(xine);
50
58
#endif
51
59
#ifdef USE_GSTREAMER_AUDIO
52
60
        gst_object_unref (GST_OBJECT (music));
53
61
#endif
54
62
}
55
63
 
56
 
void CAudio::playMusic( char * filename )
57
 
{
58
 
        if (isPlaying()) 
59
 
            stopMusic();
60
 
 
61
 
#ifdef USE_LIBXINE_AUDIO
62
 
        int pos_stream;
 
64
namespace {
 
65
        // Boost WTF time format, directly from C...
 
66
        boost::xtime& operator+=(boost::xtime& time, double seconds) {
 
67
                double nsec = 1e9 * (time.sec + seconds) + time.nsec;
 
68
                time.sec = boost::xtime::xtime_sec_t(nsec / 1e9);
 
69
                time.nsec = boost::xtime::xtime_nsec_t(std::fmod(nsec, 1e9));
 
70
                return time;
 
71
        }
 
72
        boost::xtime operator+(boost::xtime const& left, double seconds) {
 
73
                boost::xtime time = left;
 
74
                return time += seconds;
 
75
        }
 
76
        boost::xtime now() {
 
77
                boost::xtime time;
 
78
                boost::xtime_get(&time, boost::TIME_UTC);
 
79
                return time;
 
80
        }
 
81
}
 
82
 
 
83
void CAudio::operator()() {
 
84
        for (;;) {
 
85
                Type type;
 
86
                std::string filename;
 
87
                {
 
88
                        boost::mutex::scoped_lock l(m_mutex);
 
89
                        m_ready = true;
 
90
                        m_condready.notify_all();
 
91
                        while (m_type == NONE) m_cond.wait(l);
 
92
                        m_ready = false;
 
93
                        type = m_type;
 
94
                        m_type = NONE;
 
95
                        filename = m_filename;
 
96
                }
 
97
                switch (type) {
 
98
                  case NONE: // Should not get here...
 
99
                  case QUIT: return;
 
100
                  case STOP: stopMusic_internal(); break;
 
101
                  case PREVIEW:
 
102
                        // Wait a little while before actually starting
 
103
                        boost::thread::sleep(now() + 0.35);
 
104
                        {
 
105
                                boost::mutex::scoped_lock l(m_mutex);
 
106
                                // Did we receive another event already?
 
107
                                if (m_type != NONE) continue;
 
108
                        }
 
109
                        playPreview_internal(filename);
 
110
                        break;
 
111
                  case PLAY: playMusic_internal(filename); break;
 
112
                }
 
113
        }
 
114
}
 
115
 
 
116
unsigned int CAudio::getVolume_internal() {
 
117
#ifdef USE_LIBXINE_AUDIO
 
118
        return xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME);
 
119
#endif
 
120
#ifdef USE_GSTREAMER_AUDIO
 
121
        gdouble vol;
 
122
        g_object_get (music, "volume", &vol, NULL);
 
123
        return (unsigned int)(vol*100);
 
124
#endif
 
125
}
 
126
 
 
127
void CAudio::setVolume_internal(unsigned int _volume) {
 
128
#ifdef USE_LIBXINE_AUDIO
 
129
        xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, _volume);
 
130
#endif
 
131
#ifdef USE_GSTREAMER_AUDIO
 
132
        gdouble vol = _volume/100.;
 
133
        g_object_set (music, "volume", vol, NULL);
 
134
#endif
 
135
}
 
136
 
 
137
void CAudio::playMusic_internal(std::string const& filename) {
 
138
        stopMusic_internal();
 
139
#ifdef USE_LIBXINE_AUDIO
 
140
        int pos_stream;
63
141
        int pos_time;
64
 
 
65
 
        if (!xine_open(stream, filename) || !xine_play(stream, 0, 0)) {
66
 
            printf("could not open %s\n", filename);
67
 
        }
68
 
 
69
 
        if( !xine_get_pos_length(stream, &pos_stream, &pos_time, &length) )
70
 
                length = LENGTH_ERROR;
71
 
 
72
 
        xine_playing = 1;
 
142
        if (!xine_open(stream, filename.c_str()) || !xine_play(stream, 0, 0)) {
 
143
                std::cout << "Could not open " << filename << std::endl;
 
144
        }
 
145
        if (!xine_get_pos_length(stream, &pos_stream, &pos_time, &length)) length = LENGTH_ERROR;
 
146
        xine_playing = 1;
73
147
#endif
74
148
#ifdef USE_GSTREAMER_AUDIO
75
 
        if( filename[0] == '/' )
76
 
                g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",filename,NULL), NULL);
77
 
        else
78
 
                g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",get_current_dir_name(),"/",filename,NULL), NULL);
 
149
        if (filename[0] == '/') g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",filename.c_str(),NULL), NULL);
 
150
        else g_object_set(G_OBJECT (music), "uri", g_strconcat("file://",get_current_dir_name(),"/",filename.c_str(),NULL), NULL);
79
151
        gst_element_set_state (music, GST_STATE_PLAYING);
80
152
        GstFormat fmt = GST_FORMAT_TIME;
81
153
        gint64 len;
82
 
        if (!gst_element_query_duration (music, &fmt, &len))
83
 
                length = LENGTH_ERROR;
84
 
        else
85
 
                length = (int) (len/GST_MSECOND);
 
154
        length = gst_element_query_duration(music, &fmt, &len) ? int(len/GST_MSECOND) : LENGTH_ERROR;
86
155
#endif
87
156
}
88
157
 
89
 
 
90
 
 
91
 
void CAudio::playPreview( char * filename )
92
 
{
93
 
        if (isPlaying()) 
94
 
            stopMusic();
95
 
 
 
158
void CAudio::playPreview_internal(std::string const& filename) {
 
159
        unsigned int volume = getVolume_internal();
 
160
        setVolume_internal(0);
 
161
        stopMusic_internal();
96
162
#ifdef USE_LIBXINE_AUDIO
97
 
        int pos_stream;
 
163
        int pos_stream;
98
164
        int pos_time;
99
165
 
100
 
        if (!xine_open(stream, filename) || !xine_play(stream, 0, 30000)) {
101
 
            printf("could not open %s\n", filename);
102
 
        }
103
 
 
104
 
        if( !xine_get_pos_length(stream, &pos_stream, &pos_time, &length) )
105
 
                length = LENGTH_ERROR;
106
 
 
107
 
        xine_playing = 1;
 
166
        if (!xine_open(stream, filename.c_str()) || !xine_play(stream, 0, 0) || !xine_play(stream, 0, 30000)) {
 
167
                std::cout << "Could not open " << filename << std::endl;
 
168
        }
 
169
 
 
170
        if (!xine_get_pos_length(stream, &pos_stream, &pos_time, &length)) length = LENGTH_ERROR;
 
171
        xine_playing = 1;
108
172
#endif
109
173
#ifdef USE_GSTREAMER_AUDIO
110
 
        if( filename[0] == '/' )
111
 
                g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",filename,NULL), NULL);
112
 
        else
113
 
                g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",get_current_dir_name(),"/",filename,NULL), NULL);
 
174
        if (filename[0] == '/') g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",filename.c_str(),NULL), NULL);
 
175
        else g_object_set (G_OBJECT (music), "uri", g_strconcat("file://",get_current_dir_name(),"/",filename.c_str(),NULL), NULL);
114
176
        gst_element_set_state (music, GST_STATE_PAUSED);
115
177
        GstState state_paused = GST_STATE_PAUSED;
116
178
        gst_element_get_state (music, NULL, &state_paused, GST_CLOCK_TIME_NONE);
117
 
        if( !gst_element_seek(music, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
118
 
                GST_SEEK_TYPE_SET, 30*GST_SECOND,
119
 
                GST_SEEK_TYPE_SET, 60*GST_SECOND))
120
 
                g_print("playPreview() seek failed\n");
 
179
        if (!gst_element_seek(music, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
 
180
          GST_SEEK_TYPE_SET, 30*GST_SECOND, GST_SEEK_TYPE_NONE, 0))
 
181
          g_print("playPreview() seek failed\n");
121
182
        gst_element_set_state (music, GST_STATE_PLAYING);
122
183
        GstFormat fmt = GST_FORMAT_TIME;
123
184
        gint64 len;
124
 
        if (!gst_element_query_duration (music, &fmt, &len))
125
 
                length = LENGTH_ERROR;
126
 
        else
127
 
                length = (int) (len/GST_MSECOND);
 
185
        if (!gst_element_query_duration (music, &fmt, &len)) length = LENGTH_ERROR;
 
186
        else length = int(len/GST_MSECOND);
128
187
#endif
 
188
        // Wait a little while before restoring volume to prevent clicks
 
189
        boost::thread::sleep(now() + 0.05);
 
190
        setVolume_internal(volume);
129
191
}
130
192
 
131
 
int CAudio::getLength( void )
132
 
{
133
 
        if( length == LENGTH_ERROR ) {
 
193
double CAudio::getLength_internal() {
 
194
        if (length != LENGTH_ERROR) return 1e-3 * length;
134
195
#ifdef USE_LIBXINE_AUDIO
135
 
                int pos_stream;
136
 
                int pos_time;
137
 
                if( !xine_get_pos_length(stream, &pos_stream, &pos_time, &length) )
138
 
                        length = LENGTH_ERROR;
 
196
        int pos_stream;
 
197
        int pos_time;
 
198
        if (!xine_get_pos_length(stream, &pos_stream, &pos_time, &length)) length = LENGTH_ERROR;
139
199
#endif
140
200
#ifdef USE_GSTREAMER_AUDIO
141
 
                GstFormat fmt = GST_FORMAT_TIME;
142
 
                gint64 len;
143
 
                if (!gst_element_query_duration (music, &fmt, &len))
144
 
                        length = LENGTH_ERROR;
145
 
                else
146
 
                        length = (int) (len/GST_MSECOND);
 
201
        GstFormat fmt = GST_FORMAT_TIME;
 
202
        gint64 len;
 
203
        length = gst_element_query_duration (music, &fmt, &len) ? int(len/GST_MSECOND) : LENGTH_ERROR;
147
204
#endif
148
 
        }
149
 
 
150
 
        if( length == LENGTH_ERROR )
151
 
                return 0;
152
 
        else
153
 
                return length;
 
205
        return length == LENGTH_ERROR ? 0.0 : 1e-3 * length;
154
206
}
155
207
 
156
 
bool CAudio::isPlaying( void )
157
 
{
 
208
bool CAudio::isPlaying_internal() {
158
209
#ifdef USE_LIBXINE_AUDIO
159
 
        xine_event_t *event; 
160
 
        while((event = xine_event_get(event_queue))) {
161
 
            switch(event->type) {
162
 
                case XINE_EVENT_UI_PLAYBACK_FINISHED:
163
 
                    xine_playing = 0;
164
 
                    break;
165
 
            }
166
 
            xine_event_free(event);
167
 
        }
168
 
        if(xine_playing) {
169
 
                return true;
170
 
        } else {
171
 
                return false;
 
210
        xine_event_t *event; 
 
211
        while((event = xine_event_get(event_queue))) {
 
212
                if (event->type == XINE_EVENT_UI_PLAYBACK_FINISHED) xine_playing = 0;
 
213
                xine_event_free(event);
172
214
        }
 
215
        return xine_playing;
173
216
#endif
174
217
#ifdef USE_GSTREAMER_AUDIO
175
218
        // If the length cannot be computed, we assume that the song is playing
176
219
        // (happening in the first fex seconds)
177
 
        if( getLength()==0 )
178
 
                return true;
179
 
 
 
220
        if (getLength_internal() == 0) return true;
180
221
        // If we are not in the last second, then we are not at the end of the song 
181
 
        if( getLength() - getPosition() > 1000 )
182
 
                return true;
183
 
        else
184
 
                return false;
 
222
        return getLength_internal() - getPosition_internal() > 1.0;
185
223
#endif
186
224
        return true;
187
225
}
188
226
 
189
 
void CAudio::stopMusic( void )
190
 
{
 
227
void CAudio::stopMusic_internal() {
 
228
        // if (!isPlaying_internal()) return;
191
229
#ifdef USE_LIBXINE_AUDIO
192
 
        xine_stop(stream);
 
230
        xine_stop(stream);
193
231
#endif
194
232
#ifdef USE_GSTREAMER_AUDIO
195
233
        gst_element_set_state (music, GST_STATE_NULL);
196
234
#endif
197
235
}
198
236
 
199
 
int CAudio::getPosition( void )
200
 
{
201
 
        int position = 0;
202
 
 
 
237
double CAudio::getPosition_internal() {
 
238
        double position = 0.0;
203
239
#ifdef USE_LIBXINE_AUDIO
204
240
        int pos_stream;
205
241
        int length_time;
206
242
        int pos_time;
207
 
 
208
 
        if (xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time)) {
209
 
                position = pos_time;
210
 
        } else {
211
 
        position = 0;
212
 
        }
 
243
        position = xine_get_pos_length(stream, &pos_stream, &pos_time, &length_time) ? 1e-3 * pos_time : 0.0;
213
244
#endif
214
245
#ifdef USE_GSTREAMER_AUDIO
215
246
        GstFormat fmt = GST_FORMAT_TIME;
216
247
        gint64 pos;
217
 
        if (!gst_element_query_position (music, &fmt, &pos))
218
 
                position = 0;
219
 
        else
220
 
                position = (int) (pos/GST_MSECOND);
 
248
        position = gst_element_query_position(music, &fmt, &pos) ? double(pos) / GST_SECOND : 0.0;
221
249
#endif
222
 
 
223
250
        return position;
224
251
}
225
252
 
226
 
bool CAudio::isPaused( void ) {
227
 
#ifdef USE_LIBXINE_AUDIO
228
 
        if (isPlaying()){
229
 
                int speed = xine_get_param(stream,XINE_PARAM_SPEED);
230
 
                if (speed == XINE_SPEED_PAUSE)
231
 
                        return true;
232
 
                return false;
233
 
        }
234
 
        else
235
 
                return false;
236
 
#endif
237
 
#ifdef USE_GSTREAMER_AUDIO
238
 
        return GST_STATE(music) ==  GST_STATE_PAUSED;
239
 
#endif
240
 
}
241
 
 
242
 
void CAudio::togglePause( void ){
243
 
        if (isPlaying()){
244
 
#ifdef USE_LIBXINE_AUDIO
245
 
                if (isPaused())
246
 
                        xine_set_param(stream,XINE_PARAM_SPEED,XINE_SPEED_NORMAL);
247
 
                else
248
 
                        xine_set_param(stream,XINE_PARAM_SPEED,XINE_SPEED_PAUSE);
249
 
#endif
250
 
#ifdef USE_GSTREAMER_AUDIO
251
 
                if (isPaused())
252
 
                        gst_element_set_state(music, GST_STATE_PLAYING);
253
 
                else
254
 
                        gst_element_set_state(music, GST_STATE_PAUSED);
255
 
#endif
256
 
        }
257
 
}
258
 
void CAudio::seek( int seek_dist ){
259
 
        if (isPlaying()){
260
 
                int position = getPosition()+seek_dist;
261
 
                if ( position < 0) position = 0;
262
 
                if ( position > getLength() - 1000){
263
 
                        fprintf(stdout,"seeking too far ahead\n");
264
 
                        return;
265
 
                }
266
 
                fprintf(stdout,"seeking from %d to %d\n",getPosition(),position);
267
 
#ifdef USE_LIBXINE_AUDIO
268
 
                xine_play(stream,0,position);
269
 
#endif
270
 
#ifdef USE_GSTREAMER_AUDIO
271
 
                gst_element_set_state (music, GST_STATE_PAUSED);
272
 
                GstState state_paused = GST_STATE_PAUSED;
273
 
                gst_element_get_state (music, NULL, &state_paused, GST_CLOCK_TIME_NONE);
274
 
                if( !gst_element_seek_simple(music, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position*GST_MSECOND))
275
 
                        g_print("playPreview() seek failed\n");
276
 
                gst_element_set_state (music, GST_STATE_PLAYING);
277
 
#endif
278
 
        }
279
 
}
280
 
 
 
253
bool CAudio::isPaused_internal() {
 
254
#ifdef USE_LIBXINE_AUDIO
 
255
        return isPlaying_internal() && xine_get_param(stream,XINE_PARAM_SPEED) == XINE_SPEED_PAUSE;
 
256
#endif
 
257
#ifdef USE_GSTREAMER_AUDIO
 
258
        return GST_STATE(music) == GST_STATE_PAUSED;
 
259
#endif
 
260
}
 
261
 
 
262
void CAudio::togglePause_internal() {
 
263
        if (!isPlaying_internal()) return;
 
264
#ifdef USE_LIBXINE_AUDIO
 
265
        xine_set_param(stream, XINE_PARAM_SPEED, isPaused_internal() ? XINE_SPEED_NORMAL : XINE_SPEED_PAUSE);
 
266
#endif
 
267
#ifdef USE_GSTREAMER_AUDIO
 
268
        gst_element_set_state(music, isPaused_internal() ? GST_STATE_PLAYING : GST_STATE_PAUSED);
 
269
#endif
 
270
}
 
271
 
 
272
void CAudio::seek_internal(double seek_dist) {
 
273
        if (!isPlaying_internal()) return;
 
274
        int position = std::max(0.0, std::min(getLength_internal() - 1.0, getPosition_internal() + seek_dist));
 
275
#ifdef USE_LIBXINE_AUDIO
 
276
        xine_play(stream, 0, 1e3 * position);
 
277
#endif
 
278
#ifdef USE_GSTREAMER_AUDIO
 
279
        gst_element_set_state(music, GST_STATE_PAUSED);
 
280
        GstState state_paused = GST_STATE_PAUSED;
 
281
        gst_element_get_state(music, NULL, &state_paused, GST_CLOCK_TIME_NONE);
 
282
        if (!gst_element_seek_simple(music, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position*GST_SECOND))
 
283
          throw std::runtime_error("CAudio::seek_internal() failed");
 
284
        gst_element_set_state(music, GST_STATE_PLAYING);
 
285
#endif
 
286
}
281
287
 
282
288